From 8dc89f715340a1a4ec9d92f6b51dc451113da812 Mon Sep 17 00:00:00 2001 From: Alek Ratzloff Date: Tue, 19 May 2020 15:26:38 -0400 Subject: [PATCH] Add a lot of new stuff to the compile mod * compile::sym is now compile::name * add basic block structure * add visitor pattern * some other minor things (e.g. syn::ast::prelude) Signed-off-by: Alek Ratzloff --- src/compile/block.rs | 6 ++ src/compile/error.rs | 9 +++ src/compile/ir.rs | 59 ++++++++++++++++ src/compile/mod.rs | 39 +++++++---- src/compile/name.rs | 161 +++++++++++++++++++++++++++++++++++++++++++ src/compile/sym.rs | 16 ----- src/compile/visit.rs | 29 ++++++++ src/main.rs | 13 +++- src/syn/ast.rs | 15 ++++ 9 files changed, 316 insertions(+), 31 deletions(-) create mode 100644 src/compile/block.rs create mode 100644 src/compile/error.rs create mode 100644 src/compile/ir.rs create mode 100644 src/compile/name.rs delete mode 100644 src/compile/sym.rs create mode 100644 src/compile/visit.rs diff --git a/src/compile/block.rs b/src/compile/block.rs new file mode 100644 index 0000000..827a882 --- /dev/null +++ b/src/compile/block.rs @@ -0,0 +1,6 @@ +use crate::compile::ir::Body; + +// basic block +pub enum Block { + Body(Body), +} diff --git a/src/compile/error.rs b/src/compile/error.rs new file mode 100644 index 0000000..506bb5e --- /dev/null +++ b/src/compile/error.rs @@ -0,0 +1,9 @@ +use snafu::Snafu; + +#[derive(Debug, Snafu)] +pub enum Error { + //#[snafu(display("illegal attr key"))] + +} + +pub type Result = std::result::Result; diff --git a/src/compile/ir.rs b/src/compile/ir.rs new file mode 100644 index 0000000..1ac3f76 --- /dev/null +++ b/src/compile/ir.rs @@ -0,0 +1,59 @@ +use crate::{ + compile::Ctx, + obj::Sym, + syn::{ast, span::*}, +}; + +pub type Body = Vec; + +#[derive(Debug, Clone)] +pub enum Stmt { + Eval(Expr), + Assign(Lhs, Expr), +} + +#[derive(Debug, Clone)] +pub enum Lhs { + Sym(Sym), + Complex(Expr), +} + +#[derive(Debug, Clone)] +pub enum Expr { + Call(Box, Vec), + Base(BaseExpr), +} + +#[derive(Debug, Clone)] +pub enum BaseExprKind { + Num(i64), + Str(String), + Sym(Sym), + Ident(String), +} + +#[derive(Debug, Clone)] +pub struct BaseExpr { + pub kind: BaseExprKind, + pub span: Span, +} + +// FromAst and IntoAst are just so we can use .into_ast(ctx, text) +// some impls may not need ctx &mut ref - but probably needed for symbol resolution + +pub trait FromAst { + fn from_ast(other: A, ctx: &mut Ctx, text: &str) -> Self; +} + +pub trait IntoIr { + fn into_ir(self, ctx: &mut Ctx, text: &str) -> I; +} + +impl IntoIr for A +where + I: FromAst, +{ + fn into_ir(self, ctx: &mut Ctx, text: &str) -> I { + FromAst::from_ast(self, ctx, text) + } +} diff --git a/src/compile/mod.rs b/src/compile/mod.rs index e73a458..4c93e6f 100644 --- a/src/compile/mod.rs +++ b/src/compile/mod.rs @@ -1,30 +1,41 @@ -pub mod sym; +pub mod block; +pub mod error; +pub mod ir; +pub mod name; +pub mod visit; use crate::{ syn::ast::Stmt, - compile::sym::SymStack, + compile::name::NameStack, }; -pub trait Pass { - type Out; - fn pass(&self, ctx: &mut Ctx) -> Self::Out; -} - // * Desugar // * Collect names as symbols // * Create basic blocks -pub struct Ctx { - sym_stack: SymStack, +pub struct Ctx<'t> { + text: &'t str, + name_stack: NameStack, } -impl Ctx { - pub fn sym_stack(&self) -> &SymStack { - &self.sym_stack +impl<'t> Ctx<'t> { + pub fn new(text: &'t str) -> Self { + Ctx { + text, + name_stack: NameStack::new(), + } } - pub fn sym_stack_mut(&mut self) -> &mut SymStack { - &mut self.sym_stack + pub fn text(&self) -> &'t str { + self.text + } + + pub fn name_stack(&self) -> &NameStack { + &self.name_stack + } + + pub fn name_stack_mut(&mut self) -> &mut NameStack { + &mut self.name_stack } } diff --git a/src/compile/name.rs b/src/compile/name.rs new file mode 100644 index 0000000..4b1ca60 --- /dev/null +++ b/src/compile/name.rs @@ -0,0 +1,161 @@ +use crate::{ + compile::{visit::*, Ctx}, + syn::{ast::prelude::*, op::BinOp, span::*}, +}; +use std::collections::HashMap; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct NameId(usize); + +impl NameId { + pub fn new(id: usize) -> Self { + NameId(id) + } + + pub fn id(&self) -> usize { + self.0 + } +} + +pub struct NameStack { + next_sym: usize, + stack: Vec>, +} + +impl NameStack { + pub fn new() -> Self { + NameStack { + next_sym: 0, + stack: vec![Default::default()], + } + } + + pub fn push(&mut self, syms: HashMap) { + self.stack.push(syms); + } + + pub fn push_default(&mut self) { + self.push(Default::default()); + } + + pub fn pop(&mut self) -> Option> { + self.stack.pop() + } + + pub fn add(&mut self, name: String) -> NameId { + let next_sym = NameId::new(self.next_sym); + let sym = *self.locals_mut().entry(name).or_insert(next_sym); + if sym.id() == self.next_sym { + self.next_sym += 1; + } + sym + } + + /// Searches the top level of the symbol stack for the symbol with the supplied name. + pub fn get_local(&self, name: &str) -> Option { + self.locals().get(name).copied() + } + + /// Searches the stack from top to bottom for the symbol with the given name. + pub fn get_scoped(&self, name: &str) -> Option { + self.stack + .iter() + .rev() + .filter_map(|locals| locals.get(name)) + .next() + .copied() + } + + pub fn root(&self) -> &HashMap { + self.stack.first().expect("no root name map") + } + + pub fn root_mut(&mut self) -> &mut HashMap { + self.stack.first_mut().expect("no root name map") + } + + pub fn locals(&self) -> &HashMap { + self.stack.last().expect("no local name map") + } + + pub fn locals_mut(&mut self) -> &mut HashMap { + self.stack.last_mut().expect("no local name map") + } +} + +/// Collect local names and push them to the top layer of the name stack. +pub struct CollectNames<'c, 't: 'c> { + ctx: &'c mut Ctx<'t>, +} + +impl<'c, 't: 'c> CollectNames<'c, 't> { + pub fn new(ctx: &'c mut Ctx<'t>) -> Self { + CollectNames { ctx } + } + + pub fn collect(&mut self, stmts: &Vec) { + for stmt in stmts.iter() { + self.visit_stmt(stmt); + } + } + + fn visit_base_expr(&mut self, expr: &BaseExpr) { + match &expr.kind { + BaseExprKind::Ident => { + let name = expr.text_at(self.ctx.text()).to_string(); + self.ctx.name_stack_mut().add(name); + } + BaseExprKind::List(l) | BaseExprKind::Tuple(l) => { + l.iter().for_each(|expr| self.visit_expr(expr)); + } + BaseExprKind::Object(o) => { + o.iter().for_each(|(key, value)| { + self.visit_expr(key); + self.visit_expr(value); + }); + } + _ => { /* no-op */ } + } + } +} + +impl Visit for CollectNames<'_, '_> { + type Out = (); + + fn visit_expr(&mut self, expr: &Expr) -> Self::Out { + match expr { + Expr::Bin(b) => { + self.visit_expr(&b.lhs); + // don't descend into dot-expressions - these are not names, but symbols + if b.op != BinOp::Dot { + self.visit_expr(&b.rhs); + } + } + Expr::Un(u) => { + self.visit_expr(&u.expr); + } + Expr::FunCall(f) => { + self.visit_expr(&f.expr); + f.args.iter().for_each(|expr| self.visit_expr(expr)); + } + Expr::Index(i) => { + self.visit_expr(&i.expr); + self.visit_expr(&i.index); + } + Expr::Fun(f) => { /* no-op */ } + Expr::Base(b) => self.visit_base_expr(b), + } + } + + fn visit_stmt(&mut self, stmt: &Stmt) -> Self::Out { + match stmt { + Stmt::Assign(AssignStmt { lhs, rhs, .. }) => { + self.visit_expr(lhs); + self.visit_expr(rhs); + } + Stmt::Expr(expr) => { + self.visit_expr(expr); + } + } + } +} diff --git a/src/compile/sym.rs b/src/compile/sym.rs deleted file mode 100644 index f30e01c..0000000 --- a/src/compile/sym.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::obj::Sym; -use std::collections::HashMap; - -pub struct SymStack { - syms: HashMap, - stack: Vec>, -} - -impl SymStack { - pub fn new() -> Self { - SymStack { - syms: Default::default(), - stack: vec![Default::default()], - } - } -} diff --git a/src/compile/visit.rs b/src/compile/visit.rs new file mode 100644 index 0000000..b1ceb5b --- /dev/null +++ b/src/compile/visit.rs @@ -0,0 +1,29 @@ +use crate::syn::ast::{Stmt, Expr}; + +pub trait Visit { + type Out; + fn visit>(&mut self, acceptor: &A) -> Self::Out + where Self: Sized + { + acceptor.accept(self) + } + + fn visit_stmt(&mut self, stmt: &Stmt) -> Self::Out; + fn visit_expr(&mut self, expr: &Expr) -> Self::Out; +} + +pub trait Accept { + fn accept(&self, visitor: &mut V) -> V::Out; +} + +impl Accept for Stmt { + fn accept(&self, visitor: &mut V) -> V::Out { + visitor.visit_stmt(self) + } +} + +impl Accept for Expr { + fn accept(&self, visitor: &mut V) -> V::Out { + visitor.visit_expr(self) + } +} diff --git a/src/main.rs b/src/main.rs index 344fb00..0f9dd67 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,6 +40,17 @@ fn main() -> Result<()> { let opt = Options::from_args(); let text = fs::read_to_string(&opt.input)?; let mut parser = Parser::try_from(text.as_str())?; - println!("{:#?}", parser.next_body()?); + let ast = parser.next_body()?; + //println!("{:#?}", ast); + + let mut ctx = compile::Ctx::new(text.as_str()); + ctx.name_stack_mut().push_default(); + { + let mut collect_names = compile::name::CollectNames::new(&mut ctx); + collect_names.collect(&ast); + } + let names = ctx.name_stack_mut().pop().unwrap(); + println!("{:#?}", names); + Ok(()) } diff --git a/src/syn/ast.rs b/src/syn/ast.rs index 90343d7..127dfc3 100644 --- a/src/syn/ast.rs +++ b/src/syn/ast.rs @@ -1,6 +1,21 @@ use crate::syn::{op::*, span::*}; use derivative::Derivative; +pub mod prelude { + pub use super::{ + Stmt, + AssignStmt, + Expr, + BinExpr, + UnExpr, + FunCallExpr, + IndexExpr, + FunExpr, + BaseExpr, + BaseExprKind + }; +} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum Stmt { Assign(AssignStmt),