Code Monkey home page Code Monkey logo

virgil's Introduction

virgil: A Fast and Lightweight Systems Programming Language

def main() {
    System.puts("Virgil is fast and lightweight!\n");
}

Virgil is a programming language designed for building lightweight high-performance systems. Its design blends functional and object-oriented programming paradigms for expressiveness and performance. Virgil's compiler produces optimized, standalone native executables, WebAssembly modules, or JARs for the JVM. For quick turnaround in testing and debugging, programs can also be run directly on a built-in interpreter. It is well-suited to writing small and fast programs with little or no dependencies, which makes it ideal for the lowest level of software systems. On native targets, it includes features that allow building systems that talk directly to kernels, dynamically generate machine code, implement garbage collection, etc. It is currently being used for virtual machine and programming language research, in particular the development of a next-generation WebAssembly virtual machine, Wizard.

This repository includes the entire compiler, runtime system, some libraries, tests, documentation and supporting code for Virgil's various compilation targets.

Language Design

Virgil focuses on balancing these main features in a statically-typed language:

  • Classes - for basic object-oriented programming
  • Functions - for small-scale reuse of functionality
  • Tuples - for efficient aggregation and uniform treatment of multi-argument functions
  • Type parameters - for powerful and clean abstraction over types
  • Algebraic data types - for easy building and matching of data structures

For more, read this paper. Or see the tutorial. Or read up on libraries.

Supported Targets

Virgil can compile to native binaries for Linux or Darwin, to jar files for the JVM, or to WebAssembly modules. Linux binaries can run successfully under Windows using Window's Linux system call layer. The compiler is naturally a cross-compiler, able to compile from any supported platform to any other supported platform, so you need only be able to run on one of these platforms in order to target any of the others.

  • x86-darwin : 32-bit Darwin kernels (MacOS)
  • x86-64-darwin : 64-bit Darwin kernels (MacOS)
  • x86-linux : 32-bit Linux kernels
  • x86-64-linux : 64-bit Linux kernels
  • jar : JAR files for the Java Virtual Machine
  • wasm : WebAssembly module for any Wasm engine

Implementation

Virgil is fully self-hosted: its entire compiler and runtime system is implemented in Virgil. It was originally designed as a language for embedded systems, particularly microcontrollers, but now supports more mainstream targets. The compiler includes sophisticated whole-program optimizations that achieve great performance and small binaries. Native binaries compiled from your programs can be as small as a few hundred bytes in size and consume just kilobytes of memory at runtime. You can learn more in the Implementation Guide.

Documentation

The most up-to-date documentation is, as always, this repository! Learn how to get started using Virgil and browse the tutorial, where many example programs exist.

Research Papers

Five research papers have been published on Virgil.

License

