A compiler framework for managed code.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
Examples Updated "Set.ds" example Jul 23, 2015
Flame.Analysis Use Flame.Optimization.DissectedCall, remove Flame.Analysis.Dissected… Jan 4, 2017
Flame.Build.Lazy Untabify Flame.Build.Lazy Sep 10, 2017
Flame.Bytecode Get rid of LateBoundLabel Mar 26, 2017
Flame.Cecil Support runtime-implemented methods Sep 16, 2017
Flame.CodeDescription Updated copyright in assembly info Jun 3, 2016
Flame.Compiler Modernize IExpression.ds, GetMethodExpression.ds Oct 3, 2017
Flame.Cpp Define IEnvironment.GetBuiltinType May 6, 2017
Flame.DSProject Updated packages May 3, 2016
Flame.DSharp Make '--environment=standalone' the default Jul 26, 2017
Flame.ExpressionTrees Make GenericInstanceType a first-class citizen in TypeTransformerBase Apr 1, 2017
Flame.Front.Common Allow StandaloneEnvironment instances to have custom names Sep 16, 2017
Flame.Front Allow StandaloneEnvironment instances to have custom names Sep 16, 2017
Flame.Functional Delete some unused TypeDiffComparer methods Apr 25, 2017
Flame.Intermediate Support using the null type in on-disk IR Nov 6, 2017
Flame.MIPS Define IEnvironment.GetBuiltinType May 6, 2017
Flame.Markdown Removed IMarkupNode references Jan 28, 2016
Flame.Optimization Avoid rewriting reference types with finalizers in -fheap2stack Sep 10, 2017
Flame.Python Define IEnvironment.GetBuiltinType May 6, 2017
Flame.Recompilation Define CompileAtomicallyAttribute to make sure types don't come out h… Sep 18, 2017
Flame.Syntax Disambiguate some dictionary copies Sep 3, 2017
Flame.TextContract Minor tweaks May 15, 2017
Flame.Verification Make 'method not implemented' errors more bearable May 4, 2017
Flame.Wasm Optimize WebAssembly files before writing them to disk Jun 19, 2017
Flame.XmlDocs Make --docs use the target assembly's signature May 15, 2017
Flame Make null a primitive type Nov 6, 2017
FlameRT Updated copyright in assembly info Jun 3, 2016
Pixie Merge commit 'a6b9c8553b111b990ca3549ef5e33a80e93ca3db' Jan 28, 2016
Tests Fix a faulty test description Sep 10, 2017
UnitTests Make StandaloneEnvironmentTests a little more comprehensive Sep 9, 2017
dsc Increment the version number to v0.10.3 Sep 18, 2017
flame-wasm Move the WebAssembly back-end to a separate executable Jul 22, 2017
.gitignore Added *.userprefs files to .gitignore Dec 12, 2015
.travis.yml Use an absolute path for wasm-interp Jun 9, 2017
BootstrapFlame.sh Merge branch 'master' of https://github.com/jonathanvdc/Flame Apr 21, 2017
BuildCI.bat Clear the %args% variable in the BuildCI.bat script Apr 1, 2017
BuildCI.sh Migrate away from XBuild toward MSBuild Aug 8, 2017
BuildFlame.bat Flame projects use -fwrap-extension-properties now Dec 11, 2015
BuildFlame.sh Migrate away from XBuild toward MSBuild Aug 8, 2017
BuildFlameCore.sh Added a BuildFlameCore.sh build script Feb 28, 2016
Flame.Build.Lazy.nuspec Created a NuGet package for Flame.Build.Lazy Jul 28, 2016
Flame.Compiler.nuspec Created lightweight Flame.Compiler package Jul 27, 2016
Flame.Front.nuspec Remove dependency on Newtonsoft.Json Jul 26, 2017
Flame.Optimization.nuspec Created a Flame.Optimization package Jul 30, 2016
LICENSE Initial commit Feb 16, 2015
LinkFlame.bat Updated LinkFlame.* scripts Dec 19, 2015
LinkFlame.sh chmod +x'ed some *.sh files Mar 31, 2016
README.md Update README Jan 19, 2017
all-tests.test Move the WebAssembly back-end to a separate executable Jul 22, 2017
appveyor.yml Increment the version number to v0.10.3 Sep 18, 2017

README.md

Build Status

Linux Windows
Build Status Build status

Flame

Flame is a collection of modular, open-source .NET libraries that can be leveraged to build a compiler. It provides reusable components and a common compilation pipeline, which can be extended with additional passes, to suit the specific needs of source and target languages.

Flame specializes in compiling managed code: object-oriented, garbage-collected, high-level programming languages, which are compiled ahead-of-time to some virtual machine's bytecode. Think C# and Java.

