add pos to stuff
This commit is contained in:
parent
bded4e81b1
commit
1331ba1009
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -2,6 +2,12 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "assert_matches"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@ -93,6 +99,7 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
|||||||
name = "yapping"
|
name = "yapping"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"assert_matches",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"rand",
|
"rand",
|
||||||
]
|
]
|
||||||
|
@ -6,5 +6,6 @@ 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]
|
||||||
|
assert_matches = "1.5.0"
|
||||||
pretty_assertions = "1.4.0"
|
pretty_assertions = "1.4.0"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
163
src/checker.rs
163
src/checker.rs
@ -1,11 +1,13 @@
|
|||||||
|
use std::{rc::Rc, sync::Mutex};
|
||||||
|
|
||||||
use rand::random;
|
use rand::random;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
checked::{Node, NodeKind, Type},
|
checked::{Node, NodeKind, Type},
|
||||||
itertewls::Itertewls,
|
|
||||||
parsed,
|
parsed,
|
||||||
|
pos::{Error, ErrorAcc, Pos},
|
||||||
sym::Syms,
|
sym::Syms,
|
||||||
util::hash,
|
util::{hash, Itertewls},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait IdGen {
|
pub trait IdGen {
|
||||||
@ -26,22 +28,25 @@ impl IdGen for RandIdGen {
|
|||||||
pub struct Checker<FnIdGen: IdGen = RandIdGen> {
|
pub struct Checker<FnIdGen: IdGen = RandIdGen> {
|
||||||
syms: Syms,
|
syms: Syms,
|
||||||
fn_id_gen: FnIdGen,
|
fn_id_gen: FnIdGen,
|
||||||
|
error_acc: Rc<Mutex<ErrorAcc>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Checker {
|
impl Checker {
|
||||||
pub fn new() -> Self {
|
pub fn new(error_acc: Rc<Mutex<ErrorAcc>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
syms: Syms::new(),
|
syms: Syms::new(),
|
||||||
fn_id_gen: RandIdGen::new(),
|
fn_id_gen: RandIdGen::new(),
|
||||||
|
error_acc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<FnIdGen: IdGen> Checker<FnIdGen> {
|
impl<FnIdGen: IdGen> Checker<FnIdGen> {
|
||||||
pub fn new_with_fn_id_gen() -> Self {
|
pub fn new_with_fn_id_gen(error_acc: Rc<Mutex<ErrorAcc>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
syms: Syms::new(),
|
syms: Syms::new(),
|
||||||
fn_id_gen: FnIdGen::new(),
|
fn_id_gen: FnIdGen::new(),
|
||||||
|
error_acc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,19 +61,20 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
|
|||||||
|
|
||||||
fn fn_scan(&mut self, ast: &[parsed::Node]) {
|
fn fn_scan(&mut self, ast: &[parsed::Node]) {
|
||||||
for node in ast {
|
for node in ast {
|
||||||
if let parsed::Node::Fn {
|
let pos = node.pos.clone();
|
||||||
|
if let parsed::NodeKind::Fn {
|
||||||
subject,
|
subject,
|
||||||
params,
|
params,
|
||||||
return_typ,
|
return_typ,
|
||||||
body: _,
|
body: _,
|
||||||
} = node
|
} = &node.kind
|
||||||
{
|
{
|
||||||
let Ok(params) = self.fn_scan_params(params) else {
|
let Ok(params) = self.fn_scan_params(¶ms) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(_) = params.iter().map(|(id, _)| *id).find_first_duplicate() {
|
if let Some(_) = params.iter().map(|(id, _)| *id).find_first_duplicate() {
|
||||||
self.error("redefinition param");
|
self.error("redefinition param", pos.clone());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,14 +86,14 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
|
|||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let parsed::Node::Id(id) = subject.as_ref() else { unreachable!() };
|
let parsed::NodeKind::Id(id) = subject.as_ref().kind else { unreachable!() };
|
||||||
|
|
||||||
if self.syms.defined_locally(*id) {
|
if self.syms.defined_locally(id) {
|
||||||
self.error("redefinition fn");
|
self.error("redefinition fn", pos.clone());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let return_typ = self.check_type(return_typ);
|
let return_typ = self.check_type(&return_typ);
|
||||||
|
|
||||||
let typ = Type::Fn {
|
let typ = Type::Fn {
|
||||||
id: self.fn_id_gen.gen(),
|
id: self.fn_id_gen.gen(),
|
||||||
@ -95,7 +101,7 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
|
|||||||
return_typ: Box::new(return_typ),
|
return_typ: Box::new(return_typ),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.syms.define(*id, typ.clone());
|
self.syms.define(id, typ.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,14 +110,14 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
|
|||||||
params
|
params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|param| {
|
.map(|param| {
|
||||||
let parsed::Node::Param { subject, typ } = param else { unreachable!() };
|
let parsed::NodeKind::Param { subject, typ } = ¶m.kind else { unreachable!() };
|
||||||
let parsed::Node::Id(id) = subject.as_ref() else { unreachable!() };
|
let parsed::NodeKind::Id(id) = subject.as_ref().kind else { unreachable!() };
|
||||||
let typ = self.check_type(typ.as_ref().ok_or(())?);
|
let typ = self.check_type(typ.as_ref().ok_or(())?);
|
||||||
Ok((
|
Ok((
|
||||||
*id,
|
id,
|
||||||
self.node(
|
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)),
|
||||||
typ: Some(typ),
|
typ: Some(typ),
|
||||||
},
|
},
|
||||||
Type::Unit,
|
Type::Unit,
|
||||||
@ -122,16 +128,17 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_expr(&mut self, node: &parsed::Node) -> Node {
|
fn check_expr(&mut self, node: &parsed::Node) -> Node {
|
||||||
match node {
|
let pos = node.pos.clone();
|
||||||
parsed::Node::Error => self.node(NodeKind::Error, Type::Unit),
|
match &node.kind {
|
||||||
parsed::Node::Id(id) => {
|
parsed::NodeKind::Error => self.node(NodeKind::Error, Type::Unit),
|
||||||
|
parsed::NodeKind::Id(id) => {
|
||||||
let Some(sym) = self.syms.get(*id) else {
|
let Some(sym) = self.syms.get(*id) else {
|
||||||
self.error("undefined >~<");
|
self.error("undefined >~<", pos.clone());
|
||||||
return self.node(NodeKind::Error, Type::Error);
|
return self.node(NodeKind::Error, Type::Error);
|
||||||
};
|
};
|
||||||
self.node(NodeKind::Id(*id), sym.typ.clone())
|
self.node(NodeKind::Id(*id), sym.typ.clone())
|
||||||
}
|
}
|
||||||
parsed::Node::Int(value) => self.node(
|
parsed::NodeKind::Int(value) => self.node(
|
||||||
NodeKind::Int(*value),
|
NodeKind::Int(*value),
|
||||||
if *value > i32::MAX as i64 {
|
if *value > i32::MAX as i64 {
|
||||||
Type::U32
|
Type::U32
|
||||||
@ -139,13 +146,13 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
|
|||||||
Type::I32
|
Type::I32
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
parsed::Node::Str(value) => self.node(NodeKind::Str(value.clone()), Type::Str),
|
parsed::NodeKind::Str(value) => self.node(NodeKind::Str(value.clone()), Type::Str),
|
||||||
parsed::Node::Group(expr) => {
|
parsed::NodeKind::Group(expr) => {
|
||||||
let expr = self.check_expr(expr);
|
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::NodeKind::Block(stmts) => {
|
||||||
self.syms.enter_scope();
|
self.syms.enter_scope();
|
||||||
let stmts = stmts
|
let stmts = stmts
|
||||||
.iter()
|
.iter()
|
||||||
@ -158,8 +165,8 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
|
|||||||
.unwrap_or(Type::Unit);
|
.unwrap_or(Type::Unit);
|
||||||
self.node(NodeKind::Block(stmts), typ)
|
self.node(NodeKind::Block(stmts), typ)
|
||||||
}
|
}
|
||||||
parsed::Node::Call { subject, args } => {
|
parsed::NodeKind::Call { subject, args } => {
|
||||||
let subject = Box::new(self.check_expr(subject));
|
let subject = Box::new(self.check_expr(&subject));
|
||||||
|
|
||||||
let args = args
|
let args = args
|
||||||
.iter()
|
.iter()
|
||||||
@ -173,7 +180,7 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
|
|||||||
return_typ,
|
return_typ,
|
||||||
} => {
|
} => {
|
||||||
if args.len() != params.len() {
|
if args.len() != params.len() {
|
||||||
self.error("too few/many args");
|
self.error("too few/many args", pos.clone());
|
||||||
break 'br Type::Error;
|
break 'br Type::Error;
|
||||||
}
|
}
|
||||||
if args
|
if args
|
||||||
@ -182,32 +189,32 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
|
|||||||
.map(|(arg, param)| self.compatible(&arg.typ, ¶m))
|
.map(|(arg, param)| self.compatible(&arg.typ, ¶m))
|
||||||
.any(|is_compatible| !is_compatible)
|
.any(|is_compatible| !is_compatible)
|
||||||
{
|
{
|
||||||
self.error("incorrect args");
|
self.error("incorrect args", pos.clone());
|
||||||
break 'br Type::Error;
|
break 'br Type::Error;
|
||||||
}
|
}
|
||||||
*return_typ
|
*return_typ
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.error("not a function");
|
self.error("not a function", pos.clone());
|
||||||
Type::Error
|
Type::Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.node(NodeKind::Call { subject, args }, typ)
|
self.node(NodeKind::Call { subject, args }, typ)
|
||||||
}
|
}
|
||||||
parsed::Node::If {
|
parsed::NodeKind::If {
|
||||||
cond,
|
cond,
|
||||||
truthy,
|
truthy,
|
||||||
falsy,
|
falsy,
|
||||||
} => {
|
} => {
|
||||||
let cond = Box::new(self.check_expr(cond));
|
let cond = Box::new(self.check_expr(&cond));
|
||||||
let truthy = Box::new(self.check_expr(truthy));
|
let truthy = Box::new(self.check_expr(&truthy));
|
||||||
let falsy = falsy.as_ref().map(|block| Box::new(self.check_expr(block)));
|
let falsy = falsy.as_ref().map(|block| Box::new(self.check_expr(block)));
|
||||||
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) => {
|
||||||
if !self.compatible(&truthy.typ, &falsy_typ) {
|
if !self.compatible(&truthy.typ, &falsy_typ) {
|
||||||
self.error("incompatible types #2");
|
self.error("incompatible types #2", pos.clone());
|
||||||
break 'br Type::Error;
|
break 'br Type::Error;
|
||||||
}
|
}
|
||||||
falsy_typ
|
falsy_typ
|
||||||
@ -224,16 +231,16 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
|
|||||||
typ,
|
typ,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
parsed::Node::Loop { body } => {
|
parsed::NodeKind::Loop { body } => {
|
||||||
self.syms.enter_scope();
|
self.syms.enter_scope();
|
||||||
let body = Box::new(self.check_expr(body));
|
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::NodeKind::Break => self.node(NodeKind::Break, Type::Unit),
|
||||||
parsed::Node::Assign { subject, value } => {
|
parsed::NodeKind::Assign { subject, value } => {
|
||||||
let subject = Box::new(self.check_expr(subject));
|
let subject = Box::new(self.check_expr(&subject));
|
||||||
let value = Box::new(self.check_expr(value));
|
let value = Box::new(self.check_expr(&value));
|
||||||
|
|
||||||
match subject.kind {
|
match subject.kind {
|
||||||
NodeKind::Error => {
|
NodeKind::Error => {
|
||||||
@ -241,28 +248,28 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
|
|||||||
}
|
}
|
||||||
NodeKind::Id(_) => {}
|
NodeKind::Id(_) => {}
|
||||||
_ => {
|
_ => {
|
||||||
self.error("cannot assign to expr");
|
self.error("cannot assign to expr", pos.clone());
|
||||||
return self.node(NodeKind::Error, Type::Error);
|
return self.node(NodeKind::Error, Type::Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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", pos.clone());
|
||||||
Type::Error
|
Type::Error
|
||||||
} else {
|
} else {
|
||||||
subject.typ.clone()
|
subject.typ.clone()
|
||||||
};
|
};
|
||||||
self.node(NodeKind::Assign { subject, value }, Type::Unit)
|
self.node(NodeKind::Assign { subject, value }, Type::Unit)
|
||||||
}
|
}
|
||||||
parsed::Node::Let { subject, value } => {
|
parsed::NodeKind::Let { subject, value } => {
|
||||||
let (subject, subject_typ) = match subject.as_ref() {
|
let (subject, subject_typ) = match &subject.as_ref().kind {
|
||||||
parsed::Node::Param { subject, typ } => {
|
parsed::NodeKind::Param { subject, typ } => {
|
||||||
(subject, typ.as_ref().map(|typ| self.check_type(typ)))
|
(subject, typ.as_ref().map(|typ| self.check_type(typ)))
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let value = Box::new(self.check_expr(value));
|
let value = Box::new(self.check_expr(&value));
|
||||||
let typ = value.typ.clone();
|
let typ = value.typ.clone();
|
||||||
|
|
||||||
if subject_typ
|
if subject_typ
|
||||||
@ -270,20 +277,20 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
|
|||||||
.map(|subject_typ| !self.compatible(subject_typ, &typ))
|
.map(|subject_typ| !self.compatible(subject_typ, &typ))
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
self.error("incompatible types #1");
|
self.error("incompatible types #1", pos.clone());
|
||||||
return self.node(NodeKind::Error, Type::Error);
|
return self.node(NodeKind::Error, Type::Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
let subject = match subject.as_ref() {
|
let subject = match subject.as_ref().kind {
|
||||||
parsed::Node::Id(id) => {
|
parsed::NodeKind::Id(id) => {
|
||||||
if self.syms.defined_locally(*id) {
|
if self.syms.defined_locally(id) {
|
||||||
self.error("redefinition");
|
self.error("redefinition", pos.clone());
|
||||||
return self.node(NodeKind::Error, Type::Error);
|
return self.node(NodeKind::Error, Type::Error);
|
||||||
}
|
}
|
||||||
self.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)),
|
||||||
typ: Some(Type::Unit),
|
typ: Some(Type::Unit),
|
||||||
},
|
},
|
||||||
Type::Unit,
|
Type::Unit,
|
||||||
@ -294,21 +301,21 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
|
|||||||
|
|
||||||
self.node(NodeKind::Let { subject, value }, Type::Unit)
|
self.node(NodeKind::Let { subject, value }, Type::Unit)
|
||||||
}
|
}
|
||||||
parsed::Node::Fn {
|
parsed::NodeKind::Fn {
|
||||||
subject,
|
subject,
|
||||||
params,
|
params,
|
||||||
return_typ: _,
|
return_typ: _,
|
||||||
body,
|
body,
|
||||||
} => {
|
} => {
|
||||||
let parsed::Node::Id(id) = subject.as_ref() else { unreachable!() };
|
let parsed::NodeKind::Id(id) = subject.as_ref().kind else { unreachable!() };
|
||||||
|
|
||||||
let Some(sym) = self.syms.get(*id).cloned() else {
|
let Some(sym) = self.syms.get(id).cloned() else {
|
||||||
// rejected in fn scanner
|
// rejected in fn scanner
|
||||||
return self.node(NodeKind::Error,Type::Error);
|
return self.node(NodeKind::Error,Type::Error);
|
||||||
};
|
};
|
||||||
|
|
||||||
let Type::Fn { id: fn_id, params: param_typs, return_typ } = sym.typ else {
|
let Type::Fn { id: fn_id, params: param_typs, return_typ } = sym.typ else {
|
||||||
self.error("redefintion");
|
self.error("redefintion", pos.clone());
|
||||||
return self.node(NodeKind::Error,Type::Error);
|
return self.node(NodeKind::Error,Type::Error);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -318,11 +325,11 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
|
|||||||
.iter()
|
.iter()
|
||||||
.zip(param_typs)
|
.zip(param_typs)
|
||||||
.map(|(param, typ)| {
|
.map(|(param, typ)| {
|
||||||
let parsed::Node::Param { subject, .. } = param else { unreachable!() };
|
let parsed::NodeKind::Param { subject, .. } = ¶m.kind else { unreachable!() };
|
||||||
let parsed::Node::Id(id) = subject.as_ref() else { unreachable!() };
|
let parsed::NodeKind::Id(id) = subject.as_ref().kind else { unreachable!() };
|
||||||
self.node(
|
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)),
|
||||||
typ: Some(typ),
|
typ: Some(typ),
|
||||||
},
|
},
|
||||||
Type::Unit,
|
Type::Unit,
|
||||||
@ -336,17 +343,17 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
|
|||||||
self.syms.define(id, typ.as_ref().cloned().unwrap());
|
self.syms.define(id, typ.as_ref().cloned().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
let body = Box::new(self.check_expr(body));
|
let body = Box::new(self.check_expr(&body));
|
||||||
|
|
||||||
if !self.compatible(&return_typ, &body.typ) {
|
if !self.compatible(&return_typ, &body.typ) {
|
||||||
self.error("return type violated");
|
self.error("return type violated", pos.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.syms.leave_scope().unwrap();
|
self.syms.leave_scope().unwrap();
|
||||||
|
|
||||||
self.node(
|
self.node(
|
||||||
NodeKind::Fn {
|
NodeKind::Fn {
|
||||||
subject: Box::new(self.node(NodeKind::Id(*id), Type::Unit)),
|
subject: Box::new(self.node(NodeKind::Id(id), Type::Unit)),
|
||||||
params,
|
params,
|
||||||
return_typ: *return_typ,
|
return_typ: *return_typ,
|
||||||
body,
|
body,
|
||||||
@ -355,7 +362,7 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
|
|||||||
Type::Unit,
|
Type::Unit,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
parsed::Node::Return { value } => {
|
parsed::NodeKind::Return { value } => {
|
||||||
let value = value.as_ref().map(|value| Box::new(self.check_expr(value)));
|
let value = value.as_ref().map(|value| Box::new(self.check_expr(value)));
|
||||||
let typ = value
|
let typ = value
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@ -363,17 +370,17 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
|
|||||||
.unwrap_or(Type::Unit);
|
.unwrap_or(Type::Unit);
|
||||||
self.node(NodeKind::Return { value }, typ)
|
self.node(NodeKind::Return { value }, typ)
|
||||||
}
|
}
|
||||||
parsed::Node::Param { .. } => unreachable!("handle elsewhere"),
|
parsed::NodeKind::Param { .. } => unreachable!("handle elsewhere"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_type(&self, node: &parsed::Node) -> Type {
|
fn check_type(&self, node: &parsed::Node) -> Type {
|
||||||
match node {
|
match node.kind {
|
||||||
parsed::Node::Error => Type::Error,
|
parsed::NodeKind::Error => Type::Error,
|
||||||
parsed::Node::Id(value) => {
|
parsed::NodeKind::Id(value) => {
|
||||||
if *value == hash("i32") {
|
if value == hash("i32") {
|
||||||
Type::I32
|
Type::I32
|
||||||
} else if *value == hash("u32") {
|
} else if value == hash("u32") {
|
||||||
Type::U32
|
Type::U32
|
||||||
} else {
|
} else {
|
||||||
todo!("symbol lookup idk")
|
todo!("symbol lookup idk")
|
||||||
@ -395,9 +402,13 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error<S: Into<String>>(&mut self, msg: S) {
|
fn error<S: Into<String>>(&mut self, msg: S, pos: Pos) {
|
||||||
let msg = msg.into();
|
let msg = msg.into();
|
||||||
println!("checker error: {msg}");
|
self.error_acc.lock().unwrap().add(Error {
|
||||||
|
kind: crate::pos::ErrorKind::CheckerError,
|
||||||
|
pos: Some(pos),
|
||||||
|
msg,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,7 +432,11 @@ fn test_checker() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let check = |text| Checker::<SeqIdGen>::new_with_fn_id_gen().check(&Parser::new(text).parse());
|
let check = |text| {
|
||||||
|
let error_acc = Rc::new(Mutex::new(ErrorAcc::new()));
|
||||||
|
Checker::<SeqIdGen>::new_with_fn_id_gen(error_acc.clone())
|
||||||
|
.check(&Parser::new(text, error_acc).parse())
|
||||||
|
};
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
check("let a = 5; a;"),
|
check("let a = 5; a;"),
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
enum Duplicate<T: std::hash::Hash> {
|
|
||||||
None(std::collections::HashMap<T, T>),
|
|
||||||
Found(T),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Itertewls<T>
|
|
||||||
where
|
|
||||||
Self: Iterator<Item = T> + Sized,
|
|
||||||
{
|
|
||||||
fn find_first_duplicate(self) -> Option<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, Item> Itertewls<Item> for I
|
|
||||||
where
|
|
||||||
I: Iterator<Item = Item> + Sized,
|
|
||||||
Item: std::cmp::PartialEq + Clone,
|
|
||||||
{
|
|
||||||
fn find_first_duplicate(mut self) -> Option<Item> {
|
|
||||||
self.try_fold(Vec::new(), |mut used, item| {
|
|
||||||
if used.contains(&item) {
|
|
||||||
Err(item)
|
|
||||||
} else {
|
|
||||||
used.push(item);
|
|
||||||
Ok(used)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.err()
|
|
||||||
}
|
|
||||||
}
|
|
99
src/lexer.rs
99
src/lexer.rs
@ -1,22 +1,24 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
|
pos::{Error, ErrorAcc, Pos},
|
||||||
token::{Token, TokenKind, TokenValue},
|
token::{Token, TokenKind, TokenValue},
|
||||||
util::hash,
|
util::hash,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, str::Chars};
|
use std::{collections::HashMap, rc::Rc, str::Chars, sync::Mutex};
|
||||||
|
|
||||||
pub struct Lexer<'a> {
|
pub struct Lexer<'a> {
|
||||||
text: &'a str,
|
text: &'a str,
|
||||||
chars: Chars<'a>,
|
chars: Chars<'a>,
|
||||||
current: Option<char>,
|
current: Option<char>,
|
||||||
index: usize,
|
index: usize,
|
||||||
line: i32,
|
line: i64,
|
||||||
col: i32,
|
col: i64,
|
||||||
symbols: HashMap<u64, String>,
|
symbols: HashMap<u64, String>,
|
||||||
keywords: HashMap<String, TokenKind>,
|
keywords: HashMap<String, TokenKind>,
|
||||||
|
error_acc: Rc<Mutex<ErrorAcc>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Lexer<'a> {
|
impl<'a> Lexer<'a> {
|
||||||
pub fn new(text: &'a str) -> Self {
|
pub fn new(text: &'a str, error_acc: Rc<Mutex<ErrorAcc>>) -> Self {
|
||||||
let mut chars = text.chars();
|
let mut chars = text.chars();
|
||||||
let current = chars.next();
|
let current = chars.next();
|
||||||
Self {
|
Self {
|
||||||
@ -28,6 +30,7 @@ impl<'a> Lexer<'a> {
|
|||||||
col: 1,
|
col: 1,
|
||||||
symbols: HashMap::new(),
|
symbols: HashMap::new(),
|
||||||
keywords: Self::make_keywords(),
|
keywords: Self::make_keywords(),
|
||||||
|
error_acc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,6 +51,7 @@ impl<'a> Lexer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn next_token(&mut self) -> Option<Token> {
|
fn next_token(&mut self) -> Option<Token> {
|
||||||
|
let pos = self.pos();
|
||||||
match self.current {
|
match self.current {
|
||||||
None => None,
|
None => None,
|
||||||
Some(' ' | '\t' | '\n') => {
|
Some(' ' | '\t' | '\n') => {
|
||||||
@ -66,11 +70,11 @@ impl<'a> Lexer<'a> {
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if let Some(kind) = self.keywords.get(&value) {
|
if let Some(kind) = self.keywords.get(&value) {
|
||||||
return self.token(kind.clone());
|
return self.token(kind.clone(), pos);
|
||||||
}
|
}
|
||||||
let id = hash(&value);
|
let id = hash(&value);
|
||||||
self.symbols.insert(id, value);
|
self.symbols.insert(id, value);
|
||||||
break self.token_with_value(TokenKind::Id, TokenValue::Id(id));
|
break self.token_with_value(TokenKind::Id, TokenValue::Id(id), pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,7 +91,11 @@ impl<'a> Lexer<'a> {
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let value = value.replace('_', "").parse::<i64>().unwrap();
|
let value = value.replace('_', "").parse::<i64>().unwrap();
|
||||||
break self.token_with_value(TokenKind::Int, TokenValue::Int(value));
|
break self.token_with_value(
|
||||||
|
TokenKind::Int,
|
||||||
|
TokenValue::Int(value),
|
||||||
|
pos,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,22 +114,25 @@ impl<'a> Lexer<'a> {
|
|||||||
Some('0') => value.push('\0'),
|
Some('0') => value.push('\0'),
|
||||||
Some(ch) => value.push(ch),
|
Some(ch) => value.push(ch),
|
||||||
None => {
|
None => {
|
||||||
self.error("malformed string");
|
self.error("malformed string", pos.clone());
|
||||||
break self.token(TokenKind::Error);
|
break self.token(TokenKind::Error, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some('"') => {
|
Some('"') => {
|
||||||
self.step();
|
self.step();
|
||||||
break self
|
break self.token_with_value(
|
||||||
.token_with_value(TokenKind::Str, TokenValue::Str(value));
|
TokenKind::Str,
|
||||||
|
TokenValue::Str(value),
|
||||||
|
pos,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Some(ch) => {
|
Some(ch) => {
|
||||||
value.push(ch);
|
value.push(ch);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.error("malformed string");
|
self.error("malformed string", pos.clone());
|
||||||
break self.token(TokenKind::Error);
|
break self.token(TokenKind::Error, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.step()
|
self.step()
|
||||||
@ -152,8 +163,8 @@ impl<'a> Lexer<'a> {
|
|||||||
self.step();
|
self.step();
|
||||||
}
|
}
|
||||||
(_, None) => {
|
(_, None) => {
|
||||||
self.error("malformed /**/ comment");
|
self.error("malformed /**/ comment", pos.clone());
|
||||||
break self.token(TokenKind::Error);
|
break self.token(TokenKind::Error, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,7 +177,7 @@ impl<'a> Lexer<'a> {
|
|||||||
match self.current {
|
match self.current {
|
||||||
Some('>') => {
|
Some('>') => {
|
||||||
self.step();
|
self.step();
|
||||||
self.token(TokenKind::MinusLt)
|
self.token(TokenKind::MinusLt, pos)
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
@ -174,21 +185,21 @@ impl<'a> Lexer<'a> {
|
|||||||
Some(ch @ ('0' | '(' | ')' | '{' | '}' | ':' | ',' | ';' | '=')) => {
|
Some(ch @ ('0' | '(' | ')' | '{' | '}' | ':' | ',' | ';' | '=')) => {
|
||||||
self.step();
|
self.step();
|
||||||
match ch {
|
match ch {
|
||||||
'0' => self.token_with_value(TokenKind::Int, TokenValue::Int(0)),
|
'0' => self.token_with_value(TokenKind::Int, TokenValue::Int(0), pos),
|
||||||
'(' => self.token(TokenKind::LParen),
|
'(' => self.token(TokenKind::LParen, pos),
|
||||||
')' => self.token(TokenKind::RParen),
|
')' => self.token(TokenKind::RParen, pos),
|
||||||
'{' => self.token(TokenKind::LBrace),
|
'{' => self.token(TokenKind::LBrace, pos),
|
||||||
'}' => self.token(TokenKind::RBrace),
|
'}' => self.token(TokenKind::RBrace, pos),
|
||||||
':' => self.token(TokenKind::Colon),
|
':' => self.token(TokenKind::Colon, pos),
|
||||||
',' => self.token(TokenKind::Comma),
|
',' => self.token(TokenKind::Comma, pos),
|
||||||
';' => self.token(TokenKind::Semicolon),
|
';' => self.token(TokenKind::Semicolon, pos),
|
||||||
'=' => self.token(TokenKind::Equal),
|
'=' => self.token(TokenKind::Equal, pos),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(ch) => {
|
Some(ch) => {
|
||||||
self.error(format!("unknown char '{ch}'"));
|
self.error(format!("unknown char '{ch}'"), pos.clone());
|
||||||
self.token(TokenKind::Error)
|
self.token(TokenKind::Error, pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,29 +221,33 @@ impl<'a> Lexer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn token(&self, kind: TokenKind) -> Option<Token> {
|
fn token(&self, kind: TokenKind, pos: Pos) -> Option<Token> {
|
||||||
Some(Token {
|
Some(Token {
|
||||||
kind,
|
kind,
|
||||||
value: TokenValue::None,
|
value: TokenValue::None,
|
||||||
index: self.index,
|
pos,
|
||||||
line: self.line,
|
|
||||||
col: self.col,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn token_with_value(&self, kind: TokenKind, value: TokenValue) -> Option<Token> {
|
fn token_with_value(&self, kind: TokenKind, value: TokenValue, pos: Pos) -> Option<Token> {
|
||||||
Some(Token {
|
Some(Token { kind, value, pos })
|
||||||
kind,
|
|
||||||
value,
|
|
||||||
index: self.index,
|
|
||||||
line: self.line,
|
|
||||||
col: self.col,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error<S: Into<String>>(&mut self, msg: S) {
|
fn error<S: Into<String>>(&mut self, msg: S, pos: Pos) {
|
||||||
let msg = msg.into();
|
let msg = msg.into();
|
||||||
println!("lexer error: {msg}, line {}", self.line)
|
self.error_acc.lock().unwrap().add(Error {
|
||||||
|
kind: crate::pos::ErrorKind::LexerError,
|
||||||
|
pos: Some(pos),
|
||||||
|
msg,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pos(&self) -> Pos {
|
||||||
|
Pos {
|
||||||
|
index: self.index,
|
||||||
|
line: self.line,
|
||||||
|
col: self.col,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn done(&self) -> bool {
|
fn done(&self) -> bool {
|
||||||
@ -254,7 +269,7 @@ fn test_lexer() {
|
|||||||
use TokenValue as TV;
|
use TokenValue as TV;
|
||||||
|
|
||||||
let lex = |text| {
|
let lex = |text| {
|
||||||
Lexer::new(text)
|
Lexer::new(text, Rc::new(Mutex::new(ErrorAcc::new())))
|
||||||
.map(|token| (token.kind, token.value))
|
.map(|token| (token.kind, token.value))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
};
|
};
|
||||||
|
@ -2,16 +2,15 @@
|
|||||||
|
|
||||||
mod checked;
|
mod checked;
|
||||||
mod checker;
|
mod checker;
|
||||||
mod ir;
|
mod hir;
|
||||||
mod ir_compiler;
|
mod hir_compiler;
|
||||||
mod itertewls;
|
|
||||||
mod lexer;
|
mod lexer;
|
||||||
mod parsed;
|
mod parsed;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
mod pos;
|
||||||
mod sym;
|
mod sym;
|
||||||
mod token;
|
mod token;
|
||||||
mod util;
|
mod util;
|
||||||
mod vm;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Hello, world!");
|
println!("Hello, world!");
|
||||||
|
@ -1,5 +1,19 @@
|
|||||||
|
use crate::pos::Pos;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub enum Node {
|
pub struct Node {
|
||||||
|
pub kind: NodeKind,
|
||||||
|
pub pos: Pos,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node {
|
||||||
|
pub fn new(kind: NodeKind, pos: Pos) -> Self {
|
||||||
|
Self { kind, pos }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
pub enum NodeKind {
|
||||||
Error,
|
Error,
|
||||||
Id(u64),
|
Id(u64),
|
||||||
Int(i64),
|
Int(i64),
|
||||||
|
459
src/parser.rs
459
src/parser.rs
@ -1,21 +1,27 @@
|
|||||||
use std::collections::HashMap;
|
use std::{collections::HashMap, rc::Rc, sync::Mutex};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
lexer::Lexer,
|
lexer::Lexer,
|
||||||
parsed::Node,
|
parsed::{Node, NodeKind},
|
||||||
|
pos::{Error, ErrorAcc, Pos},
|
||||||
token::{Token, TokenKind, TokenValue},
|
token::{Token, TokenKind, TokenValue},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Parser<'a> {
|
pub struct Parser<'a> {
|
||||||
lexer: Lexer<'a>,
|
lexer: Lexer<'a>,
|
||||||
current: Option<Token>,
|
current: Option<Token>,
|
||||||
|
error_acc: Rc<Mutex<ErrorAcc>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Parser<'a> {
|
impl<'a> Parser<'a> {
|
||||||
pub fn new(text: &'a str) -> Self {
|
pub fn new(text: &'a str, error_acc: Rc<Mutex<ErrorAcc>>) -> Self {
|
||||||
let mut lexer = Lexer::new(text);
|
let mut lexer = Lexer::new(text, error_acc.clone());
|
||||||
let current = lexer.next();
|
let current = lexer.next();
|
||||||
Self { lexer, current }
|
Self {
|
||||||
|
lexer,
|
||||||
|
current,
|
||||||
|
error_acc,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(&mut self) -> Vec<Node> {
|
pub fn parse(&mut self) -> Vec<Node> {
|
||||||
@ -37,6 +43,7 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_stmt(&mut self) -> Node {
|
fn parse_stmt(&mut self) -> Node {
|
||||||
|
let pos = self.pos().unwrap();
|
||||||
match self.curr_kind() {
|
match self.curr_kind() {
|
||||||
Some(TokenKind::LBrace) => self.parse_block(),
|
Some(TokenKind::LBrace) => self.parse_block(),
|
||||||
Some(TokenKind::If) => self.parse_if(),
|
Some(TokenKind::If) => self.parse_if(),
|
||||||
@ -47,7 +54,7 @@ impl<'a> Parser<'a> {
|
|||||||
Some(TokenKind::Let) => self.parse_let(),
|
Some(TokenKind::Let) => self.parse_let(),
|
||||||
Some(TokenKind::Break) => {
|
Some(TokenKind::Break) => {
|
||||||
self.step();
|
self.step();
|
||||||
Node::Break
|
self.node(NodeKind::Break, pos.clone())
|
||||||
}
|
}
|
||||||
Some(TokenKind::Return) => {
|
Some(TokenKind::Return) => {
|
||||||
self.step();
|
self.step();
|
||||||
@ -55,7 +62,7 @@ impl<'a> Parser<'a> {
|
|||||||
Some(TokenKind::Semicolon) => None,
|
Some(TokenKind::Semicolon) => None,
|
||||||
_ => Some(Box::new(self.parse_expr())),
|
_ => Some(Box::new(self.parse_expr())),
|
||||||
};
|
};
|
||||||
Node::Return { value }
|
self.node(NodeKind::Return { value }, pos.clone())
|
||||||
}
|
}
|
||||||
_ => self.parse_assign(),
|
_ => self.parse_assign(),
|
||||||
};
|
};
|
||||||
@ -65,8 +72,8 @@ impl<'a> Parser<'a> {
|
|||||||
stmt
|
stmt
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.error("expected ';'");
|
self.error("expected ';'", pos.clone());
|
||||||
Node::Error
|
self.error_node(pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,85 +81,95 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_fn(&mut self) -> Node {
|
fn parse_fn(&mut self) -> Node {
|
||||||
|
let pos = self.pos().unwrap();
|
||||||
self.step();
|
self.step();
|
||||||
if !self.curr_is(TokenKind::Id) {
|
if !self.curr_is(TokenKind::Id) {
|
||||||
self.error("expected id");
|
self.error("expected id", pos.clone());
|
||||||
return Node::Error;
|
return self.error_node(pos);
|
||||||
}
|
}
|
||||||
let subject = Box::new(self.parse_id());
|
let subject = Box::new(self.parse_id());
|
||||||
if !self.curr_is(TokenKind::LParen) {
|
if !self.curr_is(TokenKind::LParen) {
|
||||||
self.error("expected '('");
|
self.error("expected '('", pos.clone());
|
||||||
return Node::Error;
|
return self.error_node(pos);
|
||||||
}
|
}
|
||||||
let params = match self.parse_fn_params() {
|
let params = match self.parse_fn_params() {
|
||||||
Ok(params) => params,
|
Ok(params) => params,
|
||||||
Err(expr) => return expr,
|
Err(expr) => return expr,
|
||||||
};
|
};
|
||||||
if !self.curr_is(TokenKind::MinusLt) {
|
if !self.curr_is(TokenKind::MinusLt) {
|
||||||
self.error("expected '->'");
|
self.error("expected '->'", pos.clone());
|
||||||
return Node::Error;
|
return self.error_node(pos);
|
||||||
}
|
}
|
||||||
self.step();
|
self.step();
|
||||||
let return_typ = Box::new(self.parse_typ());
|
let return_typ = Box::new(self.parse_typ());
|
||||||
if !self.curr_is(TokenKind::LBrace) {
|
if !self.curr_is(TokenKind::LBrace) {
|
||||||
self.error("expected '{'");
|
self.error("expected '{'", pos.clone());
|
||||||
return Node::Error;
|
return self.error_node(pos);
|
||||||
}
|
}
|
||||||
let body = Box::new(self.parse_block());
|
let body = Box::new(self.parse_block());
|
||||||
Node::Fn {
|
self.node(
|
||||||
|
NodeKind::Fn {
|
||||||
subject,
|
subject,
|
||||||
params,
|
params,
|
||||||
return_typ,
|
return_typ,
|
||||||
body,
|
body,
|
||||||
}
|
},
|
||||||
|
pos,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_fn_params(&mut self) -> Result<Vec<Node>, Node> {
|
fn parse_fn_params(&mut self) -> Result<Vec<Node>, Node> {
|
||||||
|
let pos = self.pos().unwrap();
|
||||||
self.step();
|
self.step();
|
||||||
let mut params = Vec::new();
|
let mut params = Vec::new();
|
||||||
if !self.curr_is(TokenKind::RParen) {
|
if !self.curr_is(TokenKind::RParen) {
|
||||||
if !self.curr_is(TokenKind::Id) {
|
if !self.curr_is(TokenKind::Id) {
|
||||||
self.error("expected id");
|
self.error("expected id", pos.clone());
|
||||||
return Err(Node::Error);
|
return Err(self.error_node(pos));
|
||||||
}
|
}
|
||||||
params.push(self.parse_param());
|
params.push(self.parse_param());
|
||||||
while let Some(TokenKind::Comma) = self.curr_kind() {
|
while let Some(TokenKind::Comma) = self.curr_kind() {
|
||||||
self.step();
|
self.step();
|
||||||
if self.curr_is(TokenKind::RParen) {
|
if self.curr_is(TokenKind::RParen) {
|
||||||
self.error("expected ')'");
|
self.error("expected ')'", pos.clone());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
params.push(self.parse_param());
|
params.push(self.parse_param());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !self.curr_is(TokenKind::RParen) {
|
if !self.curr_is(TokenKind::RParen) {
|
||||||
self.error("expected ')'");
|
self.error("expected ')'", pos.clone());
|
||||||
return Err(Node::Error);
|
return Err(self.error_node(pos));
|
||||||
}
|
}
|
||||||
self.step();
|
self.step();
|
||||||
Ok(params)
|
Ok(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_let(&mut self) -> Node {
|
fn parse_let(&mut self) -> Node {
|
||||||
|
let pos = self.pos().unwrap();
|
||||||
self.step();
|
self.step();
|
||||||
if !self.curr_is(TokenKind::Id) {
|
if !self.curr_is(TokenKind::Id) {
|
||||||
self.error("expected id");
|
self.error("expected id", pos.clone());
|
||||||
return Node::Error;
|
return self.error_node(pos);
|
||||||
}
|
}
|
||||||
let subject = self.parse_param();
|
let subject = self.parse_param();
|
||||||
if !self.curr_is(TokenKind::Equal) {
|
if !self.curr_is(TokenKind::Equal) {
|
||||||
self.error("expected '='");
|
self.error("expected '='", pos.clone());
|
||||||
return Node::Error;
|
return self.error_node(pos);
|
||||||
}
|
}
|
||||||
self.step();
|
self.step();
|
||||||
let value = self.parse_expr();
|
let value = self.parse_expr();
|
||||||
Node::Let {
|
self.node(
|
||||||
|
NodeKind::Let {
|
||||||
subject: Box::new(subject),
|
subject: Box::new(subject),
|
||||||
value: Box::new(value),
|
value: Box::new(value),
|
||||||
}
|
},
|
||||||
|
pos,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_param(&mut self) -> Node {
|
fn parse_param(&mut self) -> Node {
|
||||||
|
let pos = self.pos().unwrap();
|
||||||
let subject = Box::new(self.parse_id());
|
let subject = Box::new(self.parse_id());
|
||||||
let typ = if let Some(TokenKind::Colon) = self.curr_kind() {
|
let typ = if let Some(TokenKind::Colon) = self.curr_kind() {
|
||||||
self.step();
|
self.step();
|
||||||
@ -160,30 +177,35 @@ impl<'a> Parser<'a> {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
Node::Param { subject, typ }
|
self.node(NodeKind::Param { subject, typ }, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_typ(&mut self) -> Node {
|
fn parse_typ(&mut self) -> Node {
|
||||||
|
let pos = self.pos().unwrap();
|
||||||
match self.curr_kind() {
|
match self.curr_kind() {
|
||||||
Some(TokenKind::Id) => self.parse_id(),
|
Some(TokenKind::Id) => self.parse_id(),
|
||||||
_ => {
|
_ => {
|
||||||
self.error("expected type");
|
self.error("expected type", pos.clone());
|
||||||
self.step();
|
self.step();
|
||||||
Node::Error
|
self.error_node(pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_assign(&mut self) -> Node {
|
fn parse_assign(&mut self) -> Node {
|
||||||
|
let pos = self.pos().unwrap();
|
||||||
let subject = self.parse_expr();
|
let subject = self.parse_expr();
|
||||||
match self.curr_kind() {
|
match self.curr_kind() {
|
||||||
Some(TokenKind::Equal) => {
|
Some(TokenKind::Equal) => {
|
||||||
self.step();
|
self.step();
|
||||||
let value = self.parse_expr();
|
let value = self.parse_expr();
|
||||||
Node::Assign {
|
self.node(
|
||||||
|
NodeKind::Assign {
|
||||||
subject: Box::new(subject),
|
subject: Box::new(subject),
|
||||||
value: Box::new(value),
|
value: Box::new(value),
|
||||||
}
|
},
|
||||||
|
pos,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
_ => subject,
|
_ => subject,
|
||||||
}
|
}
|
||||||
@ -194,6 +216,7 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_call(&mut self) -> Node {
|
fn parse_call(&mut self) -> Node {
|
||||||
|
let pos = self.pos().unwrap();
|
||||||
let mut subject = self.parse_value();
|
let mut subject = self.parse_value();
|
||||||
loop {
|
loop {
|
||||||
match self.curr_kind() {
|
match self.curr_kind() {
|
||||||
@ -216,15 +239,18 @@ impl<'a> Parser<'a> {
|
|||||||
match self.curr_kind() {
|
match self.curr_kind() {
|
||||||
Some(TokenKind::RParen) => {}
|
Some(TokenKind::RParen) => {}
|
||||||
_ => {
|
_ => {
|
||||||
self.error("expected ')'");
|
self.error("expected ')'", pos.clone());
|
||||||
return Node::Error;
|
return self.error_node(pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.step();
|
self.step();
|
||||||
subject = Node::Call {
|
subject = self.node(
|
||||||
|
NodeKind::Call {
|
||||||
subject: Box::new(subject),
|
subject: Box::new(subject),
|
||||||
args,
|
args,
|
||||||
};
|
},
|
||||||
|
pos.clone(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
_ => break subject,
|
_ => break subject,
|
||||||
}
|
}
|
||||||
@ -232,6 +258,7 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_value(&mut self) -> Node {
|
fn parse_value(&mut self) -> Node {
|
||||||
|
let pos = self.pos().unwrap();
|
||||||
match self.curr_kind() {
|
match self.curr_kind() {
|
||||||
Some(TokenKind::Id) => self.parse_id(),
|
Some(TokenKind::Id) => self.parse_id(),
|
||||||
Some(TokenKind::Int) => self.parse_int(),
|
Some(TokenKind::Int) => self.parse_int(),
|
||||||
@ -241,14 +268,15 @@ impl<'a> Parser<'a> {
|
|||||||
Some(TokenKind::If) => self.parse_if(),
|
Some(TokenKind::If) => self.parse_if(),
|
||||||
Some(TokenKind::Loop) => self.parse_loop(),
|
Some(TokenKind::Loop) => self.parse_loop(),
|
||||||
_ => {
|
_ => {
|
||||||
self.error("expected value");
|
self.error("expected value", pos.clone());
|
||||||
self.step();
|
self.step();
|
||||||
Node::Error
|
self.error_node(pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_id(&mut self) -> Node {
|
fn parse_id(&mut self) -> Node {
|
||||||
|
let pos = self.pos().unwrap();
|
||||||
let Some(Token {
|
let Some(Token {
|
||||||
kind: TokenKind::Id,
|
kind: TokenKind::Id,
|
||||||
value: TokenValue::Id(value),
|
value: TokenValue::Id(value),
|
||||||
@ -258,10 +286,11 @@ impl<'a> Parser<'a> {
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
self.step();
|
self.step();
|
||||||
Node::Id(value)
|
self.node(NodeKind::Id(value), pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_int(&mut self) -> Node {
|
fn parse_int(&mut self) -> Node {
|
||||||
|
let pos = self.pos().unwrap();
|
||||||
let Some(Token {
|
let Some(Token {
|
||||||
kind: TokenKind::Int,
|
kind: TokenKind::Int,
|
||||||
value: TokenValue::Int(value),
|
value: TokenValue::Int(value),
|
||||||
@ -271,10 +300,11 @@ impl<'a> Parser<'a> {
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
self.step();
|
self.step();
|
||||||
Node::Int(value)
|
self.node(NodeKind::Int(value), pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_string(&mut self) -> Node {
|
fn parse_string(&mut self) -> Node {
|
||||||
|
let pos = self.pos().unwrap();
|
||||||
let Some(Token {
|
let Some(Token {
|
||||||
kind: TokenKind::Str,
|
kind: TokenKind::Str,
|
||||||
value: TokenValue::Str(value),
|
value: TokenValue::Str(value),
|
||||||
@ -284,32 +314,34 @@ impl<'a> Parser<'a> {
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
self.step();
|
self.step();
|
||||||
Node::Str(value.clone())
|
self.node(NodeKind::Str(value.clone()), pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_group(&mut self) -> Node {
|
fn parse_group(&mut self) -> Node {
|
||||||
|
let pos = self.pos().unwrap();
|
||||||
self.step();
|
self.step();
|
||||||
let expr = Box::new(self.parse_expr());
|
let expr = Box::new(self.parse_expr());
|
||||||
if !self.curr_is(TokenKind::RParen) {
|
if !self.curr_is(TokenKind::RParen) {
|
||||||
self.error("expected ')'");
|
self.error("expected ')'", pos.clone());
|
||||||
return Node::Error;
|
return self.error_node(pos);
|
||||||
}
|
}
|
||||||
self.step();
|
self.step();
|
||||||
Node::Group(expr)
|
self.node(NodeKind::Group(expr), pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_block(&mut self) -> Node {
|
fn parse_block(&mut self) -> Node {
|
||||||
|
let pos = self.pos().unwrap();
|
||||||
self.step();
|
self.step();
|
||||||
let mut stmts = Vec::new();
|
let mut stmts = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
match self.curr_kind() {
|
match self.curr_kind() {
|
||||||
None => {
|
None => {
|
||||||
self.error("expected ')'");
|
self.error("expected ')'", pos.clone());
|
||||||
break Node::Error;
|
break self.error_node(pos);
|
||||||
}
|
}
|
||||||
Some(TokenKind::RBrace) => {
|
Some(TokenKind::RBrace) => {
|
||||||
self.step();
|
self.step();
|
||||||
break Node::Block(stmts);
|
break self.node(NodeKind::Block(stmts), pos);
|
||||||
}
|
}
|
||||||
_ => stmts.push(self.parse_stmt()),
|
_ => stmts.push(self.parse_stmt()),
|
||||||
}
|
}
|
||||||
@ -317,56 +349,74 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_if(&mut self) -> Node {
|
fn parse_if(&mut self) -> Node {
|
||||||
|
let pos = self.pos().unwrap();
|
||||||
self.step();
|
self.step();
|
||||||
let cond = Box::new(self.parse_expr());
|
let cond = Box::new(self.parse_expr());
|
||||||
if !self.curr_is(TokenKind::LBrace) {
|
if !self.curr_is(TokenKind::LBrace) {
|
||||||
self.error("expected '}'");
|
self.error("expected '}'", pos.clone());
|
||||||
return Node::Error;
|
return self.error_node(pos);
|
||||||
}
|
}
|
||||||
let truthy = Box::new(self.parse_block());
|
let truthy = Box::new(self.parse_block());
|
||||||
let falsy = match self.curr_kind() {
|
let falsy = match self.curr_kind() {
|
||||||
Some(TokenKind::Else) => {
|
Some(TokenKind::Else) => {
|
||||||
self.step();
|
self.step();
|
||||||
if !self.curr_is(TokenKind::LBrace) {
|
if !self.curr_is(TokenKind::LBrace) {
|
||||||
self.error("expected '}'");
|
self.error("expected '}'", pos.clone());
|
||||||
return Node::Error;
|
return self.error_node(pos);
|
||||||
}
|
}
|
||||||
Some(Box::new(self.parse_block()))
|
Some(Box::new(self.parse_block()))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
Node::If {
|
self.node(
|
||||||
|
NodeKind::If {
|
||||||
cond,
|
cond,
|
||||||
truthy,
|
truthy,
|
||||||
falsy,
|
falsy,
|
||||||
}
|
},
|
||||||
|
pos,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_loop(&mut self) -> Node {
|
fn parse_loop(&mut self) -> Node {
|
||||||
|
let pos = self.pos().unwrap();
|
||||||
self.step();
|
self.step();
|
||||||
if !self.curr_is(TokenKind::LBrace) {
|
if !self.curr_is(TokenKind::LBrace) {
|
||||||
self.error("expected '}'");
|
self.error("expected '}'", pos.clone());
|
||||||
return Node::Error;
|
return self.error_node(pos);
|
||||||
}
|
}
|
||||||
let body = Box::new(self.parse_block());
|
let body = Box::new(self.parse_block());
|
||||||
Node::Loop { body }
|
self.node(NodeKind::Loop { body }, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error<S: Into<String>>(&mut self, msg: S) {
|
fn error<S: Into<String>>(&mut self, msg: S, pos: Pos) {
|
||||||
let msg = msg.into();
|
let msg = msg.into();
|
||||||
println!(
|
self.error_acc.lock().unwrap().add(Error {
|
||||||
"parser error: {msg}, line {}",
|
kind: crate::pos::ErrorKind::ParserError,
|
||||||
self.current
|
pos: Some(pos),
|
||||||
.as_ref()
|
msg,
|
||||||
.map(|t| t.line.to_string())
|
});
|
||||||
.unwrap_or_else(|| "-".to_string())
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn step(&mut self) {
|
fn step(&mut self) {
|
||||||
self.current = self.lexer.next();
|
self.current = self.lexer.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn node(&self, kind: NodeKind, pos: Pos) -> Node {
|
||||||
|
Node { kind, pos }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn error_node(&self, pos: Pos) -> Node {
|
||||||
|
Node {
|
||||||
|
kind: NodeKind::Error,
|
||||||
|
pos,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pos(&self) -> Option<Pos> {
|
||||||
|
self.current.as_ref().map(|token| token.pos.clone())
|
||||||
|
}
|
||||||
|
|
||||||
fn curr_is(&self, kind: TokenKind) -> bool {
|
fn curr_is(&self, kind: TokenKind) -> bool {
|
||||||
self.curr_kind() == Some(kind)
|
self.curr_kind() == Some(kind)
|
||||||
}
|
}
|
||||||
@ -379,100 +429,223 @@ impl<'a> Parser<'a> {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_parser() {
|
fn test_parser() {
|
||||||
use crate::util::hash;
|
use crate::util::hash;
|
||||||
use Node::*;
|
use assert_matches::assert_matches;
|
||||||
|
// use pretty_assertions::assert_eq;
|
||||||
|
use NodeKind::*;
|
||||||
|
|
||||||
let parse = |text| Parser::new(text).parse();
|
macro_rules! node {
|
||||||
|
($kind:pat) => {
|
||||||
|
Node { kind: $kind, .. }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let parse = |text| Parser::new(text, Rc::new(Mutex::new(ErrorAcc::new()))).parse();
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn B<T>(v: T) -> Box<T> {
|
fn B<T>(v: T) -> Box<T> {
|
||||||
Box::new(v)
|
Box::new(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(Parser::new("abc;").parse(), vec![Id(hash("abc"))]);
|
assert_matches!(parse("abc;")[..], [node!(Id(id))] if id == hash("abc"));
|
||||||
assert_eq!(Parser::new("123;").parse(), vec![Int(123)]);
|
assert_matches!(parse("123;")[..], [node!(Int(123))]);
|
||||||
assert_eq!(
|
assert_matches!(&parse("\"hello\";")[..], [node!(Str(v))] if *v == "hello".to_string());
|
||||||
Parser::new("\"hello\";").parse(),
|
assert_matches!(parse("0;")[..], [node!(Int(0))]);
|
||||||
vec![Str("hello".to_string())]
|
assert_matches!(parse("0;abc;")[..], [node!(Int(0)), node!(Id(id))] if id == hash("abc"));
|
||||||
);
|
|
||||||
assert_eq!(Parser::new("0;").parse(), vec![Int(0)]);
|
|
||||||
assert_eq!(Parser::new("0;abc;").parse(), vec![Int(0), Id(hash("abc"))]);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse("add(mul(12, 34), 56);"),
|
parse("add(mul(12, 34), 56);"),
|
||||||
vec![Call {
|
vec![Node {
|
||||||
subject: B(Id(hash("add"))),
|
kind: Call {
|
||||||
args: vec![
|
subject: B(Node {
|
||||||
Call {
|
kind: Id(hash("add")),
|
||||||
subject: B(Id(hash("mul"))),
|
pos: Pos {
|
||||||
args: vec![Int(12), Int(34)]
|
index: 0,
|
||||||
},
|
line: 1,
|
||||||
Int(56)
|
col: 1
|
||||||
]
|
}
|
||||||
}]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
parse("a = 123;"),
|
|
||||||
vec![Assign {
|
|
||||||
subject: B(Id(hash("a"))),
|
|
||||||
value: B(Int(123))
|
|
||||||
}]
|
|
||||||
);
|
|
||||||
assert_eq!(parse("break;"), vec![Break]);
|
|
||||||
assert_eq!(parse("return;"), vec![Return { value: None }]);
|
|
||||||
assert_eq!(
|
|
||||||
parse("return add(1, 2);"),
|
|
||||||
vec![Return {
|
|
||||||
value: Some(B(Call {
|
|
||||||
subject: B(Id(hash("add"))),
|
|
||||||
args: vec![Int(1), Int(2)]
|
|
||||||
}))
|
|
||||||
}]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
parse("a = 5;"),
|
|
||||||
vec![Assign {
|
|
||||||
subject: B(Id(hash("a"))),
|
|
||||||
value: B(Int(5))
|
|
||||||
}]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
parse("let a = 5;"),
|
|
||||||
vec![Let {
|
|
||||||
subject: B(Param {
|
|
||||||
subject: B(Id(hash("a"))),
|
|
||||||
typ: None
|
|
||||||
}),
|
}),
|
||||||
value: B(Int(5))
|
args: vec![
|
||||||
|
Node {
|
||||||
|
kind: Call {
|
||||||
|
subject: B(Node {
|
||||||
|
kind: Id(14581412793212634142),
|
||||||
|
pos: Pos {
|
||||||
|
index: 4,
|
||||||
|
line: 1,
|
||||||
|
col: 5
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
args: vec![
|
||||||
|
Node {
|
||||||
|
kind: Int(12),
|
||||||
|
pos: Pos {
|
||||||
|
index: 8,
|
||||||
|
line: 1,
|
||||||
|
col: 9
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Node {
|
||||||
|
kind: Int(34),
|
||||||
|
pos: Pos {
|
||||||
|
index: 12,
|
||||||
|
line: 1,
|
||||||
|
col: 13
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
pos: Pos {
|
||||||
|
index: 4,
|
||||||
|
line: 1,
|
||||||
|
col: 5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Node {
|
||||||
|
kind: Int(56),
|
||||||
|
pos: Pos {
|
||||||
|
index: 17,
|
||||||
|
line: 1,
|
||||||
|
col: 18
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
pos: Pos {
|
||||||
|
index: 0,
|
||||||
|
line: 1,
|
||||||
|
col: 1
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
|
assert_matches!(
|
||||||
|
&parse("a = 123;")[..],
|
||||||
|
[node!(Assign {
|
||||||
|
subject,
|
||||||
|
value
|
||||||
|
})] if matches!(subject.kind, Id(id) if id == hash("a")) && matches!(value.kind, Int(123))
|
||||||
|
);
|
||||||
|
assert_matches!(parse("break;")[..], [node!(Break)]);
|
||||||
|
assert_matches!(parse("return;")[..], [node!(Return { value: None })]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse("fn test() -> i32 {}"),
|
parse("return add(1, 2);")[..],
|
||||||
vec![Fn {
|
vec![Node {
|
||||||
subject: B(Id(hash("test"))),
|
kind: Return {
|
||||||
params: vec![],
|
value: Some(B(Node {
|
||||||
return_typ: B(Id(hash("i32"))),
|
kind: Call {
|
||||||
body: B(Block(vec![]))
|
subject: B(Node {
|
||||||
|
kind: Id(hash("add")),
|
||||||
|
pos: Pos {
|
||||||
|
index: 7,
|
||||||
|
line: 1,
|
||||||
|
col: 8
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
args: vec![
|
||||||
|
Node {
|
||||||
|
kind: Int(1),
|
||||||
|
pos: Pos {
|
||||||
|
index: 11,
|
||||||
|
line: 1,
|
||||||
|
col: 12
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Node {
|
||||||
|
kind: Int(2),
|
||||||
|
pos: Pos {
|
||||||
|
index: 14,
|
||||||
|
line: 1,
|
||||||
|
col: 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
pos: Pos {
|
||||||
|
index: 7,
|
||||||
|
line: 1,
|
||||||
|
col: 8
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
pos: Pos {
|
||||||
|
index: 0,
|
||||||
|
line: 1,
|
||||||
|
col: 1
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
|
assert_matches!(
|
||||||
|
&parse("a = 5;")[..],
|
||||||
|
[node!(Assign {
|
||||||
|
subject,
|
||||||
|
value
|
||||||
|
})] if matches!(subject.kind, Id(id) if id == hash("a")) && matches!(value.kind, Int(5))
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse("if 0 {}"),
|
parse("let a = 5;")[..],
|
||||||
vec![If {
|
vec![Node {
|
||||||
cond: B(Int(0)),
|
kind: Let {
|
||||||
truthy: B(Block(vec![])),
|
subject: B(Node {
|
||||||
|
kind: Param {
|
||||||
|
subject: B(Node {
|
||||||
|
kind: Id(hash("a")),
|
||||||
|
pos: Pos {
|
||||||
|
index: 4,
|
||||||
|
line: 1,
|
||||||
|
col: 5
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
typ: None
|
||||||
|
},
|
||||||
|
pos: Pos {
|
||||||
|
index: 4,
|
||||||
|
line: 1,
|
||||||
|
col: 5
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
value: B(Node {
|
||||||
|
kind: Int(5),
|
||||||
|
pos: Pos {
|
||||||
|
index: 8,
|
||||||
|
line: 1,
|
||||||
|
col: 9
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
pos: Pos {
|
||||||
|
index: 0,
|
||||||
|
line: 1,
|
||||||
|
col: 1
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
assert_matches!(
|
||||||
|
&parse("fn test() -> i32 {}")[..],
|
||||||
|
[node!(Fn {
|
||||||
|
subject,
|
||||||
|
params,
|
||||||
|
return_typ,
|
||||||
|
body
|
||||||
|
})] if subject.kind == Id(hash("test")) && *params == vec![] && return_typ.kind == Id(hash("i32")) && body.kind == Block(vec![])
|
||||||
|
);
|
||||||
|
assert_matches!(
|
||||||
|
&parse("if 0 {}")[..],
|
||||||
|
[node!(If {
|
||||||
|
cond,
|
||||||
|
truthy,
|
||||||
falsy: None
|
falsy: None
|
||||||
}]
|
})] if matches!(cond.kind, Int(0)) && truthy.kind == Block(vec![])
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_matches!(
|
||||||
parse("if 0 {} else {}"),
|
&parse("if 0 {} else {}")[..],
|
||||||
vec![If {
|
[node!(If {
|
||||||
cond: B(Int(0)),
|
cond,
|
||||||
truthy: B(Block(vec![])),
|
truthy,
|
||||||
falsy: Some(B(Block(vec![]))),
|
falsy: Some(falsy),
|
||||||
}]
|
})] if matches!(cond.kind, Int(0)) && truthy.kind == Block(vec![]) && falsy.kind == Block(vec![])
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_matches!(
|
||||||
parse("loop {}"),
|
&parse("loop {}")[..],
|
||||||
vec![Loop {
|
[node!(Loop {
|
||||||
body: B(Block(vec![])),
|
body,
|
||||||
}]
|
})] if body.kind == Block(vec![])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
44
src/pos.rs
Normal file
44
src/pos.rs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
pub struct Pos {
|
||||||
|
pub index: usize,
|
||||||
|
pub line: i64,
|
||||||
|
pub col: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pos {
|
||||||
|
pub fn new(index: usize, line: i64, col: i64) -> Self {
|
||||||
|
Self { index, line, col }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Error {
|
||||||
|
pub kind: ErrorKind,
|
||||||
|
pub pos: Option<Pos>,
|
||||||
|
pub msg: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum ErrorKind {
|
||||||
|
LexerError,
|
||||||
|
ParserError,
|
||||||
|
CheckerError,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ErrorAcc {
|
||||||
|
errors: Vec<Error>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ErrorAcc {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { errors: Vec::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ok(&self) -> bool {
|
||||||
|
self.errors.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add(&mut self, error: Error) {
|
||||||
|
self.errors.push(error)
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
|
use crate::pos::Pos;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub struct Token {
|
pub struct Token {
|
||||||
pub kind: TokenKind,
|
pub kind: TokenKind,
|
||||||
pub value: TokenValue,
|
pub value: TokenValue,
|
||||||
pub index: usize,
|
pub pos: Pos,
|
||||||
pub line: i32,
|
|
||||||
pub col: i32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
29
src/util.rs
29
src/util.rs
@ -5,3 +5,32 @@ pub fn hash<H: Hash>(value: H) -> u64 {
|
|||||||
value.hash(&mut hasher);
|
value.hash(&mut hasher);
|
||||||
hasher.finish()
|
hasher.finish()
|
||||||
}
|
}
|
||||||
|
enum Duplicate<T: std::hash::Hash> {
|
||||||
|
None(std::collections::HashMap<T, T>),
|
||||||
|
Found(T),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Itertewls<T>
|
||||||
|
where
|
||||||
|
Self: Iterator<Item = T> + Sized,
|
||||||
|
{
|
||||||
|
fn find_first_duplicate(self) -> Option<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, Item> Itertewls<Item> for I
|
||||||
|
where
|
||||||
|
I: Iterator<Item = Item> + Sized,
|
||||||
|
Item: std::cmp::PartialEq + Clone,
|
||||||
|
{
|
||||||
|
fn find_first_duplicate(mut self) -> Option<Item> {
|
||||||
|
self.try_fold(Vec::new(), |mut used, item| {
|
||||||
|
if used.contains(&item) {
|
||||||
|
Err(item)
|
||||||
|
} else {
|
||||||
|
used.push(item);
|
||||||
|
Ok(used)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user