Update how visitors work, add NameId type
* Visitors are now defined on a per-type level, allowing for greater flexibility in combining and re-using behavior * NameId is used for namespaces, which are used to index locally scoped variables. Syms are used for free namespaces, specifically in objects. All NameIDs are symbols, while not all symbols are NameIDs. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -1,6 +1,69 @@
|
||||
use crate::compile::ir::Body;
|
||||
use crate::{
|
||||
syn::{ast::*, op::BinOp, span::*},
|
||||
compile::{
|
||||
Ctx,
|
||||
error::*,
|
||||
ir,
|
||||
visit::*,
|
||||
},
|
||||
};
|
||||
|
||||
// basic block
|
||||
pub enum Block {
|
||||
Body(Body),
|
||||
Body(ir::Body),
|
||||
}
|
||||
|
||||
pub struct TranslateAst<'c, 't> {
|
||||
ctx: &'c mut Ctx,
|
||||
text: &'t str,
|
||||
}
|
||||
|
||||
impl<'c, 't> TranslateAst<'c, 't> {
|
||||
pub fn new(ctx: &'c mut Ctx, text: &'t str) -> Self {
|
||||
TranslateAst {
|
||||
ctx,
|
||||
text,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn translate(&mut self, ast: &Vec<Stmt>) -> Result<ir::Body> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn visit_lhs_expr(&mut self, expr: &Expr) -> Result<ir::Lhs> {
|
||||
match expr {
|
||||
Expr::Bin(b) if b.op == BinOp::Dot => todo!(),
|
||||
Expr::Base(BaseExpr { kind: BaseExprKind::Ident, .. }) => {
|
||||
let name = expr.text_at(self.text);
|
||||
//let name_id = self.ctx.
|
||||
todo!()
|
||||
//Ok(ir::Lhs::Name(
|
||||
}
|
||||
_ => todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit<Stmt> for TranslateAst<'_, '_> {
|
||||
type Out = Result<ir::Stmt>;
|
||||
|
||||
fn visit(&mut self, stmt: &Stmt) -> Self::Out {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit<AssignStmt> for TranslateAst<'_, '_> {
|
||||
type Out = Result<ir::Stmt>;
|
||||
|
||||
fn visit(&mut self, stmt: &AssignStmt) -> Self::Out {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit<Expr> for TranslateAst<'_, '_> {
|
||||
type Out = Result<ir::Expr>;
|
||||
|
||||
fn visit(&mut self, expr: &Expr) -> Self::Out {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
use crate::syn::span::*;
|
||||
use snafu::Snafu;
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
pub enum Error {
|
||||
//#[snafu(display("illegal attr key"))]
|
||||
|
||||
#[snafu(display("invalid assignment target"))]
|
||||
InvalidLhs {
|
||||
span: Span,
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use crate::{
|
||||
compile::Ctx,
|
||||
obj::Sym,
|
||||
syn::span::*,
|
||||
};
|
||||
@@ -14,7 +13,7 @@ pub enum Stmt {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Lhs {
|
||||
Sym(Sym),
|
||||
Name(Sym),
|
||||
Complex(Expr),
|
||||
}
|
||||
|
||||
@@ -29,7 +28,7 @@ pub enum BaseExprKind {
|
||||
Num(i64),
|
||||
Str(String),
|
||||
Sym(Sym),
|
||||
Ident(String),
|
||||
Ident(Sym),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -37,23 +36,3 @@ 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,8 +1,8 @@
|
||||
#[macro_use] pub mod visit;
|
||||
pub mod block;
|
||||
pub mod error;
|
||||
pub mod ir;
|
||||
pub mod name;
|
||||
pub mod visit;
|
||||
|
||||
use crate::compile::name::NameStack;
|
||||
|
||||
@@ -10,23 +10,17 @@ use crate::compile::name::NameStack;
|
||||
// * Collect names as symbols
|
||||
// * Create basic blocks
|
||||
|
||||
pub struct Ctx<'t> {
|
||||
text: &'t str,
|
||||
pub struct Ctx {
|
||||
name_stack: NameStack,
|
||||
}
|
||||
|
||||
impl<'t> Ctx<'t> {
|
||||
pub fn new(text: &'t str) -> Self {
|
||||
impl Ctx {
|
||||
pub fn new() -> Self {
|
||||
Ctx {
|
||||
text,
|
||||
name_stack: NameStack::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn text(&self) -> &'t str {
|
||||
self.text
|
||||
}
|
||||
|
||||
pub fn name_stack(&self) -> &NameStack {
|
||||
&self.name_stack
|
||||
}
|
||||
@@ -35,16 +29,3 @@ impl<'t> Ctx<'t> {
|
||||
&mut self.name_stack
|
||||
}
|
||||
}
|
||||
|
||||
// no sugar in the syntax quite yet
|
||||
/*
|
||||
pub struct Desugar;
|
||||
|
||||
impl Pass<Vec<Stmt>> for Desugar {
|
||||
type Out = Vec<Stmt>;
|
||||
|
||||
fn pass(&mut self, input: Vec<Stmt>) -> Vec<Stmt> {
|
||||
input
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -1,22 +1,10 @@
|
||||
use crate::{
|
||||
compile::{visit::*, Ctx},
|
||||
syn::{ast::prelude::*, op::BinOp, span::*},
|
||||
obj::prelude::*,
|
||||
syn::{ast::prelude::*, 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>>,
|
||||
@@ -84,78 +72,70 @@ impl NameStack {
|
||||
}
|
||||
|
||||
/// 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>,
|
||||
pub struct CollectNames<'c, 't> {
|
||||
ctx: &'c mut Ctx,
|
||||
text: &'t str,
|
||||
}
|
||||
|
||||
impl<'c, 't: 'c> CollectNames<'c, 't> {
|
||||
pub fn new(ctx: &'c mut Ctx<'t>) -> Self {
|
||||
CollectNames { ctx }
|
||||
default_visitor!(Expr for CollectNames<'_, '_> where Out = ());
|
||||
empty_visitor!(FunCallExpr for CollectNames<'_, '_>);
|
||||
empty_visitor!(FunExpr for CollectNames<'_, '_>);
|
||||
|
||||
impl<'c, 't> CollectNames<'c, 't> {
|
||||
pub fn new(ctx: &'c mut Ctx, text: &'t str) -> Self {
|
||||
CollectNames { ctx, text }
|
||||
}
|
||||
|
||||
pub fn collect(&mut self, stmts: &Vec<Stmt>) {
|
||||
// Collect all LHS assignments
|
||||
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);
|
||||
if let Stmt::Assign(stmt) = stmt {
|
||||
self.visit(stmt);
|
||||
}
|
||||
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<'_, '_> {
|
||||
impl Visit<AssignStmt> 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(_) => { /* no-op */ }
|
||||
Expr::Base(b) => self.visit_base_expr(b),
|
||||
}
|
||||
fn visit(&mut self, stmt: &AssignStmt) -> Self::Out {
|
||||
self.visit(&stmt.lhs);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
impl Visit<BinExpr> for CollectNames<'_, '_> {
|
||||
type Out = ();
|
||||
|
||||
fn visit(&mut self, expr: &BinExpr) -> Self::Out {
|
||||
self.visit(&expr.lhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit<UnExpr> for CollectNames<'_, '_> {
|
||||
type Out = ();
|
||||
|
||||
fn visit(&mut self, expr: &UnExpr) -> Self::Out {
|
||||
self.visit(&expr.expr)
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit<IndexExpr> for CollectNames<'_, '_> {
|
||||
type Out = ();
|
||||
|
||||
fn visit(&mut self, expr: &IndexExpr) -> Self::Out {
|
||||
self.visit(&expr.expr);
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit<BaseExpr> for CollectNames<'_, '_> {
|
||||
type Out = ();
|
||||
|
||||
fn visit(&mut self, expr: &BaseExpr) -> Self::Out {
|
||||
// This is a LHS standalone expr
|
||||
if let BaseExpr { kind: BaseExprKind::Ident, .. } = expr {
|
||||
let name = expr.text_at(self.text).to_string();
|
||||
self.ctx.name_stack_mut().add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,91 @@
|
||||
use crate::syn::ast::{Stmt, Expr};
|
||||
use crate::syn::ast::prelude::*;
|
||||
|
||||
pub trait Visit {
|
||||
pub trait Visit<A: Accept> {
|
||||
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;
|
||||
fn visit(&mut self, acceptor: &A) -> Self::Out;
|
||||
}
|
||||
|
||||
pub trait Accept<V: Visit> {
|
||||
fn accept(&self, visitor: &mut V) -> V::Out;
|
||||
pub trait Accept {
|
||||
fn accept<V: Visit<Self>>(&self, visitor: &mut V) -> V::Out
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
impl<V: Visit> Accept<V> for Stmt {
|
||||
fn accept(&self, visitor: &mut V) -> V::Out {
|
||||
visitor.visit_stmt(self)
|
||||
pub trait DefaultAccept<V: Visit<Self>>: Accept + Sized
|
||||
{
|
||||
fn default_accept(&self, visitor: &mut V) -> V::Out;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! default_visitor {
|
||||
($default:ident for $visitor:ty where Out = $out:ty) => {
|
||||
impl crate::compile::visit::Visit<$default> for $visitor {
|
||||
type Out = $out;
|
||||
fn visit(&mut self, acceptor: &$default) -> Self::Out {
|
||||
acceptor.default_accept(self)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! empty_visitor {
|
||||
($default:ident for $visitor:ty) => {
|
||||
impl crate::compile::visit::Visit<$default> for $visitor {
|
||||
type Out = ();
|
||||
fn visit(&mut self, _: &$default) -> Self::Out {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: Visit> Accept<V> for Expr {
|
||||
fn accept(&self, visitor: &mut V) -> V::Out {
|
||||
visitor.visit_expr(self)
|
||||
}
|
||||
macro_rules! impl_accept {
|
||||
($what:ident) => {
|
||||
impl crate::compile::visit::Accept for $what {
|
||||
fn accept<V: Visit<Self>>(&self, visitor: &mut V) -> V::Out {
|
||||
visitor.visit(self)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_default_accept {
|
||||
($what:ident : $($requires:ident),+ => $($tail:tt)+) => {
|
||||
impl<V, Out> DefaultAccept<V> for $what
|
||||
where V: Visit<Self, Out=Out> $(+ Visit<$requires, Out=Out>)+
|
||||
{
|
||||
$($tail)+
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_accept!(Stmt);
|
||||
impl_default_accept!(Stmt : AssignStmt, Expr =>
|
||||
fn default_accept(&self, visitor: &mut V) -> Out {
|
||||
match self {
|
||||
Stmt::Assign(a) => visitor.visit(a),
|
||||
Stmt::Expr(e) => visitor.visit(e),
|
||||
}
|
||||
}
|
||||
);
|
||||
impl_accept!(AssignStmt);
|
||||
impl_accept!(Expr);
|
||||
|
||||
impl_default_accept!(Expr: BinExpr, UnExpr, FunCallExpr, IndexExpr, FunExpr, BaseExpr =>
|
||||
fn default_accept(&self, visitor: &mut V) -> Out {
|
||||
match self {
|
||||
Expr::Bin(b) => visitor.visit(b.as_ref()),
|
||||
Expr::Un(u) => visitor.visit(u.as_ref()),
|
||||
Expr::FunCall(f) => visitor.visit(f.as_ref()),
|
||||
Expr::Index(i) => visitor.visit(i.as_ref()),
|
||||
Expr::Fun(f) => visitor.visit(f.as_ref()),
|
||||
Expr::Base(b) => visitor.visit(b),
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
impl_accept!(BinExpr);
|
||||
impl_accept!(UnExpr);
|
||||
impl_accept!(FunCallExpr);
|
||||
impl_accept!(IndexExpr);
|
||||
impl_accept!(FunExpr);
|
||||
impl_accept!(BaseExpr);
|
||||
|
||||
Reference in New Issue
Block a user