chewker done ^w^
This commit is contained in:
parent
5f41342a16
commit
d55e9b3c70
91
Cargo.lock
generated
91
Cargo.lock
generated
@ -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",
|
||||||
|
]
|
||||||
|
@ -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"
|
||||||
|
@ -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 {
|
||||||
|
395
src/checker.rs
395
src/checker.rs
@ -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 ¶ms {
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -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};
|
||||||
|
|
||||||
|
@ -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!");
|
||||||
|
@ -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();
|
||||||
|
100
src/sym.rs
100
src/sym.rs
@ -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 });
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user