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 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(())
}

View File

@@ -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()

View File

@@ -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<Sym, Local>,
@@ -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<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.

View File

@@ -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()
}

View File

@@ -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<Stmt>,
}
pub type Body = Vec<Stmt>;
//
// impl Accept for Body
@@ -18,8 +15,7 @@ impl<V: Visit> Accept<V> for Body {
impl<V: Visit<Out=()>> DefaultAccept<V> for Body {
fn default_accept(&self, visitor: &mut V) -> V::Out {
self.body
.iter()
self.iter()
.for_each(|stmt| visitor.visit_stmt(stmt));
}
}