Licensed under the Apache License, Version 2.0. (rt/LICENSE or https://www.apache.org/licenses/LICENSE-2.0)

virgil's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

virgil's Issues

Simplified for loop

This kind of for loop (/lib/util/Arrays.v3) is not documented in the tutorial:

for (i < index) n[i] = array[i];

What about initialization and incrementation of i variable?

Why is Virgil so fast?

I ran a Hello World + Fibonacci benchmark comparing Virgil with Rust and TinyGo (the two most often cited Wasm compilers) — the results seem to good to be true!

Virgil outperforms both Rust and TinyGo by orders of magnitude in terms of both compiler speed and executable file sizes. Yes, the 0.00s compile time is correct — time(1) reports to the nearest 1/100s (when I compiled my first Virgil program it was so fast I thought it hadn't run).

The Numbers

wasm

Compile time (secs) Executable size (B) Execution time (secs)
go 4.13s 428,547 0.62s
rust 0.33s 2,054,632 1.80s
virgil 0.00s 8,802 0.96s

wasm-optimised

Compile time (secs) Executable size (B) Execution time (secs)
go 3.88s 191,265 0.62s
rust 0.80s 301,363 0.66s
virgil 0.01s 7,891 1.07s

x86-64-linux

Compile time (secs) Executable size (B) Execution time (secs)
go 1.94s 503,640 0.39s
rust 0.30s 3,853,504 1.53s
virgil 0.01s 20,552 0.63s

x86-64-linux-optimised

Compile time (secs) Executable size (B) Execution time (secs)
go 2.04s 140,056 0.38s
rust 2.73s 1,653,736 0.32s
virgil 0.01s 19,552 0.64s

WebAssembly Performance

  • The Virgil compiler is ~50x faster than the Rust compiler and over 300x faster than the TinyGo compiler.
  • The optimised Virgil executable is over 35x smaller than the Rust executable and over 20x smaller than TinyGo executable.
  • The TinyGo executable runs ~7% faster than the Rust executable and ~83% faster than the Virgil executable (executed on the wasmtime runtime).

x86-64 Performance

  • The Virgil compiler is ~30x faster than the Rust compiler and ~200x faster than the TinyGo compiler.
  • The optimised Virgil executable is ~80x smaller than the Rust executable and ~7x smaller than TinyGo executable.

Notes

  1. Virgil Wasm code generated with the compiler-opt=all option ran slower than without it but the executable size was ~10% smaller, so currently there's not a lot to be gained using the -opt=all option.

  2. Importing the fmt package increased the size of the TinyGo Wasm executable from 8KB to 191KB (an increase of 183KB), whereas importing the Virgil Strings component increased the size of the Virgil Wasm executable from 3.6KB to 7.9KB (an increase of only 4.3KB).

  3. The compiled Wasm files were executed with wasmtime-cli 0.39.1

Details

The raw data along with source code and platform information is attached.
go-results.txt
rust-results.txt
virgil-results.txt

How to compile Virgil into WASI

I've been playing with the idea of getting compilers and new languages into the Wasm/WASI world, as I really think it enriches the ecosystem.
Zig has recently supported compiling to Wasm/WASI and I was wondering how we could get the self-hosting Virgil compiler into the WASI world.

I tried playing a bit with the /bin/dev bash files but I was unable to get Virgil compiling into WASI (the compiler itself).
Any help will be greatly appreciated!

Lambda support

Virgil doesn't currently support lambdas, but support will be added soon.

I guess this means anonymous functions with closures?

For example:

def intSeq() -> () -> int {
    var i = 0;
    return () -> int {
        i = i + 1;
        return i;
    }
}

Grammar railroad diagram

Going through the code on https://github.com/titzer/virgil/blob/master/aeneas/src/vst/Parser.v3 and using this tool https://github.com/mingodad/CocoR-CSharp to create a LL(1) parser to then generate an EBNF understood by https://www.bottlecaps.de/rr/ui to generate a railroad diagram (https://en.wikipedia.org/wiki/Syntax_diagram) I've got an initial version that already shows a big chunk of virgil grammar.

Copy the EBNF shown bellow on https://www.bottlecaps.de/rr/ui in the tab Edit Grammar then switch to the tab View Diagram, I think that it's useful for documentation and understand/develop the syntax of virgil:

//
// EBNF generated by CocoR parser generator to be viewed with https://www.bottlecaps.de/rr/ui
//

//
// productions
//

Virgil ::=  parseToplevelDecl* EOF
parseToplevelDecl ::=  TK_class parseIdentCommon ( "(" ( parseClassParam ( "," parseClassParam )* )? ")" )? ( TK_extends parseTypeRef )? parseTupleExpr? parseMembers | TK_component parseIdentVoid parseMembers | TK_import TK_component parseIdentVoid parseMembers | parseVar | parseDef | parseVariant | parseEnum | parseExport
parseIdentCommon ::=  identParam parseTypeRef ( "," parseTypeRef )* ">" | ident
parseClassParam ::=  TK_var? parseParamWithOptType
parseTypeRef ::=  ( "(" ( parseTypeRef ( "," parseTypeRef )* )? ")" | parseIdentCommon ( "." parseIdentCommon )* ) ( "->" parseTypeRef )*
parseTupleExpr ::=  "(" ( parseExpr ( "," parseExpr )* )? ")"
parseMembers ::=  "{" parseMember* TK_rbrace
parseIdentVoid ::=  ident
parseVar ::=  TK_var parseIdentVoid parseFieldSuffix
parseDef ::=  TK_def TK_var? ( parseIndexed | parseIdentCommon ( parseMethodSuffix | parseFieldSuffix ) )
parseVariant ::=  TK_type parseIdentCommon ( "(" ( parseVariantCaseParam ( "," parseVariantCaseParam )* )? ")" )? parseVariantCases
parseEnum ::=  TK_enum parseIdentVoid ( "(" ( parseEnumParam ( "," parseEnumParam )* )? ")" )? "{" ( parseEnumCase ( "," parseEnumCase )* )? TK_rbrace
parseExport ::=  TK_export ( parseDef | ( parseStringLiteral | parseIdent ) ( "=" parseIdent parseDottedVarExpr? )? ";" )
parseVariantCaseParam ::=  parseParamWithOptType
parseVariantCases ::=  "{" parseVariantCase* TK_rbrace
parseVariantCase ::=  parseDef | TK_case parseIdentVoid ( "(" ( parseVariantCaseParam ( "," parseVariantCaseParam )* )? ")" )? ( ";" | parseMembers )
parseStringLiteral ::=  string
parseIdent ::=  ident
parseDottedVarExpr ::=  "." parseTypeRef ( "." parseTypeRef )*
parseEnumParam ::=  parseParamWithOptType
parseEnumCase ::=  parseIdentVoid ( "(" ( parseExpr ( "," parseExpr )* )? ")" )?
parseExpr ::=  parseSubExpr ( "=" parseExpr | addBinOpSuffixes )?
parseMember ::=  TK_private? ( parseDef | parseNew | parseVar )
parseNew ::=  TK_new "(" ( parseNewParam ( "," parseNewParam )* )? ")" ( ":"? TK_super parseTupleExpr )? parseBlockStmt
parseNewParam ::=  TK_var? parseParamWithOptType
parseBlockStmt ::=  "{" parseStmt* TK_rbrace
parseTypeParam ::=  parseIdentVoid
parseStmt ::=  parseBlockStmt | parseEmptyStmt | parseIfStmt | parseWhileStmt | parseMatchStmt | parseVarStmt | parseDefStmt | parseBreakStmt | parseContinueStmt | parseReturnStmt | parseForStmt | parseExprStmt
parseEmptyStmt ::=  ";"
parseIfStmt ::=  TK_if parseControlExpr parseStmt ( TK_else parseStmt )?
parseWhileStmt ::=  TK_while parseControlExpr parseStmt
parseMatchStmt ::=  TK_match parseControlExpr "{" ( parseMatchCase parseMatchCase* )? TK_rbrace ( TK_else parseStmt )?
parseVarStmt ::=  TK_var parseIdentVoid parseVars*
parseDefStmt ::=  TK_def parseIdentVoid parseVars*
parseBreakStmt ::=  TK_break ";"
parseContinueStmt ::=  TK_continue ";"
parseReturnStmt ::=  TK_return parseExpr? ";"
parseForStmt ::=  TK_for "(" parseLocal ( "<" parseExpr | TK_in parseExpr | ";" parseExpr ";" parseExpr ) ")" parseStmt
parseExprStmt ::=  parseExpr ";"
parseControlExpr ::=  "(" parseExpr ")"
parseLocal ::=  parseIdentVoid ( ":" parseTypeRef )? ( "=" parseExpr )?
parseMatchCase ::=  "_" "=>" parseStmt | matchPattern matchPattern*
matchPattern ::=  parseMatchPattern ( "," parseMatchPattern )* "=>" parseStmt
parseMatchPattern ::=  parseIdMatchPattern | parseByteLiteral | "-"? parseNumber
parseIdMatchPattern ::=  ( TK_true | TK_false | TK_null ) | parseIdentCommon ( ":" parseTypeRef | parseDottedVarExpr? ( "(" ( parseMatchParam ( "," parseMatchParam )* )? ")" )? )
parseByteLiteral ::=  charcon
parseNumber ::=  bincon | floatcon | intcon
parseMatchParam ::=  parseIdentVoid
parseVars ::=  ( ":" parseTypeRef )? ( "=" parseExpr )? ( "," parseIdentVoid parseVars? | ";" )
parseFieldSuffix ::=  parseVars
parseIndexed ::=  "[" ( parseMethodParam ( "," parseMethodParam )* )? "]" ( "=" parseMethodParam | "->" parseTypeRef ) ( ";" | parseBlockStmt )
parseMethodSuffix ::=  "(" ( parseMethodParam ( "," parseMethodParam )* )? ")" ( "->" ( TK_this | parseTypeRef ) )? ( ";" | parseBlockStmt )
parseMethodParam ::=  TK_var? parseParamWithOptType
parseParamWithOptType ::=  parseIdentCommon ( ":" parseTypeRef )?
parseSubExpr ::=  parseTerm ( termMultSuffix termMultSuffix* incOrDec? | incOrDec )?
addBinOpSuffixes ::=  parseInfix parseSubExpr ( parseInfix parseSubExpr )*
parseTerm ::=  TK_if "(" parseExpr "," parseExpr ( "," parseExpr )? ")" | TK_true | TK_false | TK_null | "-"? ( parseNumber | parseTupleExpr | parseIdentCommon ) | ( "!" | "~" ) parseSubExpr | parseByteLiteral | parseStringLiteral | parseArrayLiteral | parseParamExpr | incOrDec parseSubExpr
termMultSuffix ::=  addMemberSuffix | parseTupleExpr | parseArrayLiteral
incOrDec ::=  "++" | "--"
addMemberSuffix ::=  "." ( parseIdentUnchecked | ( "!" | "?" ) ( "<" parseTypeRef ( "," parseTypeRef )* ">" )? | parseInfix | intcon | "~" | "[" "]" "="? )
parseArrayLiteral ::=  "[" ( parseExpr ( "," parseExpr )* )? "]"
parseIdentUnchecked ::=  parseIdentCommon
parseInfix ::=  "==" | "!=" | "||" | "&&" | "<" | "<=" | ">" | ">=" | ( "|" | "&" | "<<" | "<<<" | TK_shr | ">>>" | "+" | "-" | "*" | "/" | "%" | "^" ) "="?
parseParamExpr ::=  "_"

//
// tokens
//

TK_break ::= "break"
TK_case ::= "case"
TK_class ::= "class"
TK_component ::= "component"
TK_continue ::= "continue"
TK_def ::= "def"
TK_else ::= "else"
TK_enum ::= "enum"
TK_export ::= "export"
TK_extends ::= "extends"
TK_false ::= "false"
TK_for ::= "for"
TK_if ::= "if"
TK_import ::= "import"
TK_in ::= "in"
TK_layout ::= "layout"
TK_match ::= "match"
TK_new ::= "new"
TK_null ::= "null"
TK_private ::= "private"
TK_return ::= "return"
TK_struct ::= "struct"
TK_super ::= "super"
TK_this ::= "this"
TK_true ::= "true"
TK_type ::= "type"
TK_var ::= "var"
TK_while ::= "while"
TK_shr ::= ">>"
TK_rbrace ::= "}"

Here is the LL(1) parser that still need fixes to parse all the .v3 files of this project:

#include "Scanner-virgil.nut"

COMPILER Virgil
	int scanStateDepth = 0;

TERMINALS
	T_SYMBOL

CHARACTERS
	letter    = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".
	oct        = '0'..'7'.
	digit     = "0123456789".
	bindigit     = "01".
	bindigitwsep     = "01_".
	nzdigit    = '1'..'9'.
	digitwsep     = "0123456789_".
	cr        = '\r'.
	lf        = '\n'.
	tab       = '\t'.
	stringCh  = ANY - '"' - '\\' - cr - lf.
	charCh    = ANY - '\'' - '\\' - cr - lf.
	printable = '\u0020' .. '\u007e'.
	hex       = "0123456789abcdefABCDEF".
	hexwsep       = "0123456789abcdefABCDEF_".

	newLine   = cr + lf.
	notNewLine = ANY - newLine .
	ws         = " " + tab + '\u000b' + '\u000c'.

TOKENS
	ident     = letter { letter | digit | '_'}.
	identParam  = letter { letter | digit | '_'} '<'.
	floatcon =
		( digit {digitwsep} '.' digit {digitwsep} [('e'|'E')  ['+'|'-'] digit {digit}]
		| digit {digitwsep} ('e'|'E')  ['+'|'-'] digit {digit}
		) ['f'|'F' | 'd' | 'D']
		| digit {digitwsep} ('f'|'F') .

	intcon   = ( digit {digitwsep}
		//| '0' {oct}
		| ("0x"|"0X") hex {hexwsep}
		) [('u'|'U') ['l'|'L'] | ('l'|'L') ['u'|'U'] | ('d' | 'D')] .

	bincon  = '0' ('b' | 'B') bindigit {bindigitwsep} ['u' | 'U'].

	string    = '"' { stringCh | '\\' printable } '"'.
	badString = '"' { stringCh | '\\' printable } (cr | lf).
	charcon      = '\'' ( charCh | '\\' printable { hex } ) '\''.

	TK_break = "break" .
	TK_case = "case" .
	TK_class = "class" .
	TK_component = "component" .
	TK_continue = "continue" .
	TK_def = "def" .
	TK_else = "else" .
	TK_enum = "enum" .
	TK_export = "export" .
	TK_extends = "extends" .
	TK_false = "false" .
	TK_for = "for" .
	TK_if = "if" .
	TK_import = "import" .
	TK_in = "in" .
	TK_layout = "layout" .
	TK_match = "match" .
	TK_new : ident = "new" .
	TK_null = "null" .
	TK_private = "private" .
	TK_return = "return" .
	TK_struct = "struct" .
	TK_super = "super" .
	TK_this : ident = "this" .
	TK_true = "true" .
	TK_type = "type" .
	TK_var = "var" .
	TK_while = "while" .

	//types
	//TK_Array = "Array" .
	//TK_bool = "bool" .
	//TK_byte = "byte" .
	//TK_double = "double" .
	//TK_float = "float" .
	//TK_int = "int" .
	//TK_long = "long" .
	//TK_short = "short" .
	//TK_string = "string" .
	//TK_void = "void" .

	//Operators
	TK_shr = ">>" . //(. print("<<DAD>>"); .)

	//Puntuation
	TK_rbrace = '}' .

PRAGMAS

	COMMENTS FROM "/*" TO "*/" NESTED
	COMMENTS FROM "//" TO lf

IGNORE cr + lf + tab

/*-------------------------------------------------------------------------*/

PRODUCTIONS

Virgil =
	{parseToplevelDecl}
	EOF
	.

parseToplevelDecl =
	"class" parseIdentCommon ['(' [parseClassParam {',' parseClassParam}] ')'] ["extends" parseTypeRef] [parseTupleExpr] parseMembers
	| "component" parseIdentVoid parseMembers
	| "import" "component" parseIdentVoid parseMembers
	| parseVar
	| parseDef
	| parseVariant
	| parseEnum
	| parseExport
	.

parseVariant =
	"type" parseIdentCommon ['(' [parseVariantCaseParam {',' parseVariantCaseParam}] ')'] parseVariantCases
	.

parseVariantCases =
	'{' {parseVariantCase}'}'
	.

parseVariantCase =
	parseDef
	| "case" parseIdentVoid ['(' [parseVariantCaseParam {',' parseVariantCaseParam}] ')'] (';' | parseMembers)
	.

parseExport =
	"export" (parseDef | (parseStringLiteral | parseIdent) ['=' parseIdent [parseDottedVarExpr]] ';')
	.

parseEnum =
	"enum" parseIdentVoid ['(' [parseEnumParam {',' parseEnumParam}] ')']
		'{' [ parseEnumCase {','
			(. if(la.kind == ParserTokens._TK_rbrace) {break; /*allow trailing separator*/} .)
			parseEnumCase} ] '}'
	.

parseEnumCase =
	parseIdentVoid ['(' [parseExpr {',' parseExpr}] /*[',']*/ ')']
	.

parseMembers =
	'{' {parseMember} '}'
	.

parseMember =
	["private"] (parseDef | parseNew | parseVar)
	.

parseNew =
	"new" '(' [parseNewParam {',' parseNewParam}] ')' [([':'] "super") parseTupleExpr] parseBlockStmt
	.
/*
parseParamCommon =
	parseIdentCommon [parseIdentVoid] [':' parseTypeRef]
	.
*/
parseTypeRef =
	(
		'(' [parseTypeRef {',' parseTypeRef}] ')'
		| parseIdentCommon {'.' parseIdentCommon}
	)
	{"->" parseTypeRef}
	.

parseTypeParam =
	parseIdentVoid
	.

parseStmt =
	parseBlockStmt
	| parseEmptyStmt
	| parseIfStmt
	| parseWhileStmt
	| parseMatchStmt
	| parseVarStmt
	| parseDefStmt
	| parseBreakStmt
	| parseContinueStmt
	| parseReturnStmt
	| parseForStmt
	| parseExprStmt
	.

parseBlockStmt =
	'{' {parseStmt} '}'
	.

parseEmptyStmt =
	';'
	.

parseControlExpr =
	'(' parseExpr ')'
	.

parseIfStmt =
	"if" parseControlExpr parseStmt ["else" parseStmt]
	.

parseWhileStmt =
	"while" parseControlExpr parseStmt
	.

parseForStmt =
	"for" '(' parseLocal ('<' parseExpr | "in" parseExpr | ';' parseExpr ';' parseExpr) ')' parseStmt
	.

parseMatchStmt =
	"match" parseControlExpr '{' [parseMatchCase {parseMatchCase}] '}' ["else" parseStmt]
	.

parseMatchCase =
	'_' "=>" parseStmt
	| matchPattern {matchPattern}
	.

matchPattern =
	parseMatchPattern {',' parseMatchPattern} "=>" parseStmt
	.

parseMatchPattern =
	parseIdMatchPattern
	| parseByteLiteral
	| ['-'] parseNumber
	.

parseDottedVarExpr =
	'.' parseTypeRef {'.' parseTypeRef}
	.

parseIdMatchPattern =
	("true" | "false" | "null")
	| parseIdentCommon (
		':' parseTypeRef
		| [parseDottedVarExpr] ['(' [parseMatchParam {',' parseMatchParam}] ')']
	)
	.

parseMatchParam =
	parseIdentVoid
	.

parseVarStmt =
	"var" parseIdentVoid {parseVars}
	.

parseDefStmt =
	"def" parseIdentVoid {parseVars}
	.

parseBreakStmt =
	"break" ';'
	.

parseContinueStmt =
	"continue" ';'
	.

parseReturnStmt =
	"return" [parseExpr] ';'
	.

parseVar =
	"var" parseIdentVoid parseFieldSuffix
	.

parseDef =
	"def" ["var"] (parseIndexed | parseIdentCommon (parseMethodSuffix | parseFieldSuffix))
	.

parseIndexed =
	'[' [parseMethodParam {',' parseMethodParam}] ']' ('=' parseMethodParam | "->" parseTypeRef) (';' | parseBlockStmt)
	.

parseMethodSuffix =
	'(' [parseMethodParam {',' parseMethodParam}] ')' ["->" ("this" | parseTypeRef)] (';' | parseBlockStmt)
	.

parseParamWithOptType =
	parseIdentCommon [':' parseTypeRef]
	.

parseMethodParam =
	["var"] parseParamWithOptType
	.

parseNewParam =
	["var"] parseParamWithOptType
	.

parseClassParam =
	["var"] parseParamWithOptType
	.

parseEnumParam =
	parseParamWithOptType
	.

parseVariantCaseParam =
	parseParamWithOptType
	.

parseExprStmt =
	parseExpr ';'
	.

parseExpr =
	parseSubExpr ['=' parseExpr | addBinOpSuffixes]
	.

parseSubExpr =
	parseTerm [termMultSuffix {termMultSuffix} [incOrDec] | incOrDec]
	.

incOrDec =
	"++" | "--"
	.

termMultSuffix =
	addMemberSuffix | parseTupleExpr | parseArrayLiteral
	.

addMemberSuffix = (. scanner.stateNo=6; .) //for tuple indexing by integers
	'.' (
		parseIdentUnchecked
		| ('!' | '?') ['<' parseTypeRef {',' parseTypeRef} '>']
		| parseInfix
		| intcon
		| '~'
		| '[' ']' ['=']
	) (. scanner.stateNo=0; .)
	.

parseTerm =
	"if" '(' parseExpr ',' parseExpr [',' parseExpr]')'
	//| parseVarExpr
	| "true"
	| "false"
	| "null"
	| ['-'] (parseNumber | parseTupleExpr | parseIdentCommon)
	| ('!' | '~') parseSubExpr
	| parseByteLiteral
	| parseStringLiteral
	| parseArrayLiteral
	| parseParamExpr
	| incOrDec parseSubExpr
	.

parseParamExpr =
	'_'
	.

parseByteLiteral =
	charcon
	.

parseStringLiteral =
	string
	.

parseTupleExpr =
	'(' [parseExpr {',' parseExpr}] ')'
	.

parseArrayLiteral =
	'[' [parseExpr {',' parseExpr}] ']'
	.

parseNumber =
	bincon //BinLiteral
	//| HexLiteral
	| floatcon //FloatLiteral
	| intcon //DecLiteral
	.
/*
parseVarExpr =
	parseIdentCommon
	| "true"
	| "false"
	| "null"
	.
*/
parseIdent =
	ident
	.

parseIdentVoid =
	ident
	.

parseIdentCommon =
	identParam
		(. if(scanStateDepth++ == 0) scanner.stateNo = 5; .)
		parseTypeRef {',' parseTypeRef} '>'
		(. if(--scanStateDepth == 0) scanner.stateNo = 0; .)
	| ident
	.

parseIdentUnchecked =
	parseIdentCommon
	.

parseLocal =
	parseIdentVoid [':' parseTypeRef] ['=' parseExpr]
	.

parseVars =
	[':' parseTypeRef] ['=' parseExpr] (',' parseIdentVoid [parseVars] | ';')
	.

parseFieldSuffix =
	parseVars
	.

addBinOpSuffixes =
	parseInfix parseSubExpr {parseInfix parseSubExpr}
	.

parseInfix =
	"=="
	| "!="
	| "||"
	| "&&"
	| '<'
	| "<="
	| '>'
	| ">="
	| (
		'|'
		| '&'
		| "<<"
		| "<<<"
		| ">>"
		| ">>>"
		| '+'
		| '-'
		| '*'
		| '/'
		| '%'
		| '^'
	) ['=']
	.

END Virgil.

lib/util: Implement %f to print floating point numbers

Since adding floating point back in 2020, the Virgil utility libraries have not yet added support for printing/rendering floating point numbers (in decimal). In C, the printf format string supports %f for specifying an argument is a floating point number. The analogous place to add code to handle this is in StringBuilder, which can deal with floating point strings.

Slight differences with C printf and Virgil StringBuffer:

  • StringBuilder uses %d (for decimal) for specifying decimal output of integer values. I think it'd be nice to just extend
  • StringBuilder doesn't yet support specifying the width (in characters) of the output item, nor left or right-justifying
  • Performance of printing floats isn't highly important; as long as the routine doesn't allocate memory, it should be fine to do the naive algorithm

I could use some help on this, and it might make a good starter project for someone new wanting to kick the tires with Virgil and contribute.

x86-64-linux executables exit with random non-zero exit codes

This is an odd one: x86-64-linux executables sometimes return a (seemingly random) non-zero exit code from the main() function:

$ cat hello.v3 && v3c-x86-64-linux hello.v3 && ./hello; echo $?
def main() {
  System.puts("Hello World\n");
}
Hello World
216

If a second print statement is added the exit code is zero:

$ cat hello.v3 && v3c-x86-64-linux hello.v3 && ./hello; echo $?
def main() {
  System.puts("Hello World\n");
  System.puts("Hello World\n");
}
Hello World
Hello World
0

Explicitly returning an exit code from main() seems to resolve the problem:

$ cat hello.v3 && v3c-x86-64-linux hello.v3 && ./hello; echo $?
def main() -> int {
  System.puts("Hello World\n");
  return 0;
}
Hello World
0

The x86-linux target does not seem to exhibit this behaviour.

$ cat hello.v3 && v3c-x86-linux hello.v3 && ./hello; echo $? 
def main() {
  System.puts("Hello World\n");
}
Hello World
0

Improve JVM bytecode generation

What steps will reproduce the problem?
1. Try to parse Aeneas.jar with IKVM (http://ikvm.net/)
2. Look at the warnings
3. See the conversation at https://sourceforge.net/p/ikvm/bugs/281/

What is the expected output? What do you see instead?
IKVM is pretty good at converting pretty much every JAR i've stumbled upon. So, 
while I personally didnt check the JAR for correctness as per JRE spec, my bet 
is that the generated bytecode is wrong.

What version of the product are you using? On what operating system?
Virgil binary from latest commit, IKVM 7.2 binary, Windows 8.1 x64, .NET 4

Please provide any additional information below.


Original issue reported on code.google.com by [email protected] on 22 Sep 2013 at 1:38

-1 bytes

user@host009:~/src/virgil/bin/dev$ wave -?
==25740==WARNING: AddressSanitizer failed to allocate 0xffffffffffffffff bytes
==25740==AddressSanitizer's allocator is terminating the process instead of returning 0
==25740==If you don't like this behavior set allocator_may_return_null=1
==25740==AddressSanitizer CHECK failed: /build/llvm-toolchain-6.0-QjOn7h/llvm-toolchain-6.0-6.0/projects/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc:225 "((0)) != (0)" (0x0, 0x0)
    #0 0x4f0645  (/home/user/src/virgil/bin/dev/wave+0x4f0645)
    #1 0x50def5  (/home/user/src/virgil/bin/dev/wave+0x50def5)
    #2 0x4f6a36  (/home/user/src/virgil/bin/dev/wave+0x4f6a36)
    #3 0x4f6a76  (/home/user/src/virgil/bin/dev/wave+0x4f6a76)
    #4 0x432837  (/home/user/src/virgil/bin/dev/wave+0x432837)
    #5 0x51ff8f  (/home/user/src/virgil/bin/dev/wave+0x51ff8f)
    #6 0x52a31b  (/home/user/src/virgil/bin/dev/wave+0x52a31b)
    #7 0x527efe  (/home/user/src/virgil/bin/dev/wave+0x527efe)
    #8 0x5257d7  (/home/user/src/virgil/bin/dev/wave+0x5257d7)
    #9 0x7f0a40925b96  (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    #10 0x427639  (/home/user/src/virgil/bin/dev/wave+0x427639)

docs / release?

I read the Virgil III paper, and it seems like a really cool mix of high level features and low level code -- the holy grail :)

I tried it out and made an echo.v3 program run under the interpreter, ran a jar, and ran an x86 executable.

Any plans for a release or maybe a README describing how to use it? I had to read the shell scripts to figure out how to invoke it.

I'm interested in the compile-time metaprogramming among other things.

It looks like it is still aimed more at embedded systems, since there's no module system or C integration? (as far as I can see)

Support 64-bit integers

Language or Compiler Enhancement?
===========================

Language and Compiler

Justification (summary of perceived benefit)
===============================

Large (64-bit) integers are necessary to represent large quantities, like 
offsets in large files, etc.

Impact estimate (select one)
----------------------
2 - small
================

Priority (select one)
----------------------
2 - medium
================


Original issue reported on code.google.com by [email protected] on 24 Jan 2013 at 7:29

Allow _ for super constructor calls

Language or Compiler Enhancement?
===========================

Language

Justification (summary of perceived benefit)
===============================

The current design requires subclasses to re-declare constructor parameters 
that are simply passed along to super constructors. This tends to be redundant 
and increases the amount of work necessary to write subclasses.

E.g.

class A {
  new(i: int) { }
}

class B extends A {
  new(i: int, j: int) super(i) { }
}


B be written more easily:

class B extends A {
  new(j: int) super(_) { }
}

or even:

class A(i: int) { }
class B(j: int) extends A(_) { }
class C extends B(3, _) { }

Impact estimate (select one)
----------------------
2 - small
================

Priority (select one)
----------------------
2 - medium
================


Original issue reported on code.google.com by [email protected] on 24 Jan 2013 at 7:24

Port Virgil to x86-64 Linux

This is a tracking issue for porting Virgil to x86-64 Linux.

I've recently filled out lib/asm/x64/X64Assembler.v3 and soon will start on the codegen.

Add -program-name option

Add an option to allow renaming the binaries output from the compiler.

% v3c -program-name=Blah.exe Foo.v3

Will output into a binary Blah.exe instead of Foo

Impact estimate (select one)
----------------------
1 - trivial
================

Priority (select one)
----------------------
3 - high
================


Original issue reported on code.google.com by [email protected] on 13 Apr 2012 at 5:26

Swig bingings for Virgil ?

Ref http://www.swig.org/exec.html

Allowing Python, Java, (etc etc) teams to drop to Virgil for functions is a key incremental strategy for converting larger projects, and indeed the developers too. A bottom-up world take over .. or pick your own lofty claim.

Gracefully handle stackoverflow on native platforms

When running on the JVM, a stack overflow manifests itself with a 
java.lang.StackOverflowError, which terminates the Virgil program. On native 
platforms, a stack overflow manifests itself by the program running past the 
end of the stack's mapped pages, causing a SIGSEGV (or SIGBUS), which cannot be 
handled by the runtime's signal handler (since there is no stack), resulting in 
termination of the program by the operating system.

Native platforms should check for stack overflow via one of the known 
mechanisms:

1. Use sigaltstack for signals
2. Stack banging
3. Explicit stack checks

Call graph analysis can likely eliminate most of #2 and #3 statically.

Original issue reported on code.google.com by [email protected] on 28 Mar 2012 at 6:46

Generate stacktraces for System.error

System.error should generate a stacktrace on native platforms.

Currently it does not because it requires a compiler intrinsic to get the 
caller IP and SP to begin stack walking.

Original issue reported on code.google.com by [email protected] on 28 Mar 2012 at 7:02

Improve WASM targets

Virgil compiles to WASM and has three different runtime implementations:

(1) rt/wave, the (W)eb(A)ssembly (V)irgil (E)nvironment), a minimal set of imports just to get Virgil running, which was only implemented in Wizard and a bit-rotted version in V8 using the C embedding API.
(2) rt/wasi_snapshot_preview1, an implementation of System against the wasi_snapshot_preview1 API, but it is not complete.
(3) rt/node, an implementation of System against the node.js APIs.

I could use some help with (2), as there are a few things not working. Also, there is no equivalent of chmod, which is a minor thing, but needed to bootstrap the compiler.

Also, I haven't fully tested (3) or made it robust. Could use some help here.

interop with C?

How is interop with C supposed to work? with FFI or clang preprocessing?

Looks great!

Very RUST-y :) (My favorite programming language)

