Skip to content

Commit

Permalink
Merge pull request #1 from raaymax/compiler
Browse files Browse the repository at this point in the history
feat: compiler and virtual machine
  • Loading branch information
Mateusz Russak authored Dec 3, 2023
2 parents 081523a + 10b3ebb commit 3e0cca3
Show file tree
Hide file tree
Showing 13 changed files with 1,049 additions and 0 deletions.
150 changes: 150 additions & 0 deletions Cargo.lock

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

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ members = [
"crates/lexer",
"crates/parser",
"crates/interpreter",
"crates/compiler",
"bins/lsp",
"bins/cli",
"tree-sitter-loom",
Expand All @@ -19,5 +20,8 @@ members = [
lexer = { path = "./crates/lexer" }
parser = { path = "./crates/parser" }
interpreter = { path = "./crates/interpreter" }
compiler = { path = "./crates/compiler" }
vm = { path = "./crates/vm" }
cli = { path = "./bins/cli" }
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

20 changes: 20 additions & 0 deletions crates/compiler/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "compiler"
version = "0.1.0"
edition = "2021"

[lib]
tests = true
path = "src/lib.rs"
crate-type = ["lib"]

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

[dependencies]
enum-display = "0.1.3"
lexer = { path = "../lexer" }
vm = { path = "../vm" }
num = "0.4.1"
num-derive = "0.4.1"
num-traits = "0.2.17"
parser = { path = "../parser" }
125 changes: 125 additions & 0 deletions crates/compiler/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
use std::{fmt::{Display, Formatter}};

use lexer::PError;
use parser::{Node, Op, Value};
use vm::{Instr, Instrs, OpCode};


struct Code {
code: Vec<Instr>,
}

impl Code {
pub fn new() -> Code {
Code {
code: Vec::new(),
}
}
pub fn push(&mut self, inst: Instr) {
self.code.push(inst);
}
pub fn to_bytes(&self) -> Vec<u8> {
Instrs(self.code.iter().map(|c| c.byte_description()).collect()).into()
}
}

struct Mem {
data: Vec<u8>,
memptr: usize,
}

impl Mem {
pub fn new() -> Mem {
Mem {
data: Vec::new(),
memptr: 0,
}
}
pub fn write(&mut self, val: u32) -> usize {
let location = self.memptr;
for i in 0..4 {
self.data[self.memptr + i] = (val >> (i * 8)) as u8;

}
self.memptr += 4;
location
}

pub fn to_bytes(&self) -> Vec<u8> {
self.data.clone()
}
}
impl Display for Mem {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Mem: {:?}", self.data)
}
}

pub fn compile_node(node: &Node, mut consts: &mut Mem, inst: &mut Code) -> Result<(), PError> {
match node.op {
Op::Add => {
compile_node(&node.children[0], &mut consts, inst)?;
inst.push(Instr::Mov(2, 0));
compile_node(&node.children[1], &mut consts, inst)?;
inst.push(Instr::Mov(1, 0));
inst.push(Instr::Add(0,1,2));
},
Op::Sub => {
compile_node(&node.children[0], &mut consts, inst)?;
inst.push(Instr::Mov(2, 0));
compile_node(&node.children[1], &mut consts, inst)?;
inst.push(Instr::Mov(1, 0));
inst.push(Instr::Sub(0,2,1));
},
Op::Value => {
match &node.value {
Some(Value::Number(0)) => inst.push(Instr::Load0(0)),
Some(Value::Number(1)) => inst.push(Instr::Load1(0)),
Some(Value::Number(val)) => {
inst.push(Instr::Load(0, *val as u16));
},
Some(..) => {
panic!("Unknown value: {}", node);
},
None => panic!("No value"),
}
},
Op::Scope | Op::Paren => {
for child in &node.children {
println!("child: {}", child.op);
compile_node(child, &mut consts, inst)?;
}
inst.push(Instr::Exit);
},
_ => {
panic!("Unknown op: {} {}", node, node.op);
}
}
Ok(())
}

pub fn compile(node: &Node) -> Result<Vec<u8>, PError> {
let mut inst = Code::new();
let mut consts = Mem::new();
compile_node(node, &mut consts, &mut inst)?;
let code = inst.to_bytes();
Ok(code)
}

#[cfg(test)]
mod tests {
use parser::Node;
use lexer::Location;

use super::*;

#[test]
fn compile_simple() {
let mut node = Node::new(Op::Scope, Location::Eof);
node.add(Node::new(Op::Value, Location::Eof).set_value(1.into()));
let bytes = compile(&node).unwrap();
assert_eq!(bytes, vec![OpCode::Load1.into(), 0, OpCode::Exit.into()]);
}

}

Loading

0 comments on commit 3e0cca3

Please sign in to comment.