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 <alekratz@gmail.com>
This commit is contained in:
6
src/compile/block.rs
Normal file
6
src/compile/block.rs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
use crate::compile::ir::Body;
|
||||||
|
|
||||||
|
// basic block
|
||||||
|
pub enum Block {
|
||||||
|
Body(Body),
|
||||||
|
}
|
||||||
9
src/compile/error.rs
Normal file
9
src/compile/error.rs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
use snafu::Snafu;
|
||||||
|
|
||||||
|
#[derive(Debug, Snafu)]
|
||||||
|
pub enum Error {
|
||||||
|
//#[snafu(display("illegal attr key"))]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
||||||
59
src/compile/ir.rs
Normal file
59
src/compile/ir.rs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
use crate::{
|
||||||
|
compile::Ctx,
|
||||||
|
obj::Sym,
|
||||||
|
syn::{ast, span::*},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub type Body = Vec<Stmt>;
|
||||||
|
|
||||||
|
#[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<Expr>, Vec<Expr>),
|
||||||
|
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<A> {
|
||||||
|
fn from_ast(other: A, ctx: &mut Ctx, text: &str) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait IntoIr<I> {
|
||||||
|
fn into_ir(self, ctx: &mut Ctx, text: &str) -> I;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, I> IntoIr<I> for A
|
||||||
|
where
|
||||||
|
I: FromAst<A>,
|
||||||
|
{
|
||||||
|
fn into_ir(self, ctx: &mut Ctx, text: &str) -> I {
|
||||||
|
FromAst::from_ast(self, ctx, text)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,30 +1,41 @@
|
|||||||
pub mod sym;
|
pub mod block;
|
||||||
|
pub mod error;
|
||||||
|
pub mod ir;
|
||||||
|
pub mod name;
|
||||||
|
pub mod visit;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
syn::ast::Stmt,
|
syn::ast::Stmt,
|
||||||
compile::sym::SymStack,
|
compile::name::NameStack,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait Pass {
|
|
||||||
type Out;
|
|
||||||
fn pass(&self, ctx: &mut Ctx) -> Self::Out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// * Desugar
|
// * Desugar
|
||||||
// * Collect names as symbols
|
// * Collect names as symbols
|
||||||
// * Create basic blocks
|
// * Create basic blocks
|
||||||
|
|
||||||
pub struct Ctx {
|
pub struct Ctx<'t> {
|
||||||
sym_stack: SymStack,
|
text: &'t str,
|
||||||
|
name_stack: NameStack,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ctx {
|
impl<'t> Ctx<'t> {
|
||||||
pub fn sym_stack(&self) -> &SymStack {
|
pub fn new(text: &'t str) -> Self {
|
||||||
&self.sym_stack
|
Ctx {
|
||||||
|
text,
|
||||||
|
name_stack: NameStack::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sym_stack_mut(&mut self) -> &mut SymStack {
|
pub fn text(&self) -> &'t str {
|
||||||
&mut self.sym_stack
|
self.text
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name_stack(&self) -> &NameStack {
|
||||||
|
&self.name_stack
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name_stack_mut(&mut self) -> &mut NameStack {
|
||||||
|
&mut self.name_stack
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
161
src/compile/name.rs
Normal file
161
src/compile/name.rs
Normal file
@@ -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<HashMap<String, NameId>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NameStack {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
NameStack {
|
||||||
|
next_sym: 0,
|
||||||
|
stack: vec![Default::default()],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, syms: HashMap<String, NameId>) {
|
||||||
|
self.stack.push(syms);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_default(&mut self) {
|
||||||
|
self.push(Default::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop(&mut self) -> Option<HashMap<String, NameId>> {
|
||||||
|
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<NameId> {
|
||||||
|
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<NameId> {
|
||||||
|
self.stack
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.filter_map(|locals| locals.get(name))
|
||||||
|
.next()
|
||||||
|
.copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn root(&self) -> &HashMap<String, NameId> {
|
||||||
|
self.stack.first().expect("no root name map")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn root_mut(&mut self) -> &mut HashMap<String, NameId> {
|
||||||
|
self.stack.first_mut().expect("no root name map")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn locals(&self) -> &HashMap<String, NameId> {
|
||||||
|
self.stack.last().expect("no local name map")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn locals_mut(&mut self) -> &mut HashMap<String, NameId> {
|
||||||
|
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<Stmt>) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
use crate::obj::Sym;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
pub struct SymStack {
|
|
||||||
syms: HashMap<String, Sym>,
|
|
||||||
stack: Vec<Vec<Sym>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SymStack {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
SymStack {
|
|
||||||
syms: Default::default(),
|
|
||||||
stack: vec![Default::default()],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
29
src/compile/visit.rs
Normal file
29
src/compile/visit.rs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
use crate::syn::ast::{Stmt, Expr};
|
||||||
|
|
||||||
|
pub trait Visit {
|
||||||
|
type Out;
|
||||||
|
fn visit<A: Accept<Self>>(&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<V: Visit> {
|
||||||
|
fn accept(&self, visitor: &mut V) -> V::Out;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: Visit> Accept<V> for Stmt {
|
||||||
|
fn accept(&self, visitor: &mut V) -> V::Out {
|
||||||
|
visitor.visit_stmt(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: Visit> Accept<V> for Expr {
|
||||||
|
fn accept(&self, visitor: &mut V) -> V::Out {
|
||||||
|
visitor.visit_expr(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/main.rs
13
src/main.rs
@@ -40,6 +40,17 @@ fn main() -> Result<()> {
|
|||||||
let opt = Options::from_args();
|
let opt = Options::from_args();
|
||||||
let text = fs::read_to_string(&opt.input)?;
|
let text = fs::read_to_string(&opt.input)?;
|
||||||
let mut parser = Parser::try_from(text.as_str())?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,21 @@
|
|||||||
use crate::syn::{op::*, span::*};
|
use crate::syn::{op::*, span::*};
|
||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
|
|
||||||
|
pub mod prelude {
|
||||||
|
pub use super::{
|
||||||
|
Stmt,
|
||||||
|
AssignStmt,
|
||||||
|
Expr,
|
||||||
|
BinExpr,
|
||||||
|
UnExpr,
|
||||||
|
FunCallExpr,
|
||||||
|
IndexExpr,
|
||||||
|
FunExpr,
|
||||||
|
BaseExpr,
|
||||||
|
BaseExprKind
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum Stmt {
|
pub enum Stmt {
|
||||||
Assign(AssignStmt),
|
Assign(AssignStmt),
|
||||||
|
|||||||
Reference in New Issue
Block a user