Allow ; for empty constructors

Syntactically, ";" for an empty constructor body is allowed, it just results in 
a !UnimplementedException in at runtime when invoking the constructor--not very 
useful. Allow ";" for an empty constructor body, or make it a compile-time 
error.

Original issue reported on code.google.com by [email protected] on 28 Mar 2012 at 6:49

Windows support

What steps will reproduce the problem?
1. Download virgil
2. Try to invoke aeneas.jar
3. There is no output or something

What is the expected output? What do you see instead?
Since virgil is bootstrapped and able to target JVM I expected it to work on 
windows out-of-the-box.
But it depends on the shell script which is Unix-specific.

What version of the product are you using? On what operating system?
Tried virgil-starter and latest source checkout (fe2ba7c2d39d), on Windows 8.1 
x64.

Please provide any additional information below.
Using Cygwin is not an option, it's very bloated and slow. I'll try to hack an 
equivalent to virgil shell though.

Original issue reported on code.google.com by [email protected] on 22 Sep 2013 at 12:12

Aeneas.wasm hello-v3.v3 - no output

user@host009:~/src/virgil/bin/dev$ wave ../current/wasm/Aeneas.wasm run \
../../rt/wave/wave.v3 ../../rt/wave/System.v3 ../../test/wave/hello-v3.v3
user@host009:~/src/virgil/bin/dev$ echo $?
0

