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:
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user