Skip to content

Commit

Permalink
Merge pull request #11 from Hirevo/feature/bytecode-compiler
Browse files Browse the repository at this point in the history
Added a bytecode-based SOM interpreter
  • Loading branch information
Hirevo authored Aug 21, 2020
2 parents aaf7eb1 + b82acd4 commit 2247a14
Show file tree
Hide file tree
Showing 64 changed files with 5,262 additions and 97 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/bench.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: build
args: --release -p som-interpreter
args: --release -p som-interpreter-ast -p som-interpreter-bc
- name: Install ReBench
run: |
pip install setuptools
Expand Down
9 changes: 7 additions & 2 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ jobs:
run_test_suite:
name: Run SOM Test Suite
runs-on: ubuntu-latest
strategy:
matrix:
interpreter:
- som-interpreter-ast
- som-interpreter-bc
steps:
- name: Checkout master branch
uses: actions/checkout@v2
Expand All @@ -24,10 +29,10 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: build
args: --release -p som-interpreter
args: --release -p ${{ matrix.interpreter }}
- name: Run test suite
run: |
./target/release/som-interpreter -c core-lib/Smalltalk core-lib/TestSuite -- TestHarness
./target/release/${{ matrix.interpreter }} -c core-lib/Smalltalk core-lib/TestSuite -- TestHarness
run_own_tests:
name: Run own tests
Expand Down
17 changes: 16 additions & 1 deletion Cargo.lock

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

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
[workspace]
members = [
"som-core",
"som-interpreter",
"som-interpreter-bc",
"som-interpreter-ast",
"som-lexer",
"som-parser-core",
"som-parser-symbols",
Expand Down
10 changes: 7 additions & 3 deletions rebench.conf
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,12 @@ benchmark_suites:
- Mandelbrot: {extra_args: 30}

executors:
som-rs:
som-rs-ast:
path: .
executable: ./target/release/som-interpreter-ast
som-rs-bc:
path: .
executable: ./target/release/som-interpreter
executable: ./target/release/som-interpreter-bc

# define the benchmarks to be executed for a re-executable benchmark run
experiments:
Expand All @@ -67,4 +70,5 @@ experiments:
- micro
- macro
executions:
- som-rs
- som-rs-ast
- som-rs-bc
139 changes: 75 additions & 64 deletions som-core/src/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,82 +3,75 @@ use std::fmt;
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Bytecode {
Halt = 0,
Dup = 1,
PushLocal = 2,
PushArgument = 3,
PushField = 4,
PushBlock = 5,
PushConstant = 6,
PushGlobal = 7,
Pop = 8,
PopLocal = 9,
PopArgument = 10,
PopField = 11,
Send = 12,
SuperSend = 13,
ReturnLocal = 14,
ReturnNonLocal = 15,
Halt,
Dup,
PushLocal(u8, u8),
PushArgument(u8, u8),
PushField(u8),
PushBlock(u8),
PushConstant(u8),
PushGlobal(u8),
Pop,
PopLocal(u8, u8),
PopArgument(u8, u8),
PopField(u8),
Send(u8),
SuperSend(u8),
ReturnLocal,
ReturnNonLocal,
}

impl Bytecode {
/// Get the instruction's name.
#[rustfmt::skip]
pub fn name(self) -> &'static str {
NAMES[self as usize]
// NAMES[self as usize]
match self {
Self::Halt => "HALT",
Self::Dup => "DUP",
Self::PushLocal(_, _) => "PUSH_LOCAL",
Self::PushArgument(_, _) => "PUSH_ARGUMENT",
Self::PushField(_) => "PUSH_FIELD",
Self::PushBlock(_) => "PUSH_BLOCK",
Self::PushConstant(_) => "PUSH_CONSTANT",
Self::PushGlobal(_) => "PUSH_GLOBAL",
Self::Pop => "POP",
Self::PopLocal(_, _) => "POP_LOCAL",
Self::PopArgument(_, _) => "POP_ARGUMENT",
Self::PopField(_) => "POP_FIELD",
Self::Send(_) => "SEND",
Self::SuperSend(_) => "SUPER_SEND",
Self::ReturnLocal => "RETURN_LOCAL",
Self::ReturnNonLocal => "RETURN_NON_LOCAL",
}
}

/// Get the instruction's name padded so that every padded names are of the same length.
#[rustfmt::skip]
pub fn padded_name(self) -> &'static str {
PADDED_NAMES[self as usize]
}

