add pos to stuff

This commit is contained in:
SimonFJ20 2024-06-10 15:49:16 +02:00
parent bded4e81b1
commit 1331ba1009
11 changed files with 574 additions and 306 deletions

7
Cargo.lock generated
View File

@ -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",
] ]

View File

@ -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"

View File

@ -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(&params) 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 } = &param.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, &param)) .map(|(arg, param)| self.compatible(&arg.typ, &param))
.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, .. } = &param.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;"),

View File

@ -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()
}
}

View File

@ -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<_>>()
}; };

View File

@ -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!");

View File

@ -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),

View File

@ -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
View 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)
}
}

View File

@ -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)]

View File

@ -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()
}
}