non-void main in wasm - expected 1 elements on the stack for fallthru to @1, found 2

While trying to diagnose the remainder of #18, I changed hello-v3.v3 to read:

def main() -> int {
	System.puts("Hello world!\n");
	return 33;
}

and got this output after compilation:

user@host009:~/src/virgil/bin/dev$ wave hello-v3.wasm
<unknown>:-1: Uncaught CompileError: WebAssembly.Module(): Compiling wasm function
 "wasm-function[4]" failed: expected 1 elements on the stack for fallthru to @1, found 2 @+232
ERROR: could not compile hello-v3.wasm
255 user@host009:~/src/virgil/bin/dev$

Where to ask for help - slices / memcopy

I'm having some fun making a tokenizer/parser and learning virgil. Really enjoying the language so far. Are there any community places such as irc or discord for questions?

If not, i'm trying to answer these two questions:

  • how to use Pointers
  • how to slice / get a substring of an array without making a copy

The usecase is basically just a memcopy from the end of an array to the beginning. I tried using Arrays.copy and Arrays.copyInto but couldn't figure out how to slice the last n elements.

And when I try to use something like Pointer.atContents() i'm getting an UnresolvedIdentifier: identifier "Pointer" cannot be found. I looked and couldn't find a file where Pointer is defined. 🤔

