Skip to content

Commit

Permalink
Initial Monkey formatter (#10)
Browse files Browse the repository at this point in the history
# Pull Request

Initial implementation of the monkey formatter.

## Description

In this PR a basic Monkey formatter is implemented. The formatter itself
is really simple and there is no customization. The idea was to have an
initial implementation that could be later improved. Some modifications
to the structure of the project have also been made.

## Changes Made

- Creation of a formatter crate.
- Basic formatter
- Refactoring of the `precedence_of` function on the `parser` module
- Renamed `repl::Cli` to `repl::ReplCli`, to avoid any sort of confusion
with `formatter::FormatterCli`
- Fixed the `fibonacci_it.monkey` example and the `array_append` bench.
- Add more monkey examples.

## Related Issue <!-- Optional -->

<!-- Link to the related issue, e.g., "Closes #123" or "Fixes #456" -->

Closes #3 

## Checklist

- [x] I have self-reviewed my code
- [x] Code follows project's style guidelines
- [x] Tests added and passing
- [x] Documentation updated (if needed)
  • Loading branch information
Yag000 authored Aug 10, 2023
2 parents 8ae435e + 8ae10ae commit a0bd47a
Show file tree
Hide file tree
Showing 25 changed files with 1,528 additions and 71 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,19 @@ compiler = { path = "./crates/compiler" }
vm = { path = "./crates/vm" }
repl = { path = "./crates/repl" }
object = { path = "./crates/object" }
formatter = { path = "./crates/formatter" }

# external crates
clap = "4.3.11"
clap_derive = "4.3.2"
criterion = "0.5.1"
chrono = "0.4.26"


[[bench]]
name = "formatter_bench"
harness = false

[[bench]]
name = "fibonacci_bench"
harness = false
Expand All @@ -42,3 +48,5 @@ harness = false
name = "array_bench"
harness = false



23 changes: 18 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,23 @@ The Monkey language is a language created by Thorsten Ball for his book [Writing

Monkey-rs is an implementation of the Monkey language in Rust. It is based on the books [Writing an Interpreter in Go](https://interpreterbook.com/) and [Writing a Compiler in Go](https://compilerbook.com/).

This implemenattion is still in development. For now an interpreter and a compiler are fully implemented, allowing to run a REPL and to run Monkey files (`.monkey` extension).
This implementation is still in development. For now an interpreter and a compiler are fully implemented, allowing to run a REPL and to run Monkey files (`.monkey` extension).
There are some issues that I want to fix before I can call this implementation complete.

### REPL

To start the REPL, run the following command:

```bash
cargo run --release
cargo run --release --bin monkey
```

### File interpreter

To run a Monkey file, run the following command:

```bash
cargo run --release -- <path-to-file>
cargo run --release --bin monkey -- <path-to-file>
```

### Other modes
Expand All @@ -40,15 +40,28 @@ Where `<mode>` can be `compiler`, `parser`, `lexer` or `interpreter`.
Example:

```bash
cargo run --release -- <path-to-file> --mode compiler
cargo run --release --bin monkey -- <path-to-file> --mode compiler
```

### Formatter

A monkey formatter is also available, with the binary `monkeyfmt`. I will format any correct piece of monkey code.
To use it you only need to run the following command:

```bash
cargo run --release --bin monkeyfmt -- <path-to-file>
```

Adding the `-r` flag after the file name will replace the contents of the file with the
formatted code. If the flag is not activated, the formatted code will be printed to
`stdout`.

### Help

To see the help, run the following command:

```bash
cargo run --release -- --help
cargo run --release --bin monkey -- --help
```

## Monkey syntax
Expand Down
11 changes: 5 additions & 6 deletions benches/array_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,16 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion};
use monkey::{compile_program, execute_interpreter, execute_vm, parse_program};

const ARRAY_APPEND: &str = r#"
let push_n = fn(arr, n) {
let push_n = fn (arr, n) {
if (n < 0) {
arr
} else{
let new_arr = arr.push(n):
push_n(new_arr, n - 1);
} else {
let new_arr = push(arr, n);
push_n(new_arr, n - 1)
}
};
let a = [];
push_n(a, 100);
push_n(a, 500);
"#;

pub fn array_append_compiler_benchmark(c: &mut Criterion) {
Expand Down
201 changes: 201 additions & 0 deletions benches/formatter_bench.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};

use formatter::formatter::Formatter;

pub fn long_formatter_benchmark(c: &mut Criterion) {
let input = r#"
let fibonacci_it = fn (x) {
if (x < 2) {
return x;
}
let iter = fn (i, table) {
if (i > x) {
return last(table);
} else {
let new_table = push(table, table[i - 1] + table[i - 2]);
return iter(i + 1, new_table);
}
};
return iter(2, [0, 1]);
};
let fib = fibonacci_it(20);
puts (fib);
let fibonacci = fn (x) {
if (x < 2) {
x
} else {
fibonacci(x - 1) + fibonacci(x - 2)
}
};
puts(fibonacci(3));
let filter = fn (arr, f) {
let iter = fn (arr, accumulated) {
if (len(arr) == 0) {
accumulated
} else {
let head = first(arr);
let tail = rest(arr);
if (f(head)) {
iter(tail, push(accumulated, head))
} else {
iter(tail, accumulated)
}
}
};
iter(arr, [])
};
let a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 100];
let is_even = fn (x) {
x / 2 * 2 == x
};
filter(a, is_even);
let foldl = fn (arr, initial , f) {
let iter = fn (arr, result) {
if (len(arr) == 0) {
result;
} else {
iter(rest(arr), f(result, first(arr)))
}
};
iter(arr, initial)
};
let a = [1, 2, 3, 4];
let sum = fn (x, y) {
x + y
};
foldl(a, 0, sum);
let foldr = fn(arr, initial, f) {
let iter = fn(arr, result) {
if (len(arr) == 0) {
result
} else {
iter(rest(arr), f(first(arr), result));
}
};
iter(arr, initial);
};
let a = [1, 2, 3, 4];
let sum = fn(x, y) { x + y };
foldr(a, 0, sum);
let input = r;
"
let map = fn(arr, f) {
let iter = fn(arr, accumulated) {
if (len(arr) == 0) {
accumulated
} else {
iter(rest(arr), push(accumulated, f(first(arr))));
}
};
iter(arr, []);
};
let a = [1, 2, 3, 4];
let double = fn(x) { x * 2 };
map(a, double);
";
~/Projects/monkey-rs 3-Formatter *2 !1 ?1 ❯ cat monkey_examples/* 17:00:36
let fibonacci_it = fn (x) {
if (x < 2) {
return x;
}
let iter = fn (i, table) {
if (i > x) {
return last(table);
} else {
let new_table = push(table, table[i - 1] + table[i - 2]);
return iter(i + 1, new_table);
}
};
return iter(2, [0, 1]);
};
let fib = fibonacci_it(20);
puts(fib);
let fibonacci = fn (x) {
if (x < 2) {
x
} else {
fibonacci(x - 1) + fibonacci(x - 2)
}
};
puts(fibonacci(30));
let filter = fn (arr, f) {
let iter = fn (arr, accumulated) {
if (len(arr) == 0) {
accumulated
} else {
let head = first(arr);
let tail = rest(arr);
if (f(head)) {
iter(tail, push(accumulated, head))
} else {
iter(tail, accumulated)
}
}
};
iter(arr, [])
};
let a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 100];
let is_even = fn (x) {
x / 2 * 2 == x
};
filter(a, is_even);
let foldl = fn (arr, initial, f) {
let iter = fn (arr, result) {
if (len(arr) == 0) {
result
} else {
iter(rest(arr), f(result, first(arr)))
}
};
iter(arr, initial)
};
let a = [1, 2, 3, 4];
let sum = fn (x, y) {
x + y
};
foldl(a, 0, sum);
let foldr = fn(arr, initial, f) {
let iter = fn(arr, result) {
if (len(arr) == 0) {
result
} else {
iter(rest(arr), f(first(arr), result));
}
};
iter(arr, initial);
};
let a = [1, 2, 3, 4];
let sum = fn(x, y) { x + y };
foldr(a, 0, sum);
let map = fn(arr, f) {let iter = fn(arr, accumulated) {
if (len(arr) == 0) {
accumulated
} else {
iter(rest(arr), push(accumulated, f(first(arr))));
}
};
iter(arr, []);
};
let a = [1, 2, 3, 4];
let double = fn(x) { x * 2 };
map(a, double);
"#;

c.bench_function("Long format", |b| {
b.iter(|| Formatter::format(black_box(input)))
});
}

criterion_group!(benches, long_formatter_benchmark);
criterion_main!(benches);
16 changes: 16 additions & 0 deletions crates/formatter/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "formatter"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

lexer = { path = "../lexer" }
parser = { path = "../parser" }


# External crates
clap = "4.3.11"
clap_derive = "4.3.2"
19 changes: 19 additions & 0 deletions crates/formatter/ressources/test_formatting.monkey
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
let filter = fn(arr, f) {
let iter = fn(arr, accumulated) {
if (len(arr)==0) {
accumulated
} else {
let head = first(arr);
let tail =rest(arr);
if (f(head)) {
iter(tail, push(accumulated, head));
} else {
iter(tail, accumulated);
}
}
};
iter(arr, []);
};
let a = [1, 2, 3, 4,5,6,7,8,9,11,100];
let is_even = fn(x) { (x/2)*2 == x };
filter(a, is_even);
Loading

0 comments on commit a0bd47a

Please sign in to comment.