geertguldentops / jlox

Java implementation of the Lox programming language from the book "Crafting Interpreters"
MIT License
2 stars 1 forks source link

README

What is this repository for?

This is a Java version of the lox interpreter from the wonderful book Crafting Interpreters

It is written in pure Java, using only 2 external Java libraries for testing: JUnit 5 and AssertJ.

This implementation focuses heavily on unit testing. I tried to unit test as many scenarios as is reasonably possible since I felt this really deepened my understanding of how exactly the interpreter works.

This is also the reason why this implementation contains relatively little acceptance tests.

be.guldentops.geert.lox.LoxMain and be.guldentops.geert.lox.tools.GenerateAbstractSyntaxTree are not tested by design, see their respective Javadocs why.

How do I get set up?

Compiling the interpreter

Maven (3) is used to compile the code and run the tests:

Running a Lox program

Lox has 2 modes it can run in:

  1. REPL mode: Run the main method in the LoxMain class with exactly 1 program argument, the path to the Lox script you want to run.

  2. Script mode: Run the main method in the LoxMain class with no program arguments.

Generating the AST

The Expression class and its subtypes are generated by the GenerateAbstractSyntaxTree class.

GenerateAbstractSyntaxTree has a main method which accepts exactly 1 program argument, the output directory of the generated Expression class.

E.g.: ${ABSOLUTE_PATH_TO_JLOX_PROJECT}/jlox/src/main/java/be/guldentops/geert/lox/grammar

Running all the tests (unit + acceptance)

Through maven: mvn clean test

Using an IDE, for instance IntelliJ IDEA: Run all JUnit tests in package be.guldentops.geert.lox

Running all the unit tests

Run all the tests except the acceptance tests which are located in the be.guldentops.geert.lox.LoxAcceptanceTest class

Running all the acceptance tests

Run all the tests in the be.guldentops.geert.lox.LoxAcceptanceTest class

Lox Lexical Grammar

NUMBER          → DIGIT+ ( "." DIGIT+ )? ;
STRING          → '"' <any char except '"'>* '"' ;
IDENTIFIER      → ALPHA ( ALPHA | DIGIT )* ;
ALPHA           → 'a' ... 'z' | 'A' ... 'Z' | '_' ;
DIGIT           → '0' ... '9' ;

Lox Syntax Grammar

program         → declaration* EOF ;

declaration     → classDecl
                | funDecl
                | varDecl
                | statement ;
classDecl       → "class" IDENTIFIER ( "<" IDENTIFIER )?
                "{" function* "}" ;
funDecl         → "fun" function ;
function        → IDENTIFIER "(" parameters? ")" block ;
parameters      → IDENTIFIER ( "," IDENTIFIER )* ;
varDecl         → "var" IDENTIFIER ( "=" expression )? ";" ;

statement       → exprStmt
                | forStmt
                | ifStmt
                | printStmt
                | returnStmt
                | whileStmt
                | block ;

exprStmt        → expression ";" ;                    
forStmt         → "for" "(" ( varDecl | exprStmt | ";" )
                            expression? ";"
                            expression? ")" statement ;
ifStmt          → "if" "(" expression ")" statement ( "else" statement )? ;
printStmt       → "print" expression ";" ;
returnStmt      → "return" expression? ";" ;
whileStmt       → "while" "(" expression ")" statement ; 
block           → "{" declaration* "}" ;

expression      → assignment ;

assignment      → ( call "." )? IDENTIFIER "=" assignment
                | logic_or ;

logic_or        → logic_and ( "or" logic_and )* ;
logic_and       → equality ( "and" equality )* ;
equality        → comparison ( ( "!=" | "==" ) comparison )* ;
comparison      → addition ( ( ">" | ">=" | "<" | "<=" ) addition )* ;
addition        → multiplication ( ( "-" | "+" ) multiplication )* ;
multiplication  → unary ( ( "/" | "*" ) unary )* ;

unary           → ( "!" | "-" ) unary | call ;
call            → primary ( "(" arguments? ")" | "." IDENTIFIER )* ;
arguments       → expression ( "," expression )* ;
primary         → "true" | "false" | "nil" | "this"
                | NUMBER | STRING | IDENTIFIER | "(" expression ")"
                | "super" "." IDENTIFIER ;

Lox Precedence Rules

Name Operators Associates
Unary ! - Right
Multiplication / * Left
Addition - + Left
Comparison > >= < <= Left
Equality == != Left