From e72cbe2b8c152cd63abc044ce42cbfa128dc8ff1 Mon Sep 17 00:00:00 2001 From: Alek Ratzloff Date: Wed, 16 Sep 2020 18:01:40 -0700 Subject: [PATCH] Base compilation of some kind of file to a list of instructions seems to work(!) I'm able to compile some basic expressions into instructions using the `not` binary. Big first step, now we need to introduce branches and loops to the syntax. Signed-off-by: Alek Ratzloff --- src/bin/not.rs | 12 +++++++++--- src/compile/basic_block.rs | 17 ++++++++++++++++- src/compile/mod.rs | 19 ++++++++++++------- src/compile/thunk.rs | 10 ++++++++-- src/syn/ast.rs | 8 ++------ 5 files changed, 47 insertions(+), 19 deletions(-) diff --git a/src/bin/not.rs b/src/bin/not.rs index 67bab79..dbb3934 100644 --- a/src/bin/not.rs +++ b/src/bin/not.rs @@ -1,4 +1,4 @@ -use not_python::syn::ast; +use not_python::{syn::ast, compile::Compile}; use std::{fs, path::PathBuf}; use structopt::StructOpt; @@ -31,8 +31,14 @@ fn main() -> Result<()> { } return Err("errors reported, exiting".into()); } - }; - println!("{:#?}", ast); + }.unwrap(); + //println!("{:#?}", ast); + + let mut compile = Compile::new(); + let (inst, const_pool) = compile.compile(&ast)?; + + println!("{:#?}", inst); + println!("{:#?}", const_pool); Ok(()) } diff --git a/src/compile/basic_block.rs b/src/compile/basic_block.rs index 00489c2..1ed69e7 100644 --- a/src/compile/basic_block.rs +++ b/src/compile/basic_block.rs @@ -69,7 +69,10 @@ impl BasicBlockList { body.push(Inst::Jump(addr)); } } - BasicBlock::Branch { block_true, block_false } => { + BasicBlock::Branch { + block_true, + block_false, + } => { // insert conditional jump to true statement, and unconditional jump to false // statement let addr_true = addr_rev[&block_true]; @@ -96,10 +99,22 @@ impl BasicBlockList { let mut blocks = Vec::with_capacity(self.len()); let mut entry_map = BTreeMap::new(); // first pass: add blocks to the "blocks" list, and map block indices + let mut last_block_index = 0; for (new_index, (index, block)) in self.blocks.into_iter().enumerate() { + // search for the largest block index referred to in here - that is the last block + match block { + BasicBlock::Block { exit, .. } => last_block_index = exit.max(last_block_index), + BasicBlock::Branch { + block_true, + block_false, + } => last_block_index = block_true.max(block_false.max(last_block_index)), + } blocks.push(block); entry_map.insert(index, new_index); } + // this inserts a "dummy" mapping for the last block index because it will point out of bounds + let last_index = entry_map.len(); + entry_map.insert(dbg!(last_block_index), dbg!(last_index)); // second pass: update blocks in-place with their newly mapped addresses blocks .into_iter() diff --git a/src/compile/mod.rs b/src/compile/mod.rs index a33963e..6f2cc21 100644 --- a/src/compile/mod.rs +++ b/src/compile/mod.rs @@ -3,9 +3,10 @@ pub mod error; mod locals; pub mod thunk; -use crate::{syn::ast::Body, obj::prelude::*, vm::consts::*}; +use crate::{syn::ast::Body, obj::prelude::*, vm::{consts::*, inst::Inst}}; use std::collections::{BTreeMap, HashMap}; +#[derive(Default)] pub struct Compile { const_data: ConstData, globals: BTreeMap, @@ -16,12 +17,16 @@ pub struct Compile { impl Compile { /// Creates a new compiler using the given text. pub fn new() -> Self { - Compile { - const_data: Default::default(), - globals: Default::default(), - locals: Default::default(), - next_local: Default::default(), - } + Default::default() + } + + /// Compiles the given AST body. + pub fn compile<'c>(&'c mut self, body: &Body) -> error::Result<(Vec, &'c ConstPool)> { + let main = thunk::CompileBody::new(self) + .compile(body)? + .flatten() + .to_vec(); + Ok((main, &self.const_data.const_pool)) } /// Gets the constant data that is interned in this compile session. diff --git a/src/compile/thunk.rs b/src/compile/thunk.rs index 1fbc367..d83f625 100644 --- a/src/compile/thunk.rs +++ b/src/compile/thunk.rs @@ -234,7 +234,7 @@ impl Visit for CompileBody<'_> { self.compile.collect_locals(body); let mut thunk = Thunk::Nop; - for stmt in body.body.iter() { + for stmt in body.iter() { thunk.push_thunk(stmt.accept(self)?); } @@ -347,7 +347,13 @@ impl Visit for CompileBody<'_> { let thunk = match atom { Atom::Ident(ident) => { let sym = global_sym(ident.to_string()); - let local = self.compile.lookup_scope(sym).unwrap(); + let local = if let Some(local) = self.compile.lookup_scope(sym) { + local + } else { + // create a global that gets looked up instead, since nothing with this name + // has been declared/assigned in this scope + self.compile.create_global(sym) + }; // get local Inst::PushLocal(local).into() } diff --git a/src/syn/ast.rs b/src/syn/ast.rs index dd5ab5b..6cd90a0 100644 --- a/src/syn/ast.rs +++ b/src/syn/ast.rs @@ -2,10 +2,7 @@ use crate::syn::visit::*; // TODO : add locations to parsed items -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Body { - pub body: Vec, -} +pub type Body = Vec; // // impl Accept for Body @@ -18,8 +15,7 @@ impl Accept for Body { impl> DefaultAccept for Body { fn default_accept(&self, visitor: &mut V) -> V::Out { - self.body - .iter() + self.iter() .for_each(|stmt| visitor.visit_stmt(stmt)); } }