/// Get the number of bytes to read to process the instruction.
pub fn bytecode_len(self) -> usize {
// PADDED_NAMES[self as usize]
match self {
Bytecode::Halt => 1,
Bytecode::Dup => 1,
Bytecode::PushLocal => 3,
Bytecode::PushArgument => 3,
Bytecode::PushField => 2,
Bytecode::PushBlock => 2,
Bytecode::PushConstant => 2,
Bytecode::PushGlobal => 2,
Bytecode::Pop => 1,
Bytecode::PopLocal => 3,
Bytecode::PopArgument => 3,
Bytecode::PopField => 2,
Bytecode::Send => 2,
Bytecode::SuperSend => 2,
Bytecode::ReturnLocal => 1,
Bytecode::ReturnNonLocal => 1,
}
}

/// Attempt to convert a raw byte to an instruction.
pub fn from_byte(byte: u8) -> Option<Bytecode> {
match byte {
0 => Some(Bytecode::Halt),
1 => Some(Bytecode::Dup),
2 => Some(Bytecode::PushLocal),
3 => Some(Bytecode::PushArgument),
4 => Some(Bytecode::PushField),
5 => Some(Bytecode::PushBlock),
6 => Some(Bytecode::PushConstant),
7 => Some(Bytecode::PushGlobal),
8 => Some(Bytecode::Pop),
9 => Some(Bytecode::PopLocal),
10 => Some(Bytecode::PopArgument),
11 => Some(Bytecode::PopField),
12 => Some(Bytecode::Send),
13 => Some(Bytecode::SuperSend),
14 => Some(Bytecode::ReturnLocal),
15 => Some(Bytecode::ReturnNonLocal),
_ => None,
Self::Halt => "HALT ",
Self::Dup => "DUP ",
Self::PushLocal(_, _) => "PUSH_LOCAL ",
Self::PushArgument(_, _) => "PUSH_ARGUMENT ",
Self::PushField(_) => "PUSH_FIELD ",
Self::PushBlock(_) => "PUSH_BLOCK ",
Self::PushConstant(_) => "PUSH_CONSTANT ",
Self::PushGlobal(_) => "PUSH_GLOBAL ",
Self::Pop => "POP ",
Self::PopLocal(_, _) => "POP_LOCAL ",
Self::PopArgument(_, _) => "POP_ARGUMENT ",
Self::PopField(_) => "POP_FIELD ",
Self::Send(_) => "SEND ",
Self::SuperSend(_) => "SUPER_SEND ",
Self::ReturnLocal => "RETURN_LOCAL ",
Self::ReturnNonLocal => "RETURN_NON_LOCAL",
}
}
}

