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 <alekratz@gmail.com>
This commit is contained in:
2020-09-16 18:01:40 -07:00
parent 61ac00ae39
commit e72cbe2b8c
5 changed files with 47 additions and 19 deletions

View File

@@ -1,4 +1,4 @@
use not_python::syn::ast; use not_python::{syn::ast, compile::Compile};
use std::{fs, path::PathBuf}; use std::{fs, path::PathBuf};
use structopt::StructOpt; use structopt::StructOpt;
@@ -31,8 +31,14 @@ fn main() -> Result<()> {
} }
return Err("errors reported, exiting".into()); return Err("errors reported, exiting".into());
} }
}; }.unwrap();
println!("{:#?}", ast); //println!("{:#?}", ast);
let mut compile = Compile::new();
let (inst, const_pool) = compile.compile(&ast)?;
println!("{:#?}", inst);
println!("{:#?}", const_pool);
Ok(()) Ok(())
} }

View File

@@ -69,7 +69,10 @@ impl BasicBlockList {
body.push(Inst::Jump(addr)); 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 // insert conditional jump to true statement, and unconditional jump to false
// statement // statement
let addr_true = addr_rev[&block_true]; let addr_true = addr_rev[&block_true];
@@ -96,10 +99,22 @@ impl BasicBlockList {
let mut blocks = Vec::with_capacity(self.len()); let mut blocks = Vec::with_capacity(self.len());
let mut entry_map = BTreeMap::new(); let mut entry_map = BTreeMap::new();
// first pass: add blocks to the "blocks" list, and map block indices // 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() { 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); blocks.push(block);
entry_map.insert(index, new_index); 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 // second pass: update blocks in-place with their newly mapped addresses
blocks blocks
.into_iter() .into_iter()

View File

@@ -3,9 +3,10 @@ pub mod error;
mod locals; mod locals;
pub mod thunk; 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}; use std::collections::{BTreeMap, HashMap};
#[derive(Default)]
pub struct Compile { pub struct Compile {
const_data: ConstData, const_data: ConstData,
globals: BTreeMap<Sym, Local>, globals: BTreeMap<Sym, Local>,
@@ -16,12 +17,16 @@ pub struct Compile {
impl Compile { impl Compile {
/// Creates a new compiler using the given text. /// Creates a new compiler using the given text.
pub fn new() -> Self { pub fn new() -> Self {
Compile { Default::default()
const_data: Default::default(), }
globals: Default::default(),
locals: Default::default(), /// Compiles the given AST body.
next_local: Default::default(), pub fn compile<'c>(&'c mut self, body: &Body) -> error::Result<(Vec<Inst>, &'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. /// Gets the constant data that is interned in this compile session.

View File

@@ -234,7 +234,7 @@ impl Visit for CompileBody<'_> {
self.compile.collect_locals(body); self.compile.collect_locals(body);
let mut thunk = Thunk::Nop; let mut thunk = Thunk::Nop;
for stmt in body.body.iter() { for stmt in body.iter() {
thunk.push_thunk(stmt.accept(self)?); thunk.push_thunk(stmt.accept(self)?);
} }
@@ -347,7 +347,13 @@ impl Visit for CompileBody<'_> {
let thunk = match atom { let thunk = match atom {
Atom::Ident(ident) => { Atom::Ident(ident) => {
let sym = global_sym(ident.to_string()); 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 // get local
Inst::PushLocal(local).into() Inst::PushLocal(local).into()
} }

View File

@@ -2,10 +2,7 @@ use crate::syn::visit::*;
// TODO : add locations to parsed items // TODO : add locations to parsed items
#[derive(Debug, Clone, PartialEq, Eq)] pub type Body = Vec<Stmt>;
pub struct Body {
pub body: Vec<Stmt>,
}
// //
// impl Accept for Body // impl Accept for Body
@@ -18,8 +15,7 @@ impl<V: Visit> Accept<V> for Body {
impl<V: Visit<Out=()>> DefaultAccept<V> for Body { impl<V: Visit<Out=()>> DefaultAccept<V> for Body {
fn default_accept(&self, visitor: &mut V) -> V::Out { fn default_accept(&self, visitor: &mut V) -> V::Out {
self.body self.iter()
.iter()
.for_each(|stmt| visitor.visit_stmt(stmt)); .for_each(|stmt| visitor.visit_stmt(stmt));
} }
} }