Giter Club home page Giter Club logo

lox-interpreter's People

Contributors

stefanobaghino avatar

Watchers

 avatar  avatar

lox-interpreter's Issues

Implement a formatter

In principle, it looks like it's more or less the reverse of a scanner which can possibly be configured.

Syncing prevents normal function of REPL

When a parsing error occurs in REPL mode, the parser tries to get to the following sync point before resuming normal operation, preventing the reporting of the error until such point is reached.

Refactor scanning to be more idiomatic

The scanner is more or less ported as-is from the original Java code. This is probably a good idea for the time being because by minimizing the differences from the book, it's less likely to be confusing. However, once it's clear that scanning if finalized, it can and should be refactored to be more idiomatic and make full use of Scala.

Evaluate and possibly adopt mutation testing

Since the whole project seems to not have any automatic testing in mind and the code is being ported as-is from Java to Scala Go, mutation testing might be useful to uncover whether the testing coverage I'm adding going along is not sufficient.

Add support for `break` statements

The syntax is a break keyword followed by a semicolon. It should be a syntax error to have a break statement appear outside of any enclosing loop. At runtime, a break statement causes execution to jump to the end of the nearest enclosing loop and proceeds from there. Note that the break may be nested inside other blocks and if statements that also need to be exited.

Add support for anonymous functions

Languages that encourage a functional style usually support anonymous functions or lambdas—an expression syntax that creates a function without binding it to a name. Add anonymous function syntax to Lox so that this works:

fun thrice(fn) {
  for (var i = 1; i <= 3; i = i + 1) {
    fn(i);
  }
}

thrice(fun (a) {
  print a;
});
// "1".
// "2".
// "3".

How do you handle the tricky case of an anonymous function expression occurring in an expression statement:

fun () {};

-- https://craftinginterpreters.com/functions.html#challenges

Add assert statements

Print statements work well to manually inspect the state, but asserts could help making it easier to test the language. The current approach is that of having the interpreter execute some statements and then passing an expression that evaluates a predicate, which is ultimately used to evaluate whether the code was interpreted correctly.

interpreter.interpret(statements)
val aEquals2 =
Expr
.Binary(
Expr.Variable(Tokens.Identifier),
Tokens.EqualEqual,
Expr.Literal(2.0),
)
.accept(interpreter)
.asInstanceOf[Boolean]
assert(aEquals2)

This might be repackaged as a function after #7 is closed. Hypothetically, refactoring so that the state can be inspected without necessarily invoking the interpreter explicitly might make this point moot.

Setup CI

Run tests, verify formatting, evaluate and possibly implement code coverage checks

Evaluate and possibly adopt fuzz testing

As part of merging #41, I changed the scanner as it is implemented in the book to make the error flow explicit in the code. As part of this, the scanner is also supposed to stop on UTF-8 decoding errors, but this is currently not tested. To make sure all edge cases are covered in this regard, it would be nice to see whether fuzz testing could come in handy to do so without creating a bunch of test cases by hand.

Test the scanner and parser together

In #26 the parser is tested by feeding manually crafted tokens. It would be interesting to integrate the two components in a single test. To what extent would it make sense to drop some or all tests in the scanner?

Add support for comma expressions

In C, a block is a statement form that allows you to pack a series of statements where a single one is expected. The comma operator is an analogous syntax for expressions. A comma-separated series of expressions can be given where a single expression is expected (except inside a function call’s argument list). At runtime, the comma operator evaluates the left operand and discards the result. Then it evaluates and returns the right operand.

Add support for comma expressions. Give them the same precedence and associativity as in C. Write the grammar, and then implement the necessary parsing code.

-- https://craftinginterpreters.com/parsing-expressions.html#challenges

Test error reporting from the scanner

Evaluate refactoring error detection so that it happens before error reporting to make it easier to test. Ideally this should enable to easily reach a 100% test coverage in the scanner without capturing logs.

Add support for block comments

Add support to the scanner for C-style /* ... */ block comments. Make sure to handle newlines in them. Consider allowing them to nest. Is adding support for nesting more work than you expected? Why?

Implement a Reverse Polish Notation expression visitor

In reverse Polish notation (RPN), the operands to an arithmetic operator are both placed before the operator, so 1 + 2 becomes 1 2 +. Evaluation proceeds from left to right. Numbers are pushed onto an implicit stack. An arithmetic operator pops the top two numbers, performs the operation, and pushes the result. Thus, this:

(1 + 2) * (4 - 3)

in RPN becomes:

1 2 + 4 3 - *

Define a visitor class for our syntax tree classes that takes an expression, converts it to RPN, and returns the resulting string.

Failed assertions always report line 0

Right now the assertion error always reports line 0 since the token doesn't have a reference to the line number. Make sure at least the line number is reported correctly.

Consider using pattern matching for parsing

Right now, parsing is implemented using the visitor pattern. This is useful writing Java, but it's probably better expressed in Scala using pattern matching. Evaluate this refactoring and possibly implement it. Ideally, write down as a comment which direction you decided to take and why.

Port to Scala 3

As a personal challenge and a way to learn something new, it would be interesting to port this project to Scala 3.

Fix shadowing

Implementing static binding resolution (#59) seems to have broken shadowing. While the original Java code was ported apparently faithfully, I suspect the problem arises from the fact that I implemented the whole interpreter to discover the user input one line at a time, possibly breaking assumptions in the original implementation.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.