How to compile programs into WASI?

Hi,

I'm starting to trial Virgil a little bit more, and I was unable to get an application compiling to WASI.

Here's what I'm doing (in latest master)

cd apps/HelloWorld/
$ ../../bin/dev/v3c-wasi -run HelloWorld.v3
!EvalUnimplemented: CallAddress
	in main() [HelloWorld.v3 @ 2:20]

I also tried to compile and then run it with Wasmer, but it seems that the Wasm file is not valid:

cd apps/HelloWorld/
$ ../../bin/dev/v3c-wasi HelloWorld.v3
$ wasmer HelloWorld.wasm
error: failed to run `HelloWorld.wasm`
│   1: module instantiation failed (engine: universal, compiler: cranelift)
╰─▶ 2: Validation error: type mismatch: expected i32 but nothing on stack (at offset 409)

Did I miss some steps here? What can I do to help fix the issue?

wish: run-time eval (aka self-embedding and runtime linking)

Could Aeneas embed [the entirety of] itself if it sees a very special command ("eval()", for instance) when compiling? (similar to how it appends the GC source when needed)

Next request after that is to enable linking of compiled code from the running code..

[MacOS] Rosetta 2 refuses to run Virgil x86-64-darwin binaries

I recently ported Virgil to x86-64-darwin, i.e. 64-bit MacOS on Intel. I expected that the binaries generated would work automatically under Rosetta 2, but they apparently do not.