static NAMES: [&str; 16] = [
pub static NAMES: [&str; 16] = [
"HALT",
"DUP",
"PUSH_LOCAL",
Expand All @@ -97,7 +90,7 @@ static NAMES: [&str; 16] = [
"RETURN_NON_LOCAL",
];

static PADDED_NAMES: [&str; 16] = [
pub static PADDED_NAMES: [&str; 16] = [
"HALT ",
"DUP ",
"PUSH_LOCAL ",
Expand All @@ -117,7 +110,25 @@ static PADDED_NAMES: [&str; 16] = [
];

impl fmt::Display for Bytecode {
#[rustfmt::skip]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name())
match self {
Self::Halt => write!(f, "HALT"),
Self::Dup => write!(f, "DUP"),
Self::PushLocal(up_idx, idx) => write!(f, "PUSH_LOCAL {}, {}", up_idx, idx),
Self::PushArgument(up_idx, idx) => write!(f, "PUSH_ARGUMENT {}, {}", up_idx, idx),
Self::PushField(idx) => write!(f, "PUSH_FIELD {}", idx),
Self::PushBlock(idx) => write!(f, "PUSH_BLOCK {}", idx),
Self::PushConstant(idx) => write!(f, "PUSH_CONSTANT {}", idx),
Self::PushGlobal(idx) => write!(f, "PUSH_GLOBAL {}", idx),
Self::Pop => write!(f, "POP"),
Self::PopLocal(up_idx, idx) => write!(f, "POP_LOCAL {}, {}", up_idx, idx),
Self::PopArgument(up_idx, idx) => write!(f, "POP_ARGUMENT {}, {}", up_idx, idx),
Self::PopField(idx) => write!(f, "POP_FIELD {}", idx),
Self::Send(idx) => write!(f, "SEND {}", idx),
Self::SuperSend(idx) => write!(f, "SUPER_SEND {}", idx),
Self::ReturnLocal => write!(f, "RETURN_LOCAL", ),
Self::ReturnNonLocal => write!(f, "RETURN_NON_LOCAL", ),
}
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
[package]
name = "som-interpreter"
name = "som-interpreter-ast"
version = "0.1.0"
description = "An interpreter for the Simple Object Machine"
authors = ["Nicolas Polomack <[email protected]>"]
edition = "2018"
publish = false
license = "MIT OR Apache-2.0"

[lib]
path = "src/lib.rs"

[[bin]]
name = "som-interpreter"
path = "src/main.rs"

[dependencies]
# internal
som-core = { path = "../som-core", version = "0.1.0" }
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ use structopt::StructOpt;

mod shell;

use som_interpreter::invokable::Return;
use som_interpreter::universe::Universe;
use som_interpreter::value::Value;
use som_interpreter_ast::invokable::Return;
use som_interpreter_ast::universe::Universe;
use som_interpreter_ast::value::Value;

#[derive(Debug, Clone, PartialEq, StructOpt)]
#[structopt(about, author)]
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ use anyhow::Error;
use som_lexer::{Lexer, Token};
use som_parser::lang;

use som_interpreter::evaluate::Evaluate;
use som_interpreter::frame::FrameKind;
use som_interpreter::invokable::Return;
use som_interpreter::universe::Universe;
use som_interpreter::value::Value;
use som_interpreter_ast::evaluate::Evaluate;
use som_interpreter_ast::frame::FrameKind;
use som_interpreter_ast::invokable::Return;
use som_interpreter_ast::universe::Universe;
use som_interpreter_ast::value::Value;

/// Launches an interactive Read-Eval-Print-Loop within the given universe.
pub fn interactive(universe: &mut Universe, verbose: bool) -> Result<(), Error> {
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::path::PathBuf;

use som_interpreter::evaluate::Evaluate;
use som_interpreter::frame::FrameKind;
use som_interpreter::invokable::Return;
use som_interpreter::universe::Universe;
use som_interpreter::value::Value;
use som_interpreter_ast::evaluate::Evaluate;
use som_interpreter_ast::frame::FrameKind;
use som_interpreter_ast::invokable::Return;
use som_interpreter_ast::universe::Universe;
use som_interpreter_ast::value::Value;
use som_lexer::{Lexer, Token};

use som_parser::lang;
Expand Down
31 changes: 31 additions & 0 deletions som-interpreter-bc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[package]
name = "som-interpreter-bc"
version = "0.1.0"
description = "A bytecode compiler for the Simple Object Machine"
authors = ["Nicolas Polomack <[email protected]>"]
edition = "2018"
publish = false
license = "MIT OR Apache-2.0"

[dependencies]
# internal
som-core = { path = "../som-core", version = "0.1.0" }
som-lexer = { path = "../som-lexer", version = "0.1.0" }
som-parser = { package = "som-parser-symbols", path = "../som-parser-symbols", version = "0.1.0" }
# som-parser = { package = "som-parser-text", path = "../som-parser-text", version = "0.1.0" }

# CLI interface
structopt = "0.3.14"

# error handling
anyhow = "1.0.31"

# consistently-ordered hashmaps
indexmap = "1.4.0"

# big integers
num-bigint = "0.2.6"
num-traits = "0.2.11"

# random numbers
rand = "0.7.3"
8 changes: 8 additions & 0 deletions som-interpreter-bc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
The SOM Interpreter
===================

This is the interpreter for the Simple Object Machine.

It is AST-based, in that it works by recursively traversing and evaluating nodes from the Abstract Syntax Tree from **`som-core`**.

Resources are managed and tracked through reference-counting (using Rust's **`Rc`**/**`Weak`** types).
Loading

0 comments on commit 2247a14

Please sign in to comment.