In a way, Flame is a compiler construction kit for managed languages, much like LLVM is for native languages. Building your own compiler is easy: all you need is a front-end that generates valid Flame IR (that's short for intermediate representation, more on that later), and Flame will take care of the rest. Specifically, it will (among other things):

  • Parse command-line options for you.
  • Resolve library dependencies.
  • Allow you to easily print expressive diagnostics, which can highlight source code.
  • Optimize the IR that the front-end generates.
  • Optionally link multiple assemblies together, at compile-time. As a bonus, unused types/methods/fields are discarded when the final executable is compiled.
  • Perform codegen: a Flame back-end of your choice will generate an output assembly.

In short, it allows you to build and implement an awesome compiled programming language, instead of constantly having to worry about the details of the compilation process.

Note: Flame is still under development. It contains its fair share of bugs. Be sure to open an issue if you encounter one (especially when using 'stable' components).

Getting and building Flame

NuGet

If you want to use Flame as a library, then I recommend you get the latest stable Flame.Front NuGet package, and add that to your project.

If you for some reason can't, or don't want to, use NuGet, then you can get a pre-built version of dsc (and the Flame libraries it ships with) and optionally compile Flame yourself.

Note that Flame is partially bootstrapping: you'll need a working version of dsc to compile Flame. Fortunately, you can grab the latest (stable) version of dsc from the releases page. The download itself is dsc.zip. You can't miss it.

Once dsc has been downloaded and unzipped, you can use it to get Flame set up for you. There are two ways to do this:

The easy way: copying the executables

You can convince dsc to copy all libraries (including Flame) that shipped with dsc to the working directory by running:

$ dsc -copy-rt

Create a console application, reference the libraries you require (you can probably lose Flame.DSharp, unless you need a D# front-end) in your project, and you're good to go. Note that you're using the latest stable-ish version of the Flame libraries now. If you want the latest features, I recommend you take:

The hard way: building Flame

Building Flame is actually not that hard. You'll need the following:

  • D# compiler: dsc (the dsc.zip download). I recommend you put it in your path variable, or define it as an alias.
  • C# compiler, like csc or mcs.
  • F# compiler: fsc (if you want to compile the functional bindings for Flame).
  • msbuild or xbuild.

Now run:

Linux:

$ ./BuildFlame.sh

Windows:

$ BuildFlame.bat
$ msbuild /p:Configuration=Release Flame.Cecil\Flame.Cecil.sln

That's it. The Flame libraries you just compiled should be located in the bin subdirectories of the top-level Flame project directories.

Flame's architecture

Front-ends, back-ends and drivers

There is no fixed input or output format for Flame: reading input and writing output is accomplished by individual front-ends and back-ends, respectively. The Flame libraries provide a common middle-end, as well as a number of back-ends. Flame currently has the following relatively stable back-ends:

  • CLR (.NET)
  • Flame's intermediate representation (IR)

It also comes bundled with a number of experimental back-ends, which may not support all source language features:

  • C++ code (experimental)
  • Python code (experimental)
  • WebAssembly S-expressions (experimental)

This repository includes front-ends for Flame's intermediate representation and the D# programming language. But Flame is extensible, so you can just write your own.

A driver program is the actual compiler: it's a compact program that glues the Flame libraries and the front-end together. As an example, here's the source code for dsc's main function: Program.cs.

Intermediate representation

At the heart of Flame is the intermediate representation (IR), which is a language-agnostic way of representing code. Front-ends generate this IR, back-ends consume it, and the middle-end optimizes it.

Flame IR can be stored both in-memory and on-disk. That's pretty neat, because it allows us to compile a project, save it as IR, and then link it with some other project, which can even be in another programming language.

The D# programming language

D# is - roughly speaking - a dialect of C#. Implementation-wise, it's a general-purpose programming language that is implemented as a Flame front-end. dsc is the D# compiler.

A number of Flame libraries are written in D#, but you don't need to know D# to use Flame.

An overview of Flame libraries

Flame

The core Flame library is mainly a reflection framework. It provides common interfaces and functionality for assemblies, namespaces, types and type members. Also, Flame contains some primitive types, whose functionality should have an equivalent on any platform.
Flame is written in D#.

Flame.Compiler

Flame.Compiler provides a common API for code generation, and is written in D#.
A brief list of its functionality is as follows.

Low-level code generation

This is achieved by the ICodeGenerator interface, which allows for the creation of ICodeBlocks: opaque, implementation-defined objects that represent a chunk of target-specific code. Any ICodeBlock implementation must support yielding zero or one values, like a statement or expression. These code blocks need not, however, restrict themselves to this model. The ICodeBlock implementations for the .Net Framework IL, for example, conveniently model a stack, whereas a code block implementation for a register-based architecture may use registers instead.

High-level expression-statement trees

The IExpression and IStatement interfaces are a programmer-friendly abstraction over the lower-level emit API. Expressions can be queried for their type, and support compile-time evaluation. Both statements and expressions have an "Optimize" method, which is intended to perform simple optimizations, like compile-time string concatenation.

Common project interfaces

Flame.Compiler also includes some simple interfaces that define common project behavior to make project file format interoperation easier.

Textual code generation

CodeBuilder and CodeLine ease the process of generating well-formatted textual code.

Assembly creation

IAssemblyBuilder, INamespaceBuilder, ITypeBuilder, etc function as a portable interface for any back-end.

Flame.Syntax

Flame.Syntax is a small project that makes writing front-ends and back-ends for various programming languages easier.
Flame.Syntax is written in D#.

Flame.DSharp

Flame.DSharp is the D# front-end which is used in dsc.
It is written in D#.

Flame.Cecil

Flame.Cecil facilitates reflecting upon and emitting .Net Framework assemblies. dsc uses this library to reference and generate .Net assemblies.
Flame.Cecil is written in C#.

Flame.Cpp

Flame.Cpp is an experimental C++ back-end, which can be used by stating -platform C++ when compiling with dsc. Since Flame.Cpp cannot parse C++ itself, dsc "plugs" are used to allow the programmer to interact with the standard library from managed code. Plugs for PlatformRT and PortableRT can be found in the "Examples" folder.
Flame.Cpp is written in C#.

Flame.Python

Flame.Python is an experimental Python back-end, accessible through -platform Python when compiling with dsc.
Flame.Python is written in C#.

Flame.Recompilation

Flame.Recompilation uses the assembly creation and decompilation interfaces of Flame.Compiler and the reflection facilities provided by Flame to "recompile" assemblies, namespaces, types and type members from one assembly to another.
Flame.Recompilation is written in C#.

dsc

dsc is a command-line utility that compiles D# code files and projects using Flame.DSharp and one of the various back-ends, such as Flame.Cecil, Flame.Python and Flame.Cpp.
dsc is written in C#.