Programming languages and compilers are one of my biggest interests, following the Swift evolution list and watching Jonathan Blow develop his new language are two of my hobbies. I’ve played with parsers in the past, and tried to mess around with the missing metaprogramming features in Swift but I’ve never tried to implement a complete language. Although I understand the theory behind it I was missing the motivation to get my hands dirty, motivation that Bob’s book seems to have given me!
The plan here is to follow Bob’s work on the book and implement the chapters one by one in Swift. I’m really curious to see how Swift is suited for this kind of work.
One thing to note is that I’m trying to write a mix between idiomatic Swift (whatever that means in this young language) and the code that the book shows in Java. Because I’m not making up the language nor the compiler/interpreter but I’m following the book I don’t want to get into a point where in future chapters the book asks for some code changes and they get too complex because I was trying to be too smart. So I take it as a learning exercise and try to implement it as close as possible, except for those occasions where I can’t resist using Swift nice features like guard or the powerful switch statements. There will be time to maybe write another compiler that explores different ways of doing things, but this is not it.
Helper method for parsing left-associative series of binary operators. Swift can’t pass variadic arguments between functions (no array splatting), so it’s a little bit hugly.
Challenge 1: Add prefix and postfix ++ and – operators.
Challenge 2: Add support for the C-style conditional or “ternary” operator ?:
Challenge 3: Add error productions to handle each binary operator appearing without a left-hand operand.
Challenge 1: Allowing comparisons on types other than numbers could be useful.
Challenge 2: Many languages define + such that if either operand is a string, the other is converted to a string and the results are then concatenated.
Challenge 3: Change the implementation in visitBinary() to detect and report a runtime error when dividing by 0.
Challenge 1: Multiple inheritance. Nothing to implement…?
Challenge 2: Reverse method lookup order in class hierarchy.
Challenge 3: Add your own features!
Tests
I integrated Bob tests in order to be able to make sure this implementation behaves in the same way as the original implementation. You can find the test in this project with the test.pyscript modified to work with this project. You can also find a diff with the main modifications.
Example of usage: sh build.sh; ./tools/test.py chap13_inheritance
Project structure
This project now uses SPM to manage the executables, framework and dependencies.
The bulk of the interpreter is implemented in a framework and the executable is just a small CLI program that uses that framework.
slox: The executable. Can be used as a CLI to run the interpreter.
LoxCore: The main framework that contains the implementation of the Lox language in Swift.
GenerateAst: A small executable that generates the AST for LoxCore.
slox
Swift implementation of a Lox interpreter
This project contains a Swift implementation of the Lox language following the book Crafting Interpreters written by Bob Nystrom. Crafting Interpreters in GitHub
Programming languages and compilers are one of my biggest interests, following the Swift evolution list and watching Jonathan Blow develop his new language are two of my hobbies. I’ve played with parsers in the past, and tried to mess around with the missing metaprogramming features in Swift but I’ve never tried to implement a complete language. Although I understand the theory behind it I was missing the motivation to get my hands dirty, motivation that Bob’s book seems to have given me!
The plan here is to follow Bob’s work on the book and implement the chapters one by one in Swift. I’m really curious to see how Swift is suited for this kind of work.
One thing to note is that I’m trying to write a mix between idiomatic Swift (whatever that means in this young language) and the code that the book shows in Java. Because I’m not making up the language nor the compiler/interpreter but I’m following the book I don’t want to get into a point where in future chapters the book asks for some code changes and they get too complex because I was trying to be too smart. So I take it as a learning exercise and try to implement it as close as possible, except for those occasions where I can’t resist using Swift nice features like
guard
or the powerfulswitch
statements. There will be time to maybe write another compiler that explores different ways of doing things, but this is not it.Implementation
as of 11/02/2018
A TREE-WALK INTERPRETER
?:
Tests
I integrated Bob tests in order to be able to make sure this implementation behaves in the same way as the original implementation. You can find the test in this project with the
test.py
script modified to work with this project. You can also find a diff with the main modifications.Example of usage:
sh build.sh; ./tools/test.py chap13_inheritance
Project structure
This project now uses SPM to manage the executables, framework and dependencies.
The bulk of the interpreter is implemented in a framework and the executable is just a small CLI program that uses that framework.
Author
Alejandro Martinez | http://alejandromp.com | @alexito4