This is a C++ interpreter for Lox, made while taking on the "Build your own Interpreter" Challenge by CodeCrafters.
from Crafting Interpreters -- Lox is a language created solely for the purpose of the book and learning.
This is the repo for codecrafters' online judge exercise, a more detailed version see here.
A C++23 compiler is required to build the project; tested with gcc, clang, and MSVC. Bazel or CMake is required to build the project.
$env:AC_CPP_DEBUG=1 # set the environment variable to enable debug mode
bazel build //tools:interpreter # build the interpreter
bazel test //tests:... # run the tests
vcpkg is required to install the dependencies.
Make sure the option AC_CPP_DEBUG
is set to ON
in the CMakeLists.txt file.
cmake --preset= # see available presets via `cmake --list-presets` make sure to alter the toolchain file
No external dependencies are required for release mode.
You can run Bazel or CMake as mentioned above(only for target interpreter
),
or run the run.sh
script in the root directory(Linux).
interpreter tokenize <source>
interpreter parse <source>
interpreter evaluate <source>
interpreter run <source>
# repl was on the way, but not in a forseeable future...
program → declaration* EOF ;
declaration -> varDecl
| statement
| funcDecl
| classDecl ;
varDecl -> "var" IDENTIFIER ( "=" expression )? ";" ;
funcDecl -> "fun" function ;
classDecl -> "class" IDENTIFIER ("<" IDENTIFIER )? ( "{" function* "}" )? ;
statement -> exprStmt
| printStmt
| block
| ifStmt
| whileStmt
| forStmt
| returnStmt ;
exprStmt -> expression ";" ;
printStmt -> "print" expression ";" ;
block -> "{" declaration* "}" ;
ifStmt -> "if" "(" expression ")" statement ( "else" statement )? ;
whileStmt -> "while" "(" expression ")" statement ;
forStmt -> "for" "(" ( varDecl | exprStmt | ";" )
expression? ";"
expression? ")" statement ;
returnStmt -> "return" expression? ";" ;
expression -> assignment ;
assignment -> ( call "." )? IDENTIFIER "=" assignment
| logic_or ;
logic_or -> logic_and ( "or" logic_and )* ;
logic_and -> equality ( "and" equality )* ;
equality -> comparison ( ( "!=" | "==" ) comparison )* ;
comparison -> term ( ( ">" | ">=" | "<" | "<=" ) term )* ;
term -> factor ( ( "-" | "+" ) factor )* ;
factor -> unary ( ( "/" | "*" ) unary )* ;
unary -> ( "!" | "-" ) unary
| call ;
call -> primary ( "(" arguments? ")" | "." IDENTIFIER )* ;
primary -> NUMBER | STRING
| "true" | "false" | "nil" | "this"
| "(" expression ")" | IDENTIFIER | "super" "." IDENTIFIER;
arguments -> expression ( "," expression )* ;
function -> IDENTIFIER "(" parameters? ")" block ;
parameters -> IDENTIFIER ( "," IDENTIFIER )* ;
alnums -> [a-zA-Z0-9]
| [.!@#$%^&*()]
| [...] ;
number -> digit + ( "." digit + )? ;
string -> "\"" + ([[alnums]])* + "\"" ;
identifier -> [a-zA-Z_] + [a-zA-Z0-9_]* ;
note: the
cpp
was just for syntax highlighting in vscode to make it look prettier than plain text.
dependencies for interpreter, generated by Bazel
This exercise is still in active development, and I will be updating it as I progress through the book.
TODO(pirority from high to low)
- Desugar
for
statement(currently handles it saparately) - Binding and resolving
- Add
class
support - Add class inheritance support
- JVM bytecode generation
- LLVM IR generation
- Machine code generation(x86_64, risc-v)