compiler ^^

This commit is contained in:
SimonFJ20 2024-05-31 11:28:35 +02:00
parent a6c77f6633
commit a80e9bbccb
8 changed files with 292 additions and 154 deletions

View File

@ -10,7 +10,7 @@ pub enum NodeKind {
Error, Error,
Id(u64), Id(u64),
Int(i64), Int(i64),
String(String), Str(String),
Group(Box<Node>), Group(Box<Node>),
Block(Vec<Node>), Block(Vec<Node>),
Call { Call {
@ -56,10 +56,10 @@ pub enum Type {
Unit, Unit,
I32, I32,
U32, U32,
String, Str,
Fn { Fn {
id: u64, id: u64,
params: Vec<Node>, params: Vec<Type>,
return_typ: Box<Type>, return_typ: Box<Type>,
}, },
} }

View File

@ -27,6 +27,7 @@ pub struct Checker<FnIdGen: IdGen = RandIdGen> {
syms: Syms, syms: Syms,
fn_id_gen: FnIdGen, fn_id_gen: FnIdGen,
} }
impl Checker { impl Checker {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@ -71,7 +72,13 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
continue; continue;
} }
let params = params.into_iter().map(|(_, param)| param).collect(); let params = params
.into_iter()
.map(|(_, param)| {
let NodeKind::Param { subject: _, typ } = param.kind else {unreachable!()};
typ.as_ref().cloned().unwrap()
})
.collect::<Vec<_>>();
let parsed::Node::Id(id) = subject.as_ref() else { unreachable!() }; let parsed::Node::Id(id) = subject.as_ref() else { unreachable!() };
@ -132,7 +139,7 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
Type::I32 Type::I32
}, },
), ),
parsed::Node::String(value) => self.node(NodeKind::String(value.clone()), Type::String), parsed::Node::Str(value) => self.node(NodeKind::Str(value.clone()), Type::Str),
parsed::Node::Group(expr) => { parsed::Node::Group(expr) => {
let expr = self.check_expr(expr); let expr = self.check_expr(expr);
let typ = expr.typ.clone(); let typ = expr.typ.clone();
@ -171,8 +178,8 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
} }
if args if args
.iter() .iter()
.zip(params) .zip(params.clone())
.map(|(arg, param)| self.compatible(&arg.typ, &param.typ)) .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");
@ -228,13 +235,24 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
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));
let typ = if !self.compatible(&subject.typ, &value.typ) { match subject.kind {
NodeKind::Error => {
return *subject;
}
NodeKind::Id(_) => {}
_ => {
self.error("cannot assign to expr");
return self.node(NodeKind::Error, Type::Error);
}
}
let _typ = if !self.compatible(&subject.typ, &value.typ) {
self.error("incompatible types #3"); self.error("incompatible types #3");
Type::Error Type::Error
} else { } else {
subject.typ.clone() subject.typ.clone()
}; };
self.node(NodeKind::Assign { subject, value }, typ) self.node(NodeKind::Assign { subject, value }, Type::Unit)
} }
parsed::Node::Let { subject, value } => { parsed::Node::Let { subject, value } => {
let (subject, subject_typ) = match subject.as_ref() { let (subject, subject_typ) = match subject.as_ref() {
@ -274,11 +292,11 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
_ => unreachable!(), _ => unreachable!(),
}; };
self.node(NodeKind::Let { subject, value }, typ) self.node(NodeKind::Let { subject, value }, Type::Unit)
} }
parsed::Node::Fn { parsed::Node::Fn {
subject, subject,
params: _, params,
return_typ: _, return_typ: _,
body, body,
} => { } => {
@ -289,20 +307,33 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
return self.node(NodeKind::Error,Type::Error); return self.node(NodeKind::Error,Type::Error);
}; };
let Type::Fn { id: fn_id, params, 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");
return self.node(NodeKind::Error,Type::Error); return self.node(NodeKind::Error,Type::Error);
}; };
self.syms.enter_scope(); self.syms.enter_scope();
let params = params
.iter()
.zip(param_typs)
.map(|(param, typ)| {
let parsed::Node::Param { subject, .. } = param else { unreachable!() };
let parsed::Node::Id(id) = subject.as_ref() else { unreachable!() };
self.node(
NodeKind::Param {
subject: Box::new(self.node(NodeKind::Id(*id), Type::Unit)),
typ: Some(typ),
},
Type::Unit,
)
})
.collect::<Vec<_>>();
for param in &params { for param in &params {
let NodeKind::Param { let NodeKind::Param { ref subject, ref typ } = param.kind else { unreachable!() };
ref subject,
typ: Some(ref typ),
} = param.kind else { unreachable!() };
let NodeKind::Id(id) = subject.kind else { unreachable!() }; let NodeKind::Id(id) = subject.kind else { unreachable!() };
self.syms.define(id, typ.clone()); 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));
@ -415,7 +446,7 @@ fn test_checker() {
table_id: 0, table_id: 0,
}) })
}, },
typ: I32, typ: Unit,
table_id: 0, table_id: 0,
}, },
Node { Node {
@ -449,7 +480,7 @@ fn test_checker() {
table_id: 0, table_id: 0,
}) })
}, },
typ: I32, typ: Unit,
table_id: 0, table_id: 0,
}, },
Node { Node {
@ -464,6 +495,7 @@ fn test_checker() {
] ]
); );
println!("intentionally undefined");
assert_eq!( assert_eq!(
check("let a = 5; a; { a; let b = 5; b; } a; b;"), check("let a = 5; a; { a; let b = 5; b; } a; b;"),
vec![ vec![
@ -487,7 +519,7 @@ fn test_checker() {
table_id: 0, table_id: 0,
}) })
}, },
typ: I32, typ: Unit,
table_id: 0, table_id: 0,
}, },
Node { Node {
@ -522,7 +554,7 @@ fn test_checker() {
table_id: 1, table_id: 1,
}) })
}, },
typ: I32, typ: Unit,
table_id: 1, table_id: 1,
}, },
Node { Node {

View File

@ -1,27 +1,12 @@
#[derive(Clone, PartialEq, Debug)]
pub struct Data {
pub kind: DataKind,
pub id: u64,
}
#[derive(Clone, PartialEq, Debug)]
pub enum DataKind {
U8(Vec<u8>),
}
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
pub struct Fn { pub struct Fn {
pub blocks: Vec<Block>, pub ops: Vec<Op>,
pub data: Vec<Data>,
pub id: u64, pub id: u64,
pub arg_count: i32, pub arg_count: i32,
pub local_count: i32, pub local_count: i32,
} }
#[derive(Clone, PartialEq, Debug)]
pub struct Block {
pub ops: Vec<Op>,
}
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
pub enum Op { pub enum Op {
Pop, Pop,
@ -31,8 +16,20 @@ pub enum Op {
StoreLocal(i32), StoreLocal(i32),
LoadLocal(i32), LoadLocal(i32),
Jump(u64), Jump(u64),
JumpIfFalse(u64),
JumpIfTrue(u64), JumpIfTrue(u64),
CallFn(u64, i32), CallFn(u64, i32),
CallPtr(i32), CallPtr(i32),
Return, Return,
} }
#[derive(Clone, PartialEq, Debug)]
pub struct Data {
pub kind: DataKind,
pub id: u64,
}
#[derive(Clone, PartialEq, Debug)]
pub enum DataKind {
U8(Vec<u8>),
}

View File

@ -4,13 +4,12 @@ use std::collections::HashMap;
use crate::{ use crate::{
checked::{self, Node, NodeKind}, checked::{self, Node, NodeKind},
ir::{Block, Data, DataKind, Fn, Op}, ir::{Data, DataKind, Fn, Op},
sym::Syms, sym::Syms,
}; };
pub struct Program { pub struct Program {
pub fns: Vec<Fn>, pub fns: Vec<Fn>,
pub data: Vec<Data>,
pub entry: u64, pub entry: u64,
pub sym: Syms, pub sym: Syms,
} }
@ -25,10 +24,9 @@ impl Compiler {
} }
pub fn compile(self, ast: &[Node]) -> Result<Program, ()> { pub fn compile(self, ast: &[Node]) -> Result<Program, ()> {
let (fns, data) = FnCompiler::new(&self.syms).compile_entry(ast)?; let fns = FnCompiler::new(&self.syms).compile_entry(ast)?;
Ok(Program { Ok(Program {
fns, fns,
data,
sym: self.syms, sym: self.syms,
entry: 0, entry: 0,
}) })
@ -42,10 +40,11 @@ impl Compiler {
struct FnCompiler<'syms> { struct FnCompiler<'syms> {
syms: &'syms Syms, syms: &'syms Syms,
ops: Vec<Op>, ops: Vec<Op>,
data: Vec<Data>,
fns: Vec<Fn>,
local_count: i32, local_count: i32,
local_map: HashMap<u64, i32>, local_map: HashMap<u64, i32>,
fns: Vec<Fn>, break_stack: Vec<usize>,
data: Vec<Data>,
} }
impl<'syms> FnCompiler<'syms> { impl<'syms> FnCompiler<'syms> {
@ -53,35 +52,36 @@ impl<'syms> FnCompiler<'syms> {
Self { Self {
syms, syms,
ops: Vec::new(), ops: Vec::new(),
local_count: 0,
local_map: HashMap::new(),
fns: Vec::new(), fns: Vec::new(),
data: Vec::new(), data: Vec::new(),
local_count: 0,
local_map: HashMap::new(),
break_stack: Vec::new(),
} }
} }
pub fn compile_entry(mut self, ast: &[Node]) -> Result<(Vec<Fn>, Vec<Data>), ()> { pub fn compile_entry(mut self, ast: &[Node]) -> Result<Vec<Fn>, ()> {
let mut blocks = Vec::new();
for stmt in ast { for stmt in ast {
blocks.append(&mut self.compile_stmt(stmt)?); self.compile_stmt(stmt)?;
if stmt.typ != checked::Type::Unit { if stmt.typ != checked::Type::Unit {
self.ops.push(Op::Pop); self.ops.push(Op::Pop);
} }
} }
self.fns.push(Fn { self.fns.push(Fn {
blocks, ops: self.ops,
data: self.data,
id: 0, id: 0,
arg_count: 0, arg_count: 0,
local_count: self.local_count, local_count: self.local_count,
}); });
Ok((self.fns, self.data)) Ok(self.fns)
} }
pub fn compile(mut self, node: &Node) -> Result<Fn, ()> { pub fn compile(mut self, node: &Node) -> Result<Vec<Fn>, ()> {
let Node { let Node {
kind: kind:
NodeKind::Fn { NodeKind::Fn {
subject: _, subject,
params, params,
return_typ: _, return_typ: _,
body, body,
@ -92,69 +92,103 @@ impl<'syms> FnCompiler<'syms> {
else { else {
unreachable!() unreachable!()
}; };
for param in params {
let NodeKind::Param { subject, typ } = &param.kind else { unreachable!() };
let NodeKind::Id(param_id) = subject.kind else { unreachable!() };
let sym_table = self.syms.view(body.table_id);
let sym = sym_table.get(param_id).unwrap();
let local_id = self.local_count;
self.local_count += 1;
self.local_map.insert(sym.uid, local_id);
}
let NodeKind::Block(body) = &body.kind else { let NodeKind::Block(body) = &body.kind else {
unreachable!() unreachable!()
}; };
let mut blocks = Vec::new();
for stmt in body { for stmt in body {
blocks.append(&mut self.compile_stmt(stmt)?); self.compile_stmt(stmt)?;
if stmt.typ != checked::Type::Unit { if stmt.typ != checked::Type::Unit {
self.ops.push(Op::Pop); self.push(Op::Pop);
} }
} }
self.push_ops(&mut blocks); self.fns.push(Fn {
Ok(Fn { ops: self.ops,
blocks, data: self.data,
id: *id, id: *id,
arg_count: params.len() as i32, arg_count: params.len() as i32,
local_count: self.local_count, local_count: self.local_count,
}) });
Ok(self.fns)
} }
pub fn compile_stmt(&mut self, stmt: &Node) -> Result<Vec<Block>, ()> { fn compile_stmt(&mut self, stmt: &Node) -> Result<(), ()> {
let syms = self.syms.view(stmt.table_id); let syms = self.syms.view(stmt.table_id);
let mut blocks = Vec::new();
match &stmt.kind { match &stmt.kind {
NodeKind::Error => return Err(()), NodeKind::Error => return Err(()),
NodeKind::Break => todo!(), NodeKind::Break => {
NodeKind::Assign { subject, value } => todo!(), let addr = self.ops.len();
NodeKind::Let { subject, value } => todo!(), self.push(Op::Jump(0));
NodeKind::Fn { self.break_stack.push(addr);
subject, }
params, NodeKind::Assign { subject, value } => {
return_typ, self.compile_expr(value)?;
body, match subject.kind {
id, NodeKind::Error => {
} => todo!(), return Err(());
}
NodeKind::Id(id) => {
let sym_table = self.syms.view(stmt.table_id);
let sym = sym_table.get(id).unwrap();
let local_id = self.local_map.get(&sym.uid).unwrap();
self.push(Op::StoreLocal(*local_id));
}
_ => unimplemented!(),
}
}
NodeKind::Let { subject, value } => {
let NodeKind::Param { subject, typ: _ } = &subject.kind else { unreachable!() };
let NodeKind::Id(subject_id) = subject.kind else { unreachable!()};
let sym_table = self.syms.view(stmt.table_id);
let sym = sym_table.get(subject_id).unwrap();
let local_id = self.local_count;
self.local_map.insert(sym.uid, local_id);
self.local_count += 1;
self.compile_expr(value)?;
self.push(Op::StoreLocal(local_id));
}
NodeKind::Fn { subject, .. } => {
let mut compiled_fn = FnCompiler::new(self.syms).compile(stmt)?;
self.fns.append(&mut compiled_fn);
let NodeKind::Id(subject_id) = subject.kind else { unreachable!()};
let sym_table = self.syms.view(stmt.table_id);
let sym = sym_table.get(subject_id).unwrap();
self.local_map.insert(sym.uid, self.local_count);
self.local_count += 1;
}
NodeKind::Return { value } => { NodeKind::Return { value } => {
self.ops.push(Op::Return); self.ops.push(Op::Return);
} }
_ => { _ => {
blocks.append(&mut self.compile_expr(stmt)?); self.compile_expr(stmt)?;
} }
} }
if stmt.typ != checked::Type::Unit { Ok(())
self.ops.push(Op::Pop);
}
Ok(blocks)
} }
fn compile_expr(&mut self, expr: &Node) -> Result<Vec<Block>, ()> { fn compile_expr(&mut self, expr: &Node) -> Result<(), ()> {
let syms = self.syms.view(expr.table_id); let syms = self.syms.view(expr.table_id);
let mut blocks = Vec::new();
match &expr.kind { match &expr.kind {
NodeKind::Error => return Err(()), NodeKind::Error => return Err(()),
NodeKind::Id(id) => { NodeKind::Id(id) => {
let sym = syms.get(*id).unwrap(); let sym = syms.get(*id).unwrap();
let local_id = self.local_map.get(&sym.uid).unwrap(); let local_id = self.local_map.get(&sym.uid).unwrap();
self.ops.push(Op::LoadLocal(*local_id)); self.push(Op::LoadLocal(*local_id));
} }
NodeKind::Int(value) => match expr.typ { NodeKind::Int(value) => match expr.typ {
checked::Type::I32 => self.ops.push(Op::PushI32(*value as i32)), checked::Type::I32 => self.push(Op::PushI32(*value as i32)),
checked::Type::U32 => self.ops.push(Op::PushU32(*value as u32)), checked::Type::U32 => self.push(Op::PushU32(*value as u32)),
_ => unreachable!(), _ => unreachable!(),
}, },
NodeKind::String(value) => { NodeKind::Str(value) => {
let id = self.data.len() as u64; let id = self.data.len() as u64;
let bytes = value.bytes().collect(); let bytes = value.bytes().collect();
self.data.push(Data { self.data.push(Data {
@ -164,13 +198,13 @@ impl<'syms> FnCompiler<'syms> {
self.ops.push(Op::PushStaticPtr(id)); self.ops.push(Op::PushStaticPtr(id));
} }
NodeKind::Group(expr) => { NodeKind::Group(expr) => {
blocks.append(&mut self.compile_expr(expr)?); self.compile_expr(expr)?;
} }
NodeKind::Block(stmts) => { NodeKind::Block(stmts) => {
let mut last_typ = None; let mut last_typ = None;
for stmt in stmts { for stmt in stmts {
if last_typ.filter(|typ| *typ != checked::Type::Unit).is_some() { if last_typ.filter(|typ| *typ != checked::Type::Unit).is_some() {
self.ops.push(Op::Pop); self.push(Op::Pop);
} }
last_typ = Some(stmt.typ.clone()); last_typ = Some(stmt.typ.clone());
self.compile_stmt(stmt)?; self.compile_stmt(stmt)?;
@ -187,10 +221,10 @@ impl<'syms> FnCompiler<'syms> {
params: _, params: _,
return_typ: _, return_typ: _,
} => { } => {
self.ops.push(Op::CallFn(id, args.len() as i32)); self.push(Op::CallFn(id, args.len() as i32));
} }
_ => { _ => {
self.ops.push(Op::CallPtr(args.len() as i32)); self.push(Op::CallPtr(args.len() as i32));
} }
} }
} }
@ -200,59 +234,39 @@ impl<'syms> FnCompiler<'syms> {
falsy, falsy,
} => { } => {
self.compile_expr(cond)?; self.compile_expr(cond)?;
let cond_idx = blocks.len(); let l0 = self.ops.len();
self.push_ops(&mut blocks); self.push(Op::JumpIfFalse(0));
self.compile_expr(truthy)?;
match falsy { let l1 = self.ops.len();
Some(falsy) => { if let Op::JumpIfFalse(ref mut addr) = self.ops[l0] {
let truthy_first_idx = blocks.len() as u64; *addr = l1 as u64;
let mut truthy = self.compile_expr(truthy)?;
let truthy_last_idx = blocks.len();
self.push_ops(&mut truthy);
blocks.append(&mut truthy);
let falsy_first_idx = blocks.len() as u64;
let mut falsy = self.compile_expr(falsy)?;
let falsy_last_idx = blocks.len();
self.push_ops(&mut falsy);
blocks.append(&mut falsy);
let after_idx = blocks.len() as u64;
blocks[cond_idx].ops.push(Op::JumpIfTrue(truthy_first_idx));
blocks[cond_idx].ops.push(Op::Jump(falsy_first_idx));
blocks[truthy_last_idx].ops.push(Op::Jump(after_idx));
blocks[falsy_last_idx].ops.push(Op::Jump(after_idx));
} }
None => { if let Some(falsy) = falsy {
let truthy_first_idx = blocks.len() as u64; self.push(Op::Jump(0));
let mut truthy = self.compile_expr(truthy)?; self.compile_expr(falsy)?;
let truthy_last_idx = blocks.len(); let l2 = self.ops.len();
self.push_ops(&mut truthy); if let Op::Jump(ref mut addr) = self.ops[l1] {
blocks.append(&mut truthy); *addr = l2 as u64;
let after_idx = blocks.len() as u64;
blocks[cond_idx].ops.push(Op::JumpIfTrue(truthy_first_idx));
blocks[cond_idx].ops.push(Op::Jump(after_idx));
blocks[truthy_last_idx].ops.push(Op::Jump(after_idx));
} }
} }
} }
NodeKind::Loop { body } => { NodeKind::Loop { body } => {
let body = self.compile_expr(body)?; let l0 = self.ops.len() as u64;
let body_idx = blocks.len(); self.compile_expr(body)?;
let l1 = self.ops.len() as u64;
for op in self.break_stack.drain(..) {
let Op::Jump(ref mut addr) = self.ops[op] else { unreachable!() };
*addr = l1;
}
self.push(Op::Jump(l0));
} }
_ => unreachable!(), _ => unreachable!(),
} }
self.push_ops(&mut blocks); Ok(())
Ok(blocks)
} }
fn push_ops(&mut self, blocks: &mut Vec<Block>) { fn push(&mut self, op: Op) {
let mut ops = Vec::new(); self.ops.push(op);
std::mem::swap(&mut self.ops, &mut ops);
blocks.push(Block { ops });
} }
fn error<S: Into<String>>(&mut self, msg: S) { fn error<S: Into<String>>(&mut self, msg: S) {
@ -264,9 +278,10 @@ impl<'syms> FnCompiler<'syms> {
fn test_compiler() { fn test_compiler() {
use crate::checker::{Checker, IdGen}; use crate::checker::{Checker, IdGen};
use crate::parser::Parser; use crate::parser::Parser;
use pretty_assertions::assert_eq;
use Op::*; use Op::*;
use pretty_assertions::assert_eq;
struct SeqIdGen(u64); struct SeqIdGen(u64);
impl IdGen for SeqIdGen { impl IdGen for SeqIdGen {
fn new() -> Self { fn new() -> Self {
@ -285,18 +300,112 @@ fn test_compiler() {
let checked = checker.check(&Parser::new(text).parse()); let checked = checker.check(&Parser::new(text).parse());
let syms = checker.finish(); let syms = checker.finish();
let compiled = Compiler::new(syms).compile(&checked); let compiled = Compiler::new(syms).compile(&checked);
compiled compiled.map(|program| program.fns)
}; };
assert_eq!( assert_eq!(
compile("123;").map(|program| program.fns), compile("fn test(a: i32) -> i32 { a; } test(123);"),
Ok(vec![
Fn {
ops: vec![LoadLocal(0), Pop],
data: vec![],
id: 0,
arg_count: 1,
local_count: 1
},
Fn {
ops: vec![LoadLocal(0), PushI32(123), CallFn(0, 1), Pop],
data: vec![],
id: 0,
arg_count: 0,
local_count: 1
}
])
);
assert_eq!(
compile("let a = 5; let b = 3; a; b; a = b;"),
Ok(vec![Fn { Ok(vec![Fn {
blocks: vec![Block { ops: vec![
ops: vec![PushI32(123)] PushI32(5),
StoreLocal(0),
PushI32(3),
StoreLocal(1),
LoadLocal(0),
Pop,
LoadLocal(1),
Pop,
LoadLocal(1),
StoreLocal(0),
],
data: vec![],
id: 0,
arg_count: 0,
local_count: 2,
}])
);
assert_eq!(
compile("let a = \"hello\";"),
Ok(vec![Fn {
ops: vec![PushStaticPtr(0), StoreLocal(0)],
data: vec![Data {
kind: DataKind::U8(vec![104, 101, 108, 108, 111]),
id: 0
}], }],
id: 0, id: 0,
arg_count: 0, arg_count: 0,
local_count: 1
}])
);
assert_eq!(
compile("if 1 { 2; } if 1 { 2; } else { 3; }"),
Ok(vec![Fn {
ops: vec![
PushI32(1),
JumpIfFalse(3),
PushI32(2),
PushI32(1),
JumpIfFalse(6),
PushI32(2),
Jump(8),
PushI32(3),
Pop,
],
data: vec![],
id: 0,
arg_count: 0,
local_count: 0 local_count: 0
}]) }])
); );
assert_eq!(
compile("let a = if 1 { 2; } else { 3; };"),
Ok(vec![Fn {
ops: vec![
PushI32(1),
JumpIfFalse(3),
PushI32(2),
Jump(5),
PushI32(3),
StoreLocal(0),
],
data: vec![],
id: 0,
arg_count: 0,
local_count: 1
}])
);
assert_eq!(
compile("loop { break; }"),
Ok(vec![Fn {
ops: vec![Jump(1), Jump(0)],
data: vec![],
id: 0,
arg_count: 0,
local_count: 0,
},])
);
} }

View File

@ -114,7 +114,7 @@ impl<'a> Lexer<'a> {
Some('"') => { Some('"') => {
self.step(); self.step();
break self break self
.token_with_value(TokenKind::String, TokenValue::String(value)); .token_with_value(TokenKind::Str, TokenValue::Str(value));
} }
Some(ch) => { Some(ch) => {
value.push(ch); value.push(ch);
@ -261,18 +261,18 @@ fn test_lexer() {
assert_eq!(lex("abc"), vec![(TK::Id, TV::Id(hash("abc")))]); assert_eq!(lex("abc"), vec![(TK::Id, TV::Id(hash("abc")))]);
assert_eq!(lex("123"), vec![(TK::Int, TV::Int(123))]); assert_eq!(lex("123"), vec![(TK::Int, TV::Int(123))]);
assert_eq!(lex("\"\""), vec![(TK::String, TV::String("".to_string()))]); assert_eq!(lex("\"\""), vec![(TK::Str, TV::Str("".to_string()))]);
assert_eq!( assert_eq!(
lex("\"hello\""), lex("\"hello\""),
vec![(TK::String, TV::String("hello".to_string()))] vec![(TK::Str, TV::Str("hello".to_string()))]
); );
assert_eq!( assert_eq!(
lex("\"new\\nline\""), lex("\"new\\nline\""),
vec![(TK::String, TV::String("new\nline".to_string()))] vec![(TK::Str, TV::Str("new\nline".to_string()))]
); );
assert_eq!( assert_eq!(
lex("\"backslash\\\\\""), lex("\"backslash\\\\\""),
vec![(TK::String, TV::String("backslash\\".to_string()))] vec![(TK::Str, TV::Str("backslash\\".to_string()))]
); );
assert_eq!(lex("->"), vec![(TK::MinusLt, TV::None)]); assert_eq!(lex("->"), vec![(TK::MinusLt, TV::None)]);
assert_eq!(lex("let"), vec![(TK::Let, TV::None)]); assert_eq!(lex("let"), vec![(TK::Let, TV::None)]);

View File

@ -3,7 +3,7 @@ pub enum Node {
Error, Error,
Id(u64), Id(u64),
Int(i64), Int(i64),
String(String), Str(String),
Group(Box<Node>), Group(Box<Node>),
Block(Vec<Node>), Block(Vec<Node>),
Call { Call {

View File

@ -111,10 +111,6 @@ impl<'a> Parser<'a> {
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::RParen) {
self.error("expected ')'");
return Err(Node::Error);
}
if !self.curr_is(TokenKind::Id) { if !self.curr_is(TokenKind::Id) {
self.error("expected id"); self.error("expected id");
return Err(Node::Error); return Err(Node::Error);
@ -158,7 +154,7 @@ impl<'a> Parser<'a> {
fn parse_param(&mut self) -> Node { fn parse_param(&mut self) -> Node {
let subject = Box::new(self.parse_id()); let subject = Box::new(self.parse_id());
let typ = if let Some(TokenKind::Comma) = self.curr_kind() { let typ = if let Some(TokenKind::Colon) = self.curr_kind() {
self.step(); self.step();
Some(Box::new(self.parse_typ())) Some(Box::new(self.parse_typ()))
} else { } else {
@ -239,7 +235,7 @@ impl<'a> Parser<'a> {
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(),
Some(TokenKind::String) => self.parse_string(), Some(TokenKind::Str) => self.parse_string(),
Some(TokenKind::LParen) => self.parse_group(), Some(TokenKind::LParen) => self.parse_group(),
Some(TokenKind::LBrace) => self.parse_block(), Some(TokenKind::LBrace) => self.parse_block(),
Some(TokenKind::If) => self.parse_if(), Some(TokenKind::If) => self.parse_if(),
@ -280,15 +276,15 @@ impl<'a> Parser<'a> {
fn parse_string(&mut self) -> Node { fn parse_string(&mut self) -> Node {
let Some(Token { let Some(Token {
kind: TokenKind::String, kind: TokenKind::Str,
value: TokenValue::String(value), value: TokenValue::Str(value),
.. ..
}) = self.current.clone() }) = self.current.clone()
else { else {
unreachable!() unreachable!()
}; };
self.step(); self.step();
Node::String(value.clone()) Node::Str(value.clone())
} }
fn parse_group(&mut self) -> Node { fn parse_group(&mut self) -> Node {
@ -307,6 +303,10 @@ impl<'a> Parser<'a> {
let mut stmts = Vec::new(); let mut stmts = Vec::new();
loop { loop {
match self.curr_kind() { match self.curr_kind() {
None => {
self.error("expected ')'");
break Node::Error;
}
Some(TokenKind::RBrace) => { Some(TokenKind::RBrace) => {
self.step(); self.step();
break Node::Block(stmts); break Node::Block(stmts);
@ -392,7 +392,7 @@ fn test_parser() {
assert_eq!(Parser::new("123;").parse(), vec![Int(123)]); assert_eq!(Parser::new("123;").parse(), vec![Int(123)]);
assert_eq!( assert_eq!(
Parser::new("\"hello\";").parse(), Parser::new("\"hello\";").parse(),
vec![String("hello".to_string())] vec![Str("hello".to_string())]
); );
assert_eq!(Parser::new("0;").parse(), vec![Int(0)]); assert_eq!(Parser::new("0;").parse(), vec![Int(0)]);
assert_eq!(Parser::new("0;abc;").parse(), vec![Int(0), Id(hash("abc"))]); assert_eq!(Parser::new("0;abc;").parse(), vec![Int(0), Id(hash("abc"))]);

View File

@ -12,7 +12,7 @@ pub enum TokenKind {
Error, Error,
Id, Id,
Int, Int,
String, Str,
If, If,
Else, Else,
Loop, Loop,
@ -36,5 +36,5 @@ pub enum TokenValue {
None, None,
Id(u64), Id(u64),
Int(i64), Int(i64),
String(String), Str(String),
} }