I could some help debugging some issues.

% aeneas bootstrap
% cd apps/HelloWorld/
% v3c-x86-64-darwin -output=/tmp HelloWorld.v3 
% /tmp/HelloWorld 
rosetta error: /tmp/HelloWorld: overlapping Mach-O segments
Trace/BPT trap: 5
%

Tinkering with the segment layouts in aeneas/src/x86-64/X86_64Darwin.v3 can get past that, but other errors remain. I am not sure what the rules are for Rosetta.

Rename !*Exception to !*Violation

Since these safety violations result in a termination of the program, it's not 
really accurate to call them exceptions. Violation = Termination!

Original issue reported on code.google.com by [email protected] on 28 Mar 2012 at 6:52

I wonder if it is feasible to add ARM backend for virgil

Hi,

I'm looking for a VM that can run a PLC.
The idea is:

  1. Have some kind of high level IDE (disclaimer. I build one: https://github.com/vlsi/ide61131)
  2. Make that IDE to compile the program into some kind of bytecode
  3. Make PLC to execute that bytecode

The bytecode is there so IDE, etc can be PLC-independent (that is one can easily support different kinds of CPUs without changing front-end too much).

I do like virgil's idea of "allocating all the memory at initialization".

For the "OS" I think of http://www.freertos.org/ (that will provide TCP/UDP, and some multitasking).

I aim for 200KiB...1MiB RAM devices with 200Mhz+ cpus.
I aim to fit "simple logic computation" under 1ms.

The devices might have different CPUs (some kind of ARM, AURIX) and common denominator is probably some kind of C compiler (gcc, TI, Keil, etc).

Is virgil feasible/reasonable for that?

To consider the αcτµαlly pδrταblε εxεcµταblε (APE) format cross-platform executable

Hi, I just saw your project Virgil, and the interesting part is the compilation of different targets (Native machine & Virtual Machine).
I don't know which language you used to produce the 1st compiler of Virgil, But I may guess it was C. The reason I am referring to this point is because of an open-source that tries to solve the issues of cross-compilation to native machine code from a different view. I will not give more details than the links to read, download, compile and test from the author (Justine Tunney) blogs posts. Here are the links:

In summary, it is about compiling one-time to a native-machine code (At the moment is x86) and running on any operating system platform (Darwin, Linux, BSD, Window). I see the project is promising as yours.

Built in interpretor

What IR does the built-in interpreter interpret? Is is wasm? It seems that this basic question is left untouched in the documentation which I have dug through multiple times.

Top-level namespacing

How can you disambiguate same-named components and classes from different source files (aka the module problem)?

I see that this issue was addressed as as "Future Work" in the 2013 paper https://dl.acm.org/doi/10.1145/2491956.2491962

The current EBNF grammar file contains "import" and "export" keywords but I haven't been able to find a description of their semantics:

ComponentDecl ::= "import"? "component" IDENTIFIER "{" Member* "}"

ExportDecl ::= "export" ( DefMethod | ( STRING | Ident ) ( "=" SymbolParam )? ";" )

Exceptions don't work on MacOS 10.8

What steps will reproduce the problem?
1. Write a program that throws an exception.
2. Run the program.

What is the expected output? What do you see instead?

Expected output should be an exception stacktrace. Instead, program gets stuck, 
probably in the signal handler.


Original issue reported on code.google.com by [email protected] on 18 Apr 2013 at 9:18

UTF-8 string literals

Does Virgil support UTF-8 string literals?

The documentation suggests it does:

- Aeneas parses text as bytes, only allows UTF-8 inside string constants

Here I've inserted the copyright character in a string literal:

$ cat hello.v3    
def main() {
        System.puts("Hello World ©\n");
}

$ virgil run tmp/hello.v3
[tmp/hello.v3 @ 2:21] ParseError: invalid string literal
        System.puts("Hello World ©\n");
                    ^

Hex byte values work though:

$ cat hello.v3
def main() {
        System.puts("Hello World \xC2\xA9\n");
}

$ virgil run hello.v3
Hello World ©

Support floating point

Language or Compiler Enhancement?
===========================

Language and Compiler

Justification (summary of perceived benefit)
===============================

Support for 32 and 64 bit floating point numbers is necessary to perform all 
manner of scientific and graphics calculations.

Impact estimate (select one)
----------------------
3 - large
================

Priority (select one)
----------------------
2 - medium
================


Original issue reported on code.google.com by [email protected] on 24 Jan 2013 at 7:29

NullCheckException in LinearScanRegAlloc.assignEnd

127 user@host009:~/src/virgil/bin$ ./v3c-x86-linux ../apps/Multi/Multi.v3
!NullCheckException
in LinearScanRegAlloc.assignEnd() [/Users/titzer/virgil/aeneas/src/mach/RegAlloc.v3 @ 95:66]
in LinearScanRegAlloc.assignRegs() [/Users/titzer/virgil/aeneas/src/mach/RegAlloc.v3 @ 68:57]
in X86CodeGen.genCode() [/Users/titzer/virgil/aeneas/src/x86/X86CodeGen.v3 @ 72:32]
in X86Runtime.genX86Code() [/Users/titzer/virgil/aeneas/src/x86/X86Runtime.v3 @ 24:28]
in MachProgram.layoutCode() [/Users/titzer/virgil/aeneas/src/mach/MachProgram.v3 @ 405:32]
in X86Linux.encodeCode() [/Users/titzer/virgil/aeneas/src/x86/X86Linux.v3 @ 86:32]
in X86Linux.emit() [/Users/titzer/virgil/aeneas/src/x86/X86Linux.v3 @ 37:27]
in X86Target.emit() [/Users/titzer/virgil/aeneas/src/x86/X86Target.v3 @ 21:24]
in Compilation.emit() [/Users/titzer/virgil/aeneas/src/main/Compiler.v3 @ 292:36]
in Compiler.compile() [/Users/titzer/virgil/aeneas/src/main/Compiler.v3 @ 128:34]
in Aeneas.compile() [/Users/titzer/virgil/aeneas/src/main/Aeneas.v3 @ 111:33]
in Aeneas.main() [/Users/titzer/virgil/aeneas/src/main/Aeneas.v3 @ 71:32]

More robust cross-compile testing solution

Recently I have been developing on an M1 mac, which is a platform not supported by Virgil.

This is a problem because it is not possible to run either x86-linux and x86-darwin binaries directly on this platform. In the past, I have relied on testing on one or the other x86 platform and relying on bootstrap change detection to avoid breaking the other.

To address this, I added a caching mechanism for execute tests so that "aeneas test" can at least detect if test binaries are an exact match.

Recently, I've taken to using qemu running tinycore Linux in a VM for x86 testing, but doing so is clunky, and this was a pain to set up.

This is a tracking issue for making cross-compile testing a priority.

I'm envisioning a distributed ssh/scp solution that can be driven directly by the "aeneas test" script, both with real devices and VMs.

Idea: TS Transpiler to Virgil

Since TypeScript can have programs with fully statically defined types, I wonder if it may be possible to have a transpiler that transforms TS codebases into Virgil and then we use it to compile to very lean Wasm code.

There are already some projects that do static compilation of Typescript:

Could it be possible to achieve with Virgil? Where you think may be the limitations?

Enable optimizations later in the pipeline

With 2b34472, I've added switches for turning on optimizations later in the pipeline, after specialization and normalization.

This is a tracking issue. There are a couple bugs and inlining should be enabled as well.

Improve register allocation for Virgil

Issue for tracking implementation of a graph-coloring based register allocation for Virgil with both spilling and splitting of live ranges. The splitting heuristic implemented should be cheap to compute and should not sacrifice the quality of allocation. A simple splitting heuristic is implemented in the V8 optimizing JS compiler.

The main concern with a graph-coloring approach is the cost of rebuilding the interference graph after splitting or spilling a live range. Ideally, the interference graph reconstruction is cheap. An approach like the tiling based approach of Callahan-Koblenz [1] can be considered.

Current Roadmap

  • Rip out liveness analysis from current register allocator
  • Interference graph construction and graph coloring (with spilling)
  • Refine splitting heuristic

[1]: Callahan, David, and Brian Koblenz. “Register Allocation via Hierarchical Graph Coloring.” Proceedings of the ACM SIGPLAN 1991 Conference on Programming Language Design and Implementation, vol. 26, no. 6, 1991, pp. 192–203.

Foreach loop over sequences, lists, maps

Language or Compiler Enhancement?
===========================

Language

Justification (summary of perceived benefit)
===============================

Virgil currently only supports foreach loops over arrays. Devise a mechanism to 
allow cons Lists, Sequences, Maps, and other user types to be foreach-iterable. 
This must be done as efficiently as possible, without implicitly allocating 
objects on the heap.


Impact estimate (select one)
----------------------
2 - small
================

Priority (select one)
----------------------
3 - high
================


Original issue reported on code.google.com by [email protected] on 24 Jan 2013 at 7:28

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.