2020-05-19 15:26:38 -04:00
|
|
|
use crate::{
|
2020-05-21 19:09:48 -04:00
|
|
|
compile::ctx::Ctx,
|
2020-05-20 14:41:12 -04:00
|
|
|
obj::prelude::*,
|
|
|
|
|
syn::{ast::prelude::*, span::*},
|
2020-05-21 19:09:48 -04:00
|
|
|
visit::*,
|
2020-05-19 15:26:38 -04:00
|
|
|
};
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
2020-05-20 14:51:30 -04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// NameStack
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2020-05-20 15:24:40 -04:00
|
|
|
#[derive(Debug, Clone)]
|
2020-05-19 15:26:38 -04:00
|
|
|
pub struct NameStack {
|
|
|
|
|
next_sym: usize,
|
|
|
|
|
stack: Vec<HashMap<String, NameId>>,
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-20 15:24:40 -04:00
|
|
|
impl Default for NameStack {
|
|
|
|
|
fn default() -> Self {
|
2020-05-19 15:26:38 -04:00
|
|
|
NameStack {
|
|
|
|
|
next_sym: 0,
|
|
|
|
|
stack: vec![Default::default()],
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-20 15:24:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl NameStack {
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
|
Default::default()
|
|
|
|
|
}
|
2020-05-19 15:26:38 -04:00
|
|
|
|
|
|
|
|
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")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-20 14:51:30 -04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// CollectNames
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
/// Collect local stack names and push them to the top layer of the name stack.
|
2020-05-20 14:41:12 -04:00
|
|
|
pub struct CollectNames<'c, 't> {
|
|
|
|
|
ctx: &'c mut Ctx,
|
|
|
|
|
text: &'t str,
|
2020-05-19 15:26:38 -04:00
|
|
|
}
|
|
|
|
|
|
2020-05-20 14:41:12 -04:00
|
|
|
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 }
|
2020-05-19 15:26:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn collect(&mut self, stmts: &Vec<Stmt>) {
|
2020-05-20 14:41:12 -04:00
|
|
|
// Collect all LHS assignments
|
2020-05-19 15:26:38 -04:00
|
|
|
for stmt in stmts.iter() {
|
2020-05-20 14:41:12 -04:00
|
|
|
if let Stmt::Assign(stmt) = stmt {
|
|
|
|
|
self.visit(stmt);
|
|
|
|
|
}
|
2020-05-19 15:26:38 -04:00
|
|
|
}
|
|
|
|
|
}
|
2020-05-20 14:41:12 -04:00
|
|
|
}
|
2020-05-19 15:26:38 -04:00
|
|
|
|
2020-05-20 14:41:12 -04:00
|
|
|
impl Visit<AssignStmt> for CollectNames<'_, '_> {
|
|
|
|
|
type Out = ();
|
|
|
|
|
|
|
|
|
|
fn visit(&mut self, stmt: &AssignStmt) -> Self::Out {
|
|
|
|
|
self.visit(&stmt.lhs);
|
2020-05-19 15:26:38 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-20 14:41:12 -04:00
|
|
|
impl Visit<BinExpr> for CollectNames<'_, '_> {
|
2020-05-19 15:26:38 -04:00
|
|
|
type Out = ();
|
|
|
|
|
|
2020-05-20 14:41:12 -04:00
|
|
|
fn visit(&mut self, expr: &BinExpr) -> Self::Out {
|
|
|
|
|
self.visit(&expr.lhs);
|
2020-05-19 15:26:38 -04:00
|
|
|
}
|
2020-05-20 14:41:12 -04:00
|
|
|
}
|
2020-05-19 15:26:38 -04:00
|
|
|
|
2020-05-20 14:41:12 -04:00
|
|
|
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
|
2020-05-20 14:51:30 -04:00
|
|
|
if let BaseExpr {
|
|
|
|
|
kind: BaseExprKind::Ident,
|
|
|
|
|
..
|
|
|
|
|
} = expr
|
|
|
|
|
{
|
2020-05-20 14:41:12 -04:00
|
|
|
let name = expr.text_at(self.text).to_string();
|
|
|
|
|
self.ctx.name_stack_mut().add(name);
|
2020-05-19 15:26:38 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-20 14:51:30 -04:00
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// CollectSyms
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2020-05-20 15:24:40 -04:00
|
|
|
|
|
|
|
|
/// Collect symbols (identifiers and symbols included).
|
|
|
|
|
///
|
|
|
|
|
/// These are used for indexing values in attribute maps.
|
|
|
|
|
pub struct CollectSyms<'c, 't> {
|
|
|
|
|
ctx: &'c mut Ctx,
|
|
|
|
|
text: &'t str,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'c, 't> CollectSyms<'c, 't> {
|
|
|
|
|
pub fn new(ctx: &'c mut Ctx, text: &'t str) -> Self {
|
|
|
|
|
CollectSyms { ctx, text }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn collect(&mut self, stmts: &Vec<Stmt>) {
|
|
|
|
|
// Collect all LHS assignments
|
|
|
|
|
for stmt in stmts.iter() {
|
|
|
|
|
self.visit(stmt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default_visitor!(Stmt for CollectSyms<'_, '_> where Out = ());
|
|
|
|
|
default_visitor!(Expr for CollectSyms<'_, '_> where Out = ());
|
|
|
|
|
|
|
|
|
|
impl Visit<AssignStmt> for CollectSyms<'_, '_> {
|
|
|
|
|
type Out = ();
|
|
|
|
|
|
|
|
|
|
fn visit(&mut self, stmt: &AssignStmt) -> Self::Out {
|
|
|
|
|
self.visit(&stmt.lhs);
|
|
|
|
|
self.visit(&stmt.rhs);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Visit<BinExpr> for CollectSyms<'_, '_> {
|
|
|
|
|
type Out = ();
|
|
|
|
|
|
|
|
|
|
fn visit(&mut self, expr: &BinExpr) -> Self::Out {
|
|
|
|
|
self.visit(&expr.lhs);
|
|
|
|
|
self.visit(&expr.rhs);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Visit<UnExpr> for CollectSyms<'_, '_> {
|
|
|
|
|
type Out = ();
|
|
|
|
|
|
|
|
|
|
fn visit(&mut self, expr: &UnExpr) -> Self::Out {
|
|
|
|
|
self.visit(&expr.expr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Visit<FunCallExpr> for CollectSyms<'_, '_> {
|
|
|
|
|
type Out = ();
|
|
|
|
|
|
|
|
|
|
fn visit(&mut self, expr: &FunCallExpr) -> Self::Out {
|
|
|
|
|
self.visit(&expr.expr);
|
|
|
|
|
expr.args.iter().for_each(|expr| self.visit(expr));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Visit<IndexExpr> for CollectSyms<'_, '_> {
|
|
|
|
|
type Out = ();
|
|
|
|
|
|
|
|
|
|
fn visit(&mut self, expr: &IndexExpr) -> Self::Out {
|
|
|
|
|
self.visit(&expr.expr);
|
|
|
|
|
self.visit(&expr.index);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Visit<FunExpr> for CollectSyms<'_, '_> {
|
|
|
|
|
type Out = ();
|
|
|
|
|
|
|
|
|
|
fn visit(&mut self, expr: &FunExpr) -> Self::Out {
|
|
|
|
|
expr.params.iter().for_each(|name| {
|
2020-05-21 18:51:54 -04:00
|
|
|
self.ctx.syms_mut().add(name.clone());
|
2020-05-20 15:24:40 -04:00
|
|
|
});
|
|
|
|
|
self.visit(&expr.expr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Visit<BaseExpr> for CollectSyms<'_, '_> {
|
|
|
|
|
type Out = ();
|
|
|
|
|
|
|
|
|
|
fn visit(&mut self, expr: &BaseExpr) -> Self::Out {
|
|
|
|
|
match &expr.kind {
|
|
|
|
|
BaseExprKind::Ident => {
|
|
|
|
|
let name = expr.text_at(self.text).to_string();
|
2020-05-21 18:51:54 -04:00
|
|
|
self.ctx.syms_mut().add(name);
|
2020-05-20 15:24:40 -04:00
|
|
|
}
|
|
|
|
|
BaseExprKind::Sym => {
|
|
|
|
|
let name = expr.text_at(self.text).chars().skip(1).collect::<String>();
|
2020-05-21 18:51:54 -04:00
|
|
|
self.ctx.syms_mut().add(name);
|
2020-05-20 15:24:40 -04:00
|
|
|
}
|
|
|
|
|
BaseExprKind::List(l) | BaseExprKind::Tuple(l) => {
|
|
|
|
|
l.iter().for_each(|expr| self.visit(expr))
|
|
|
|
|
}
|
|
|
|
|
BaseExprKind::Object(o) => o.iter().for_each(|(k, v)| {
|
|
|
|
|
self.visit(k);
|
|
|
|
|
self.visit(v);
|
|
|
|
|
}),
|
|
|
|
|
BaseExprKind::Block(stmts) => {
|
|
|
|
|
stmts.iter().for_each(|stmt| self.visit(stmt));
|
|
|
|
|
}
|
|
|
|
|
_ => { /* no-op */ }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|