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 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(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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(),
|
|
||||||
next_local: 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.
|
/// Gets the constant data that is interned in this compile session.
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user