chewker done ^w^

This commit is contained in:
SimonFJ20 2024-05-30 13:49:41 +02:00
parent 5f41342a16
commit d55e9b3c70
9 changed files with 486 additions and 113 deletions

91
Cargo.lock generated
View File

@ -2,6 +2,97 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "diff"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "libc"
version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "pretty_assertions"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66"
dependencies = [
"diff",
"yansi",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "yansi"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
[[package]] [[package]]
name = "yapping" name = "yapping"
version = "0.1.0" version = "0.1.0"
dependencies = [
"pretty_assertions",
"rand",
]

View File

@ -6,3 +6,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
pretty_assertions = "1.4.0"
rand = "0.8.5"

View File

@ -2,6 +2,7 @@
pub struct Node { pub struct Node {
pub kind: NodeKind, pub kind: NodeKind,
pub typ: Type, pub typ: Type,
pub table_id: usize,
} }
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
@ -36,7 +37,7 @@ pub enum NodeKind {
Fn { Fn {
subject: Box<Node>, subject: Box<Node>,
params: Vec<Node>, params: Vec<Node>,
return_typ: Box<Node>, return_typ: Type,
body: Box<Node>, body: Box<Node>,
}, },
Return { Return {

View File

@ -1,79 +1,130 @@
#![allow(unused_variables)] #![allow(unused_variables)]
use rand::random;
use crate::{ use crate::{
checked::{Node, NodeKind, Type}, checked::{Node, NodeKind, Type},
hash::hash,
itertewls::Itertewls, itertewls::Itertewls,
parsed, parsed,
sym::Syms, sym::Syms,
util::hash,
}; };
pub struct Checker {} pub trait IdGen {
fn new() -> Self;
fn gen(&mut self) -> u64;
}
pub struct RandIdGen;
impl IdGen for RandIdGen {
fn new() -> Self {
Self
}
fn gen(&mut self) -> u64 {
random()
}
}
pub struct Checker<FnIdGen: IdGen = RandIdGen> {
syms: Syms,
fn_id_gen: FnIdGen,
}
impl Checker { impl Checker {
pub fn new() -> Self { pub fn new() -> Self {
Self {} Self {
syms: Syms::new(),
fn_id_gen: RandIdGen::new(),
}
}
}
impl<FnIdGen: IdGen> Checker<FnIdGen> {
pub fn new_with_fn_id_gen() -> Self {
Self {
syms: Syms::new(),
fn_id_gen: FnIdGen::new(),
}
} }
pub fn check(&mut self, ast: &Vec<parsed::Node>) -> Vec<Node> { pub fn check(&mut self, ast: &[parsed::Node]) -> Vec<Node> {
let mut syms = Syms::new(); self.fn_scan(ast);
ast.into_iter() ast.iter().map(|stmt| self.check_expr(stmt)).collect()
.map(|stmt| self.check_expr(stmt, &mut syms))
.collect()
} }
fn fn_scan<'syms>( fn fn_scan(&mut self, ast: &[parsed::Node]) {
&mut self,
ast: &Vec<parsed::Node>,
syms: &mut Syms<'syms>,
) -> Result<(), ()> {
for node in ast { for node in ast {
match node { if let parsed::Node::Fn {
parsed::Node::Fn { subject,
subject, params,
params, return_typ,
return_typ, body,
body, } = node
} => { {
let params = params.into_iter().map(|param| { let Ok(params) = self.fn_scan_params(params) else {
let parsed::Node::Param { subject, typ } = param else { unreachable!() }; continue;
let parsed::Node::Id(id) = subject.as_ref() else { unreachable!() }; };
let typ = self.check_type(typ.as_ref().ok_or(())?);
Ok((*id, self.node(NodeKind::Param { subject: Box::new(self.node(NodeKind::Id(*id), Type::Unit)), typ: Some(typ) }, Type::Unit)))
}).collect::<Result<Vec<_>, _>>()?;
if let Some(id) = params.iter().map(|(id, _)| *id).find_first_duplicate() { if let Some(id) = params.iter().map(|(id, _)| *id).find_first_duplicate() {
self.error("redefinition param"); self.error("redefinition param");
return Err(()); continue;
}
let parsed::Node::Id(id) = subject.as_ref() else { unreachable!() };
if syms.defined_locally(*id) {
self.error("redefinition fn");
return Err(());
}
//syms.define(*id, typ.clone());
} }
_ => {}
let params = params.into_iter().map(|(_, param)| param).collect();
let parsed::Node::Id(id) = subject.as_ref() else { unreachable!() };
if self.syms.defined_locally(*id) {
self.error("redefinition fn");
continue;
}
let return_typ = self.check_type(return_typ);
let typ = Type::Fn {
id: self.fn_id_gen.gen(),
params,
return_typ: Box::new(return_typ),
};
self.syms.define(*id, typ.clone());
} }
} }
Ok(())
} }
fn check_expr<'syms>(&mut self, node: &parsed::Node, syms: &mut Syms<'syms>) -> Node { fn fn_scan_params(&self, params: &[parsed::Node]) -> Result<Vec<(u64, Node)>, ()> {
params
.iter()
.map(|param| {
let parsed::Node::Param { subject, typ } = param else { unreachable!() };
let parsed::Node::Id(id) = subject.as_ref() else { unreachable!() };
let typ = self.check_type(typ.as_ref().ok_or(())?);
Ok((
*id,
self.node(
NodeKind::Param {
subject: Box::new(self.node(NodeKind::Id(*id), Type::Unit)),
typ: Some(typ),
},
Type::Unit,
),
))
})
.collect::<Result<Vec<_>, _>>()
}
fn check_expr(&mut self, node: &parsed::Node) -> Node {
match node { match node {
parsed::Node::Error => self.node(NodeKind::Error, Type::Unit), parsed::Node::Error => self.node(NodeKind::Error, Type::Unit),
parsed::Node::Id(id) => { parsed::Node::Id(id) => {
let Some(sym) = syms.get(*id) else { let Some(sym) = self.syms.get(*id) else {
self.error("undefined >~<"); self.error("undefined >~<");
return self.node(NodeKind::Error, Type::Error); return self.node(NodeKind::Error, Type::Error);
}; };
self.node(NodeKind::Id(*id), sym.typ) self.node(NodeKind::Id(*id), sym.typ.clone())
} }
parsed::Node::Int(value) => self.node( parsed::Node::Int(value) => self.node(
NodeKind::Int(*value), NodeKind::Int(*value),
if *value as i32 > i32::MAX { if *value > i32::MAX as i64 {
Type::U32 Type::U32
} else { } else {
Type::I32 Type::I32
@ -81,16 +132,17 @@ impl Checker {
), ),
parsed::Node::String(value) => self.node(NodeKind::String(value.clone()), Type::String), parsed::Node::String(value) => self.node(NodeKind::String(value.clone()), Type::String),
parsed::Node::Group(expr) => { parsed::Node::Group(expr) => {
let expr = self.check_expr(expr, syms); let expr = self.check_expr(expr);
let typ = expr.typ.clone(); let typ = expr.typ.clone();
self.node(NodeKind::Group(Box::new(expr)), typ) self.node(NodeKind::Group(Box::new(expr)), typ)
} }
parsed::Node::Block(stmts) => { parsed::Node::Block(stmts) => {
let mut child_syms = syms.child(); self.syms.enter_scope();
let stmts = stmts let stmts = stmts
.into_iter() .iter()
.map(|stmt| self.check_expr(stmt, &mut child_syms)) .map(|stmt| self.check_expr(stmt))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
self.syms.leave_scope().unwrap();
let typ = stmts let typ = stmts
.last() .last()
.map(|stmt| stmt.typ.clone()) .map(|stmt| stmt.typ.clone())
@ -98,11 +150,11 @@ impl Checker {
self.node(NodeKind::Block(stmts), typ) self.node(NodeKind::Block(stmts), typ)
} }
parsed::Node::Call { subject, args } => { parsed::Node::Call { subject, args } => {
let subject = Box::new(self.check_expr(subject, syms)); let subject = Box::new(self.check_expr(subject));
let args = args let args = args
.into_iter() .iter()
.map(|arg| self.check_expr(arg, syms)) .map(|arg| self.check_expr(arg))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let typ = 'br: { let typ = 'br: {
match subject.typ.clone() { match subject.typ.clone() {
@ -139,11 +191,9 @@ impl Checker {
truthy, truthy,
falsy, falsy,
} => { } => {
let cond = Box::new(self.check_expr(cond, syms)); let cond = Box::new(self.check_expr(cond));
let truthy = Box::new(self.check_expr(truthy, syms)); let truthy = Box::new(self.check_expr(truthy));
let falsy = falsy let falsy = falsy.as_ref().map(|block| Box::new(self.check_expr(block)));
.as_ref()
.map(|block| Box::new(self.check_expr(block, syms)));
let typ = 'br: { let typ = 'br: {
match falsy.as_ref().map(|block| block.typ.clone()) { match falsy.as_ref().map(|block| block.typ.clone()) {
Some(falsy_typ) => { Some(falsy_typ) => {
@ -166,14 +216,15 @@ impl Checker {
) )
} }
parsed::Node::Loop { body } => { parsed::Node::Loop { body } => {
let body = Box::new(self.check_expr(body, &mut syms.child())); self.syms.enter_scope();
let body = Box::new(self.check_expr(body));
let typ = body.typ.clone(); let typ = body.typ.clone();
self.node(NodeKind::Loop { body }, typ) self.node(NodeKind::Loop { body }, typ)
} }
parsed::Node::Break => self.node(NodeKind::Break, Type::Unit), parsed::Node::Break => self.node(NodeKind::Break, Type::Unit),
parsed::Node::Assign { subject, value } => { parsed::Node::Assign { subject, value } => {
let subject = Box::new(self.check_expr(subject, syms)); let subject = Box::new(self.check_expr(subject));
let value = Box::new(self.check_expr(value, syms)); let value = Box::new(self.check_expr(value));
let typ = if !self.compatible(&subject.typ, &value.typ) { let typ = if !self.compatible(&subject.typ, &value.typ) {
self.error("incompatible types #3"); self.error("incompatible types #3");
@ -191,7 +242,7 @@ impl Checker {
_ => unreachable!(), _ => unreachable!(),
}; };
let value = Box::new(self.check_expr(value, syms)); let value = Box::new(self.check_expr(value));
let typ = value.typ.clone(); let typ = value.typ.clone();
if subject_typ if subject_typ
@ -205,11 +256,11 @@ impl Checker {
let subject = match subject.as_ref() { let subject = match subject.as_ref() {
parsed::Node::Id(id) => { parsed::Node::Id(id) => {
if syms.defined_locally(*id) { if self.syms.defined_locally(*id) {
self.error("redefinition"); self.error("redefinition");
return self.node(NodeKind::Error, Type::Error); return self.node(NodeKind::Error, Type::Error);
} }
syms.define(*id, typ.clone()); self.syms.define(*id, typ.clone());
Box::new(self.node( Box::new(self.node(
NodeKind::Param { NodeKind::Param {
subject: Box::new(self.node(NodeKind::Id(*id), Type::Unit)), subject: Box::new(self.node(NodeKind::Id(*id), Type::Unit)),
@ -225,16 +276,53 @@ impl Checker {
} }
parsed::Node::Fn { parsed::Node::Fn {
subject, subject,
params, params: _,
return_typ, return_typ: _,
body, body,
} => { } => {
todo!("symbol lookup"); let parsed::Node::Id(id) = subject.as_ref() else { unreachable!() };
let Some(sym) = self.syms.get(*id).cloned() else {
// rejected in fn scanner
return self.node(NodeKind::Error,Type::Error);
};
let Type::Fn { id: fn_id, params, return_typ } = sym.typ else {
self.error("redefintion");
return self.node(NodeKind::Error,Type::Error);
};
self.syms.enter_scope();
for param in &params {
let NodeKind::Param {
ref subject,
typ: Some(ref typ),
} = param.kind else { unreachable!() };
let NodeKind::Id(id) = subject.kind else { unreachable!() };
self.syms.define(id, typ.clone());
}
let body = Box::new(self.check_expr(body));
if !self.compatible(&return_typ, &body.typ) {
self.error("return type violated");
}
self.syms.leave_scope().unwrap();
self.node(
NodeKind::Fn {
subject: Box::new(self.node(NodeKind::Id(*id), Type::Unit)),
params,
return_typ: *return_typ,
body,
},
Type::Unit,
)
} }
parsed::Node::Return { value } => { parsed::Node::Return { value } => {
let value = value let value = value.as_ref().map(|value| Box::new(self.check_expr(value)));
.as_ref()
.map(|value| Box::new(self.check_expr(value, syms)));
let typ = value let typ = value
.as_ref() .as_ref()
.map(|value| value.typ.clone()) .map(|value| value.typ.clone())
@ -266,7 +354,11 @@ impl Checker {
} }
fn node(&self, kind: NodeKind, typ: Type) -> Node { fn node(&self, kind: NodeKind, typ: Type) -> Node {
Node { kind, typ } Node {
kind,
typ,
table_id: self.syms.table_id(),
}
} }
fn error<S: Into<String>>(&mut self, msg: S) { fn error<S: Into<String>>(&mut self, msg: S) {
@ -278,10 +370,24 @@ impl Checker {
#[test] #[test]
fn test_checker() { fn test_checker() {
use crate::parser::Parser; use crate::parser::Parser;
use NodeKind::{Block, Id, Int, Let, Param}; use pretty_assertions::assert_eq;
use NodeKind::{Block, Call, Error, Fn, Id, Int, Let, Param, Return};
use Type::{Unit, I32}; use Type::{Unit, I32};
let check = |text| Checker::new().check(&Parser::new(text).parse()); struct SeqIdGen(u64);
impl IdGen for SeqIdGen {
fn new() -> Self {
Self(0)
}
fn gen(&mut self) -> u64 {
let v = self.0;
self.0 += 1;
v
}
}
let check = |text| Checker::<SeqIdGen>::new_with_fn_id_gen().check(&Parser::new(text).parse());
assert_eq!( assert_eq!(
check("let a = 5; a;"), check("let a = 5; a;"),
@ -292,26 +398,69 @@ fn test_checker() {
kind: Param { kind: Param {
subject: Box::new(Node { subject: Box::new(Node {
kind: Id(hash("a")), kind: Id(hash("a")),
typ: Unit typ: Unit,
table_id: 0,
}), }),
typ: Some(Unit) typ: Some(Unit)
}, },
typ: Unit typ: Unit,
table_id: 0,
}), }),
value: Box::new(Node { value: Box::new(Node {
kind: Int(5), kind: Int(5),
typ: I32 typ: I32,
table_id: 0,
}) })
}, },
typ: I32 typ: I32,
table_id: 0,
}, },
Node { Node {
kind: Id(hash("a")), kind: Id(hash("a")),
typ: I32 typ: I32,
table_id: 0,
} }
] ]
); );
assert_eq!(
check("let a = 5; { a; }"),
vec![
Node {
kind: Let {
subject: Box::new(Node {
kind: Param {
subject: Box::new(Node {
kind: Id(hash("a")),
typ: Unit,
table_id: 0,
}),
typ: Some(Unit)
},
typ: Unit,
table_id: 0,
}),
value: Box::new(Node {
kind: Int(5),
typ: I32,
table_id: 0,
})
},
typ: I32,
table_id: 0,
},
Node {
kind: Block(vec![Node {
kind: Id(hash("a")),
typ: I32,
table_id: 1,
},]),
typ: I32,
table_id: 0,
},
]
);
assert_eq!( assert_eq!(
check("let a = 5; a; { a; let b = 5; b; } a; b;"), check("let a = 5; a; { a; let b = 5; b; } a; b;"),
vec![ vec![
@ -321,28 +470,34 @@ fn test_checker() {
kind: Param { kind: Param {
subject: Box::new(Node { subject: Box::new(Node {
kind: Id(hash("a")), kind: Id(hash("a")),
typ: Unit typ: Unit,
table_id: 0,
}), }),
typ: Some(Unit) typ: Some(Unit)
}, },
typ: Unit typ: Unit,
table_id: 0,
}), }),
value: Box::new(Node { value: Box::new(Node {
kind: Int(5), kind: Int(5),
typ: I32 typ: I32,
table_id: 0,
}) })
}, },
typ: I32 typ: I32,
table_id: 0,
}, },
Node { Node {
kind: Id(hash("a")), kind: Id(hash("a")),
typ: I32 typ: I32,
table_id: 0,
}, },
Node { Node {
kind: Block(vec![ kind: Block(vec![
Node { Node {
kind: Id(hash("a")), kind: Id(hash("a")),
typ: I32 typ: I32,
table_id: 1,
}, },
Node { Node {
kind: Let { kind: Let {
@ -350,34 +505,92 @@ fn test_checker() {
kind: Param { kind: Param {
subject: Box::new(Node { subject: Box::new(Node {
kind: Id(hash("b")), kind: Id(hash("b")),
typ: Unit typ: Unit,
table_id: 1,
}), }),
typ: Some(Unit) typ: Some(Unit)
}, },
typ: Unit typ: Unit,
table_id: 1,
}), }),
value: Box::new(Node { value: Box::new(Node {
kind: Int(5), kind: Int(5),
typ: I32 typ: I32,
table_id: 1,
}) })
}, },
typ: I32 typ: I32,
table_id: 1,
}, },
Node { Node {
kind: Id(hash("b")), kind: Id(hash("b")),
typ: I32 typ: I32,
table_id: 1,
} }
]), ]),
typ: I32 typ: I32,
table_id: 0,
}, },
Node { Node {
kind: Id(hash("a")), kind: Id(hash("a")),
typ: I32 typ: I32,
table_id: 0,
}, },
Node { Node {
kind: NodeKind::Error, kind: Error,
typ: Type::Error typ: Type::Error,
table_id: 0,
} }
] ]
); );
assert_eq!(
check("fn a() -> i32 { return 0; } \n a();"),
vec![
Node {
kind: Fn {
subject: Box::new(Node {
kind: Id(hash("a")),
typ: Unit,
table_id: 0,
}),
params: vec![],
return_typ: I32,
body: Box::new(Node {
kind: Block(vec![Node {
kind: Return {
value: Some(Box::new(Node {
kind: Int(0),
typ: I32,
table_id: 2,
}),),
},
typ: I32,
table_id: 2,
},],),
typ: I32,
table_id: 1,
}),
},
typ: Unit,
table_id: 0,
},
Node {
kind: Call {
subject: Box::new(Node {
kind: Id(hash("a")),
typ: Type::Fn {
id: 0,
params: vec![],
return_typ: Box::new(I32)
},
table_id: 0
}),
args: vec![]
},
typ: I32,
table_id: 0,
},
]
);
} }

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
hash::hash,
token::{Token, TokenKind, TokenValue}, token::{Token, TokenKind, TokenValue},
util::hash,
}; };
use std::{collections::HashMap, str::Chars}; use std::{collections::HashMap, str::Chars};

View File

@ -2,13 +2,13 @@
mod checked; mod checked;
mod checker; mod checker;
mod hash;
mod itertewls; mod itertewls;
mod lexer; mod lexer;
mod parsed; mod parsed;
mod parser; mod parser;
mod sym; mod sym;
mod token; mod token;
mod util;
fn main() { fn main() {
println!("Hello, world!"); println!("Hello, world!");

View File

@ -205,7 +205,7 @@ impl<'a> Parser<'a> {
self.step(); self.step();
let mut args = Vec::new(); let mut args = Vec::new();
match self.curr_kind() { match self.curr_kind() {
None | Some(TokenKind::LParen) => {} None | Some(TokenKind::RParen) => {}
Some(_) => { Some(_) => {
args.push(self.parse_expr()); args.push(self.parse_expr());
while let Some(TokenKind::Comma) = self.curr_kind() { while let Some(TokenKind::Comma) = self.curr_kind() {
@ -378,7 +378,7 @@ impl<'a> Parser<'a> {
#[test] #[test]
fn test_parser() { fn test_parser() {
use crate::hash::hash; use crate::util::hash;
use Node::*; use Node::*;
let parse = |text| Parser::new(text).parse(); let parse = |text| Parser::new(text).parse();

View File

@ -9,40 +9,106 @@ pub struct Sym {
pub typ: Type, pub typ: Type,
} }
pub struct Syms<'syms> { #[derive(Debug)]
parent: Option<&'syms Syms<'syms>>, pub struct Syms {
map: HashMap<u64, Sym>, tables: Vec<SymTable>,
current_id: usize,
} }
impl<'syms> Syms<'syms> { impl Syms {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
parent: None, tables: vec![SymTable::new()],
map: HashMap::new(), current_id: 0,
} }
} }
pub fn child(&'syms self) -> Self { pub fn enter_scope(&mut self) {
Self { let new_id = self.tables.len();
parent: Some(self), self.tables.push(SymTable::from(self.current_id));
map: HashMap::new(), self.current_id = new_id;
}
} }
pub fn get(&self, id: u64) -> Option<Sym> { pub fn leave_scope(&mut self) -> Result<(), ()> {
if let Some(sym) = self.map.get(&id) { let parent = self.tables[self.current_id].parent.ok_or(())?;
return Some(sym.clone()); self.current_id = parent;
} Ok(())
if let Some(parent) = self.parent { }
return parent.get(id);
pub fn get(&self, id: u64) -> Option<&Sym> {
self.get_rec(self.current_id, id)
}
fn get_rec(&self, table_id: usize, id: u64) -> Option<&Sym> {
if let Some(sym) = self.tables[table_id].get(id) {
return Some(sym);
} }
if let Some(parent_id) = self.tables[table_id].parent {
return self.get_rec(parent_id, id);
};
None None
} }
pub fn defined_locally(&self, id: u64) -> bool { pub fn defined_locally(&self, id: u64) -> bool {
self.tables[self.current_id].defined(id)
}
pub fn define(&mut self, id: u64, typ: Type) {
self.tables[self.current_id].define(id, typ);
}
pub fn table_id(&self) -> usize {
self.current_id
}
pub fn view(&self, table_id: usize) -> SymView {
SymView {
syms: self,
current_id: table_id,
}
}
}
pub struct SymView<'a> {
syms: &'a Syms,
current_id: usize,
}
impl<'a> SymView<'a> {
pub fn get(&self, id: u64) -> Option<&Sym> {
self.syms.get_rec(self.current_id, id)
}
}
#[derive(Debug)]
struct SymTable {
map: HashMap<u64, Sym>,
parent: Option<usize>,
}
impl SymTable {
pub fn new() -> Self {
Self {
map: HashMap::new(),
parent: None,
}
}
pub fn from(parent: usize) -> Self {
Self {
map: HashMap::new(),
parent: Some(parent),
}
}
pub fn defined(&self, id: u64) -> bool {
self.map.contains_key(&id) self.map.contains_key(&id)
} }
pub fn get(&self, id: u64) -> Option<&Sym> {
self.map.get(&id)
}
pub fn define(&mut self, id: u64, typ: Type) { pub fn define(&mut self, id: u64, typ: Type) {
self.map.insert(id, Sym { id, typ }); self.map.insert(id, Sym { id, typ });
} }