Git Product home page Git Product logo

crafting-interpreters-rs's Introduction

Crafting Interpreters in Rust

Giving https://craftinginterpreters.com/ a try, while learning Rust at the same time.

Just getting started with both :)

๐Ÿฆ€ ๐Ÿฆ€ ๐Ÿฆ€ This now includes two fairly complete implementations of Bob Nystrom's Lox language: one as a tree-walk interpreter, and the other as a bytecode interpreter. The treewalk interpreter does not include a garbage collector (the bytecode interpreter does). The bytecode interpreter is written completely in safe Rust (though an unsafe version would likely be much faster). ๐Ÿฆ€ ๐Ÿฆ€ ๐Ÿฆ€

Examples

Consider fib.lox

fun fib(n) {
  if (n < 2) return n;
  return fib(n - 1) + fib(n - 2);
}

var before = clock();
print fib(25);
var after = clock();
print after - before;

We can run this in the treewalk interpreter using

cargo run --release --quiet -- fib.lox --treewalk

On my laptop, this prints a timing of 1755 milliseconds. We can run the same thing in the bytecode interpreter using

cargo run --release --quiet -- fib.lox

On the same laptop, this shows a timing of 401 milliseconds. For comparison, on the same laptop, the tiger compiler computes the same answer in 0.00s user 0.00s system 4% cpu 0.077 total (not counting compilation :)). A C compiler, or tigerc using the llvm backend :), computes this in 0.00s user 0.00s system 65% cpu 0.004 total.

Now consider hello_world.lox

print "hello world!";

We can tokenize this with

cargo run --release --quiet -- hello_world.lox --show-tokens

Which gives output

[
    Token { ty: Print, lexeme: "print", literal: None, line: 1, col: 4},
    Token { ty: String, lexeme: ""hello world!"", literal: Some(Str("hello world!")), line: 1, col: 19},
    Token { ty: Semicolon, lexeme: ";", literal: None, line: 1, col: 20},
    Token { ty: Eof, lexeme: "", literal: None, line: 1, col: 20},
]

We can show the AST with

cargo run --release --quiet -- hello_world.lox --show-ast

Which gives

[
    Print(
        Literal(
            String(
                "hello world!",
            ),
        ),
    ),
]

Finally, we can show compiled bytecode with

cargo run --release --quiet -- hello_world.lox --disassemble

Giving

============ hello_world.lox ============
------------ constants -----------
0    "hello world!"

------------ code -----------------
0000   OP_CONSTANT "hello world!" (idx=0)                 line 1
0001   OP_PRINT                                           line 1
0002   OP_NIL                                             line 1
0003   OP_RETURN                                          line 1

Debugger

This project includes a basic (in-progress, possibly never to progress further) debugger.

For example, consider f.lox

fun a() { b(); }
fun b() { c(); }
fun c() {
  c("too", "many");
}

a();

We can explore this in the debugger with

$ cargo run --release --quiet -- f.lox --debug
(loxdb) b 4
inserted breakpoint at line 4
(loxdb) g
reached breakpoint at line 4
(loxdb) list
    2    fun b() { c(); }
    3    fun c() {
==> 4      c("too", "many");
    5    }
    6
    7    a();

==> 0000   OP_GET_GLOBAL String("c") (idx=0)                  line 4
    0001   OP_CONSTANT "too" (idx=1)                          line 4
    0002   OP_CONSTANT "many" (idx=2)                         line 4
    0003   OP_CALL 2                                          line 4
(loxdb) bt
[line 7] in script
[line 1] in a()
[line 2] in b()
[line 4] in c()
(loxdb) g
Lox runtime error: Expected 0 arguments but found 2..

Traceback:

[line 7] in script
[line 1] in a()
[line 2] in b()
[line 4] in c()

REPL

A REPL for interactive development is also available, which uses the slower treewalk interpreter. Launch with

cargo run --release --quiet

Here's an example session:

$ cargo run --release --quiet
============================================
Welcome to lox! using tree-walk interpreter.
============================================

>>> var x = 42;
>>> fun f(n) { return n + 1; }
>>> f(x);
43

Extensions

Using the --Xlists command line switch (eg cargo run --release --quiet -- --Xlists), we can enable lists

===================================================
Welcome to lox 0.1.0! Using tree-walk interpreter.

Authors: Thomas Peters <[email protected]>
===================================================

>>> var xs = [1,2,3]
>>> xs
[1, 2, 3]

Lists don't have much functionality yet, but they have lengths

>>> len(xs)
3

can be concatenated

>>> var ys = xs + xs
>>> ys
[1, 2, 3, 1, 2, 3]

can be mapped over

>>> fun square(x) { return x * x; }
>>> map(square, xs)
[1, 4, 9]
>>>

can be iterated

>>> fun printFun(elt) { print elt; }
>>> forEach(xs, printFun)
1
2
3

and also have expected indexing operators

>>> xs[0] = -xs[0]
-1
>>> xs
[-1, 2, 3]

crafting-interpreters-rs's People

Contributors

tdp2110 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

crafting-interpreters-rs's Issues

DRY up parser.rs

with macros?

In C++ I would have used templates and variadics ๐Ÿคท

implement store subscript

Like python:

>>> import dis
>>> def store(x, ix, v):
...     x[ix] = v
...
>>> dis.dis(store)
  2           0 LOAD_FAST                2 (v)
              2 LOAD_FAST                0 (x)
              4 LOAD_FAST                1 (ix)
              6 STORE_SUBSCR
              8 LOAD_CONST               0 (None)
             10 RETURN_VALUE

more info when debugger, repl launches

Eg, we could do something like Python

$ python3
Python 3.9.0 (default, Dec  2 2020, 10:34:08)
[Clang 12.0.0 (clang-1200.0.32.27)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 

error in treewalk interpreter

Consider f.lox

fun a() { b(); }
fun b() { c(); }
fun c() {
  c("too", "many");
}

a()

It should give a runtime error for the call to c on line 4, but this gives:

cargo run --release --quiet -- f.lox  --treewalk
Treewalk Interpreter Error: Use of undefined variable b at line=1,col=10.
Note: b was never declared.

don't require semicolon in repl

for example, in the repl, we get barked at for writing

>>> print "hi"

Parse error: Expected token Semicolon, but found token Eof at line=1,col=9: Expected ; after value

it wants us to write

>>> print "hi";
'hi'

It should be able to figure this out for itself and correct.

DRY up `interp.member.get()` calls in treewalk_interpreter.rs

We have many examples in treewalk_interpreter.rs that look like

            match interpreter.lox_functions.get(initializer_id) {
                Some(initializer) => Some(initializer.clone()),
                None => panic!(
                    "Internal interpreter error! couldn't find an initializer method with id {}.",
                    initializer_id
                ),
            },

We should pull these out into functions like

fn get_lox_function(&self, id: i64) -> &LoxFunction
{
  match self.lox_functions.get(id) {
    Some(func) => func,
    None => panic!(
                    "Internal interpreter error! couldn't find an initializer method with id {}.",
                    id
                ),
  }
}

fix gc

run LOX_GC_TRIGGER_SIZE=10 RUST_BACKTRACE=full cargo t to see that classes (or instances, or methods ...) broke the gc.

clean up repo structure

I'm pretty new to Rust, and the package structure works, but it could probably be more idiomatic.

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.