Skip to content
A toy compiler and VM for a small language
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.

Siilinkari - a small language

Big languages (Java, Kotlin, Ceylon) seem to be named after big islands. Siilinkari is barely a language, just like Siilinkari is barely an island.

In fact, the point of Siilinkari is not to write programs in it, but rather to function as a readable introduction to the world of compilers. You can browse the code, try out implementing new features and play around.


# ./gradlew clean build

Play with REPL

# java -jar build/libs/siilinkari-all.jar
Welcome to Siilinkari! Enjoy your stay or type 'exit' to get out.
> var x = 4
> var s = ""
> if (x == 2 + 2) { var t = "It"; s = t + " worked!" }
> s
String = "It worked!"
> :dump if (x == 2 + 2) { var t = "It"; s = t + " worked!" }
0 frame[2] = global[4] ; x
1 frame[3] = Constant(4)
2 frame[2] = frame[2] == frame[3]
3 jump-if-false frame[2] 12
4 jump 5
5 frame[2] = Constant("It")
6 frame[3] = frame[2] ; (dup)
7 frame[1] = frame[3] ; store local t
8 frame[3] = Constant(" worked!")
9 frame[2] = frame[2] ++ frame[3]
10 global[5] = frame[2] ; s
11 jump 12
12 frame[2] = Constant(Unit)
13 quit frame[2]
> exit
Thank you for visiting Siilinkari, have a nice day!

Get to know the code

The evaluator consists of the following pipeline:

   Representation    Stage        Important classes
   --------------    -----        -----------------

      source code                  String
          o--------- lexer         siilinkari.lexer.{Lexer,LookaheadLexer}
       tokens                      siilinkari.lexer.Token
          o--------- parser        siilinkari.parser.Parser
  abstract syntax tree             siilinkari.ast.{Expression, Statement}
          o--------- type checker  siilinkari.types.{Type, TypeChecker}, siilinkari.env.{StaticEnvironment, Binding}
    typed syntax tree              siilinkari.types.{TypedExpression, TypedStatement}
          o--------- optimizer     siilinkari.optimizer.ASTOptimizer
    typed syntax tree              (same as above)
          o--------- translator    siilinkari.translator.Translator
      IR opcodes                   siilinkari.translator.{IR, BasicBlock}
          o--------- peephole      siilinkari.optimizer.peepholeOptimize
          |          optimization
      IR opcodes                   (same as above)
          o------- IR translation  siilinkari.translator.TranslateIRToOpCodes
    stack vm opcodes               siilinkari.vm.{OpCode, CodeSegment}
          o--------- evaluator     siilinkari.vm.{Evaluator, ThreadState, DataSegment}
        values                     siilinkari.objects.Value

Start from the important classes and either work your way through the pipeline, or just concentrate on a single transformation pass.

Project ideas

If you want to play around, here are some ideas to get started:

  • Add new unless (x) { ... } statement that works like if (!x) { ... }.
  • Convert if-statement to expression so you can say var x = if (a) b else c;.
  • Add a simple evaluator that evaluates either the typed AST directly instead of translating the code to stack vm opcodes.
  • Implement a pretty printer: it should take an AST and write it to output properly formatted.
  • Modify lexer and parser so that semicolons are not required at the end of statements.
  • Modify lexer and parser to support indentation based syntax.
  • Add support for higher order functions and lambdas.

Want more?

If you want a taste of a bigger language, take a look at Blunt. It implements a large subset of ML/Haskell-like language (see e.g. prelude.blunt and river.blunt), but naturally the implementation is a lot more complex.

You can’t perform that action at this time.