diff --git a/data/test.lang b/data/test.lang index e91466a..eb38333 100644 --- a/data/test.lang +++ b/data/test.lang @@ -1,3 +1,8 @@ +println("testy"); +let x = 3; +print_dec(x); +start(); + struct Test { a: 64, b: 64, diff --git a/src/ir/lower/program.rs b/src/ir/lower/program.rs index cc429b9..d01d541 100644 --- a/src/ir/lower/program.rs +++ b/src/ir/lower/program.rs @@ -17,7 +17,7 @@ impl LProgram { pub fn create(p: &UProgram) -> Result { let start = p .names - .id::("start") + .id::("crate") .ok_or("no start method found")?; let mut ssbuilder = SymbolSpaceBuilder::with_entries(&[start]); let entry = ssbuilder.func(&start); diff --git a/src/ir/upper/maps.rs b/src/ir/upper/assoc.rs similarity index 100% rename from src/ir/upper/maps.rs rename to src/ir/upper/assoc.rs diff --git a/src/ir/upper/kind.rs b/src/ir/upper/kind.rs index ab10c41..9abf9d8 100644 --- a/src/ir/upper/kind.rs +++ b/src/ir/upper/kind.rs @@ -100,7 +100,7 @@ macro_rules! impl_kind { ($struc:ty, $idx:expr, $field:ident, $name:expr) => { impl_kind!($struc, $idx, $field, $name, nofin); impl Finish for $struc { - fn finish(_: &mut UProgram, _: ID) {} + fn finish(_: &mut UProgram, _: ID, _: &str) {} } }; ($struc:ty, $idx:expr, $field:ident, $name:expr, nofin) => { @@ -133,9 +133,9 @@ pub type DataID = ID; pub type GenericID = ID; impl Finish for UFunc { - fn finish(p: &mut UProgram, id: ID) { + fn finish(p: &mut UProgram, id: ID, name: &str) { let var = p.def_searchable( - p.names.name(id).to_string(), + name.to_string(), Some(UVar { parent: None, ty: Type::Placeholder, @@ -153,5 +153,5 @@ pub trait Kind: Sized { } pub trait Finish: Sized { - fn finish(program: &mut UProgram, id: ID); + fn finish(program: &mut UProgram, id: ID, name: &str); } diff --git a/src/ir/upper/mod.rs b/src/ir/upper/mod.rs index 5bed81a..2d8a188 100644 --- a/src/ir/upper/mod.rs +++ b/src/ir/upper/mod.rs @@ -1,17 +1,18 @@ -mod kind; -mod instr; -mod ty; -mod program; -mod validate; +mod assoc; mod error; mod inst; -mod maps; +mod instr; +mod kind; +mod program; +mod ty; +mod validate; use super::*; -use maps::*; -pub use maps::Idents; -pub use kind::*; -pub use instr::*; -pub use ty::*; -pub use program::*; +use assoc::*; + +pub use assoc::Idents; pub use inst::*; +pub use instr::*; +pub use kind::*; +pub use program::*; +pub use ty::*; diff --git a/src/ir/upper/program.rs b/src/ir/upper/program.rs index 6214f54..a0b420b 100644 --- a/src/ir/upper/program.rs +++ b/src/ir/upper/program.rs @@ -2,16 +2,19 @@ use super::*; use std::collections::HashMap; pub struct UProgram { + // kinds pub fns: Vec>, pub vars: Vec>, pub structs: Vec>, pub types: Vec>, pub data: Vec>, + // associated data pub names: NameMap, pub origins: OriginMap, pub fn_var: FnVarMap, - pub temp: usize, + pub path: Vec, pub name_stack: Vec>, + pub temp: usize, } impl UProgram { @@ -25,8 +28,9 @@ impl UProgram { names: NameMap::new(), origins: OriginMap::new(), fn_var: FnVarMap::new(), - temp: 0, + path: Vec::new(), name_stack: vec![HashMap::new()], + temp: 0, } } pub fn push(&mut self) { @@ -35,6 +39,12 @@ impl UProgram { pub fn pop(&mut self) { self.name_stack.pop(); } + pub fn push_name(&mut self, name: &str) { + self.path.push(name.to_string()); + } + pub fn pop_name(&mut self) { + self.path.pop(); + } pub fn get_idents(&self, name: &str) -> Option { for map in self.name_stack.iter().rev() { let res = map.get(name); @@ -70,7 +80,7 @@ impl UProgram { fn temp_var_inner(&mut self, origin: Origin, ty: Type, parent: Option) -> VarInst { let v = self.def( - format!("temp{}", self.temp), + &format!("temp{}", self.temp), Some(UVar { parent, ty }), origin, ); @@ -85,23 +95,32 @@ impl UProgram { K::from_program_mut(self)[id.0] = Some(k); } - pub fn def(&mut self, name: String, k: Option, origin: Origin) -> ID { - self.names.push::(name); + pub fn def(&mut self, name: &str, k: Option, origin: Origin) -> ID { + self.names.push::(self.path_for(name)); self.origins.push::(origin); let vec = K::from_program_mut(self); let id = ID::new(vec.len()); vec.push(k); - K::finish(self, id); + K::finish(self, id, name); id } + pub fn path_for(&self, name: &str) -> String { + if self.path.is_empty() { + return name.to_string(); + } + let mut path = self.path.join("::"); + path = path + "::" + name; + path + } + pub fn def_searchable( &mut self, name: String, k: Option, origin: Origin, ) -> ID { - let id = self.def(name.clone(), k, origin); + let id = self.def(&name, k, origin); self.name_on_stack(id, name); id } diff --git a/src/ir/upper/ty.rs b/src/ir/upper/ty.rs index 52236a9..258a281 100644 --- a/src/ir/upper/ty.rs +++ b/src/ir/upper/ty.rs @@ -1,4 +1,4 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use super::{GenericID, Len, StructID, UInstruction, UProgram, UVar, VarID}; @@ -80,7 +80,7 @@ impl UProgram { pub fn resolve_instr_types( &self, - vars: &mut Vec>, + vars: &mut [Option], i: &UInstruction, ) -> Result<(), VarID> { 'outer: { @@ -161,13 +161,10 @@ impl UProgram { args[i] = ty; } } - // for arg in &args { - // println!("{:?}", self.type_name(arg)); - // } set(vars, dest.id, Type::Struct { id, args }); } - UInstruction::If { cond, body } => {} - UInstruction::Loop { body } => {} + UInstruction::If { cond, body: _ } => {} + UInstruction::Loop { body: _ } => {} UInstruction::Break => {} UInstruction::Continue => {} } diff --git a/src/ir/upper/validate.rs b/src/ir/upper/validate.rs index c4ff695..9be6f43 100644 --- a/src/ir/upper/validate.rs +++ b/src/ir/upper/validate.rs @@ -24,7 +24,7 @@ impl UProgram { } if var.ty == Type::Infer { output.err(CompilerMsg { - msg: format!("Var {:?} cannot be inferred", id), + msg: format!("Var {:?} cannot be inferred!", id), spans: vec![self.origins.get(id)], }); } @@ -40,7 +40,7 @@ impl UProgram { output.check_assign(self, &var.ty, ft, self.origins.get(id)); } else { output.err(CompilerMsg { - msg: format!("invalid parent!"), + msg: "invalid parent!".to_string(), spans: vec![self.origins.get(id)], }); } diff --git a/src/main.rs b/src/main.rs index 44e8d71..e2554fe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,7 @@ #![feature(str_as_str)] use ir::{LProgram, UProgram}; -use parser::{NodeParsable, PModule, PStatement, ParserCtx}; +use parser::{PModule, ParseResult, ParserCtx}; use std::{ fs::{create_dir_all, OpenOptions}, io::{stdout, BufRead, BufReader}, @@ -36,7 +36,7 @@ fn main() { fn run_file(file: &str, gdb: bool, asm: bool) { let mut ctx = ParserCtx::from(file); - let res = PModule::parse_node(&mut ctx); + let res = PModule::parse(&mut ctx); let mut output = ctx.output; 'outer: { if !output.errs.is_empty() { @@ -44,22 +44,19 @@ fn run_file(file: &str, gdb: bool, asm: bool) { } // println!("Parsed:"); // println!("{:#?}", res.node); - let Some(module) = res.node.as_ref() else { - break 'outer; - }; let mut program = UProgram::new(); - module.lower(&mut program, &mut output); + res.lower("crate".to_string(), &mut program, &mut output); if !output.errs.is_empty() { break 'outer; } program.resolve_types(); // println!("vars:"); // for (id, def) in program.iter_vars() { - // println!(" {id:?} = {}: {}", program.names.get(id), program.type_name(&def.ty)); - // } - // for (id, f) in program.iter_fns() { - // println!("{}:{id:?} = {:#?}", program.names.get(id), f); + // println!(" {id:?} = {}: {}", program.names.name(id), program.type_name(&def.ty)); // } + for (id, f) in program.iter_fns() { + println!("{}:{id:?} = {:#?}", program.names.name(id), f); + } output = program.validate(); if !output.errs.is_empty() { break 'outer; @@ -128,16 +125,17 @@ fn save_run(binary: &[u8], run_gdb: bool) { } pub fn run_stdin() { - for line in BufReader::new(std::io::stdin()).lines() { - let str = &line.expect("failed to read line"); - let mut ctx = ParserCtx::from(&str[..]); - if let Some(expr) = PStatement::parse_node(&mut ctx).node.as_ref() { - if ctx.next().is_none() { - println!("{:?}", expr); - } else { - println!("uhhhh ehehe"); - } - } - ctx.output.write_for(&mut stdout(), str); - } + println!("todo"); + // for line in BufReader::new(std::io::stdin()).lines() { + // let str = &line.expect("failed to read line"); + // let mut ctx = ParserCtx::from(&str[..]); + // if let Some(expr) = PStatement::parse_node(&mut ctx).node.as_ref() { + // if ctx.next().is_none() { + // println!("{:?}", expr); + // } else { + // println!("uhhhh ehehe"); + // } + // } + // ctx.output.write_for(&mut stdout(), str); + // } } diff --git a/src/parser/v3/error.rs b/src/parser/v3/error.rs index b707240..060bb4d 100644 --- a/src/parser/v3/error.rs +++ b/src/parser/v3/error.rs @@ -16,7 +16,7 @@ impl CompilerMsg { pub fn identifier_not_found(id: &Node) -> Self { Self { msg: format!("Identifier '{}' not found", id.as_ref().unwrap()), - spans: vec![id.span], + spans: vec![id.origin], } } pub fn unexpected_token(inst: &TokenInstance, expected: &str) -> Self { diff --git a/src/parser/v3/lower/arch/riscv64.rs b/src/parser/v3/lower/arch/riscv64.rs index d1864ce..1a34796 100644 --- a/src/parser/v3/lower/arch/riscv64.rs +++ b/src/parser/v3/lower/arch/riscv64.rs @@ -159,7 +159,7 @@ impl RV64Instruction { "remu" => op(ctx, op32m::REMU, op32m::FUNCT7)?, w => { - ctx.err_at(inst.op.span, format!("Unknown instruction '{}'", w)); + ctx.err_at(inst.op.origin, format!("Unknown instruction '{}'", w)); return None; } }) @@ -169,7 +169,7 @@ impl RV64Instruction { pub fn arg_to_var(node: &Node, ctx: &mut FnLowerCtx) -> Option { let PAsmArg::Ref(node) = node.inner.as_ref()? else { ctx.err_at( - node.span, + node.origin, "Expected variable / function reference".to_string(), ); return None; @@ -194,7 +194,7 @@ impl Reg { let s = &**node.inner.as_ref()?; let res = Reg::from_str(s); if res.is_none() { - ctx.err_at(node.span, format!("Unknown reg name '{}'", s)); + ctx.err_at(node.origin, format!("Unknown reg name '{}'", s)); } res } @@ -202,14 +202,14 @@ impl Reg { fn i32_from_arg(node: &Node, ctx: &mut FnLowerCtx) -> Option { let PAsmArg::Value(node) = node.inner.as_ref()? else { - ctx.err_at(node.span, "Expected an i32, found reference".to_string()); + ctx.err_at(node.origin, "Expected an i32, found reference".to_string()); return None; }; let word = node.inner.as_ref()?; match word.parse::() { Ok(x) => Some(x), Err(_) => { - ctx.err_at(node.span, format!("Expected an i64, found {}", word)); + ctx.err_at(node.origin, format!("Expected an i64, found {}", word)); None } } diff --git a/src/parser/v3/lower/block.rs b/src/parser/v3/lower/block.rs index a649c83..11bb8ab 100644 --- a/src/parser/v3/lower/block.rs +++ b/src/parser/v3/lower/block.rs @@ -1,4 +1,7 @@ -use crate::ir::{Type, UInstruction, VarInst}; +use crate::{ + ir::{Type, UInstruction, VarInst}, + parser::{PConstStatement, PStatementLike}, +}; use super::{FnLowerCtx, FnLowerable, PBlock, PStatement}; @@ -6,12 +9,48 @@ impl FnLowerable for PBlock { type Output = VarInst; fn lower(&self, ctx: &mut FnLowerCtx) -> Option { ctx.program.push(); - for statement in &self.statements { - statement.lower(ctx); + let mut last = None; + let mut statements = Vec::new(); + let mut fn_nodes = Vec::new(); + let mut struct_nodes = Vec::new(); + // first sort statements + for s in &self.statements { + let Some(s) = s.as_ref() else { + continue; + }; + match s { + PStatementLike::Statement(s) => statements.push(s), + PStatementLike::Const(pconst_statement) => match pconst_statement { + PConstStatement::Fn(f) => fn_nodes.push(f), + PConstStatement::Struct(s) => struct_nodes.push(s), + }, + } + } + // then lower const things + let mut structs = Vec::new(); + for s in &struct_nodes { + structs.push(s.lower_name(ctx.program)); + } + for (s, id) in struct_nodes.iter().zip(structs) { + if let Some(id) = id { + s.lower(id, ctx.program, ctx.output); + } + } + let mut fns = Vec::new(); + for f in &fn_nodes { + fns.push(f.lower_name(ctx.program)); + } + for (f, id) in fn_nodes.iter().zip(fns) { + if let Some(id) = id { + f.lower(id, ctx.program, ctx.output) + } + } + // then lower statements + for s in statements { + last = s.lower(ctx); } - let res = self.result.as_ref().and_then(|r| r.lower(ctx)); ctx.program.pop(); - res + last } } @@ -19,7 +58,7 @@ impl FnLowerable for PStatement { type Output = VarInst; fn lower(&self, ctx: &mut FnLowerCtx) -> Option { match self { - super::PStatement::Let(def, e) => { + PStatement::Let(def, e) => { let def = def.lower(ctx.program, ctx.output)?; let res = e.lower(ctx); if let Some(res) = res { @@ -30,7 +69,7 @@ impl FnLowerable for PStatement { } None } - super::PStatement::Return(e) => { + PStatement::Return(e) => { if let Some(e) = e { let src = e.lower(ctx)?; ctx.push_at(UInstruction::Ret { src }, src.span); @@ -40,7 +79,7 @@ impl FnLowerable for PStatement { } None } - super::PStatement::Expr(e) => e.lower(ctx), + PStatement::Expr(e) => e.lower(ctx), } } } diff --git a/src/parser/v3/lower/def.rs b/src/parser/v3/lower/def.rs index c1af82b..d2ab2ff 100644 --- a/src/parser/v3/lower/def.rs +++ b/src/parser/v3/lower/def.rs @@ -15,8 +15,8 @@ impl Node { None => Type::Infer, }; Some(VarInst { - id: program.def_searchable(name, Some(UVar { ty, parent: None }), self.span), - span: self.span, + id: program.def_searchable(name, Some(UVar { ty, parent: None }), self.origin), + span: self.origin, }) } } diff --git a/src/parser/v3/lower/expr.rs b/src/parser/v3/lower/expr.rs index a083fa2..f8f75ba 100644 --- a/src/parser/v3/lower/expr.rs +++ b/src/parser/v3/lower/expr.rs @@ -10,29 +10,29 @@ impl FnLowerable for PExpr { Some(match self { PExpr::Lit(l) => match l.as_ref()? { super::PLiteral::String(s) => { - let dest = ctx.program.temp_var(l.span, Type::Bits(8).slice()); + let dest = ctx.program.temp_var(l.origin, Type::Bits(8).slice()); let data = s.as_bytes().to_vec(); let src = ctx.program.def( - format!("string \"{}\"", s.replace("\n", "\\n")), + &format!("string \"{}\"", s.replace("\n", "\\n")), Some(UData { ty: Type::Bits(8).arr(data.len() as u32), content: data, }), - l.span, + l.origin, ); ctx.push(UInstruction::LoadSlice { dest, src }); dest } super::PLiteral::Char(c) => { let ty = Type::Bits(8); - let dest = ctx.program.temp_var(l.span, ty.clone()); + let dest = ctx.program.temp_var(l.origin, ty.clone()); let src = ctx.program.def( - format!("char '{c}'"), + &format!("char '{c}'"), Some(UData { ty, content: c.to_string().as_bytes().to_vec(), }), - l.span, + l.origin, ); ctx.push(UInstruction::LoadData { dest, src }); dest @@ -40,24 +40,30 @@ impl FnLowerable for PExpr { super::PLiteral::Number(n) => { // TODO: temp let ty = Type::Bits(64); - let dest = ctx.program.temp_var(l.span, Type::Bits(64)); + let dest = ctx.program.temp_var(l.origin, Type::Bits(64)); let src = ctx.program.def( - format!("num {n:?}"), + &format!("num {n:?}"), Some(UData { ty, content: n.whole.parse::().unwrap().to_le_bytes().to_vec(), }), - l.span + l.origin, ); ctx.push(UInstruction::LoadData { dest, src }); dest } - super::PLiteral::Unit => ctx.program.temp_var(l.span, Type::Unit), + super::PLiteral::Unit => ctx.program.temp_var(l.origin, Type::Unit), }, PExpr::Ident(i) => ctx.get_var(i)?, - PExpr::BinaryOp(op, e1, e2) => { - let res1 = e1.lower(ctx)?; - if *op == PInfixOp::Access { + PExpr::BinaryOp(op, e1, e2) => match op { + PInfixOp::Add => todo!(), + PInfixOp::Sub => todo!(), + PInfixOp::Mul => todo!(), + PInfixOp::Div => todo!(), + PInfixOp::LessThan => todo!(), + PInfixOp::GreaterThan => todo!(), + PInfixOp::Member => { + let res1 = e1.lower(ctx)?; let Some(box PExpr::Ident(ident)) = &e2.inner else { ctx.err("Field accessors must be identifiers".to_string()); return None; @@ -70,26 +76,17 @@ impl FnLowerable for PExpr { field: fname, }, ) - } else { - let res2 = e2.lower(ctx)?; - match op { - PInfixOp::Add => todo!(), - PInfixOp::Sub => todo!(), - PInfixOp::Mul => todo!(), - PInfixOp::Div => todo!(), - PInfixOp::LessThan => todo!(), - PInfixOp::GreaterThan => todo!(), - PInfixOp::Access => todo!(), - PInfixOp::Assign => { - ctx.push(UInstruction::Mv { - dest: res1, - src: res2, - }); - res1 - } - } } - } + PInfixOp::Assign => { + let res1 = e1.lower(ctx)?; + let res2 = e2.lower(ctx)?; + ctx.push(UInstruction::Mv { + dest: res1, + src: res2, + }); + res1 + } + }, PExpr::UnaryOp(op, e) => { let res = e.lower(ctx)?; match op { diff --git a/src/parser/v3/lower/func.rs b/src/parser/v3/lower/func.rs index 4018644..f6a3c78 100644 --- a/src/parser/v3/lower/func.rs +++ b/src/parser/v3/lower/func.rs @@ -19,7 +19,7 @@ impl PFunction { pub fn lower_name(&self, p: &mut UProgram) -> Option { let header = self.header.as_ref()?; let name = header.name.as_ref()?; - let id = p.def_searchable(name.to_string(), None, self.header.span); + let id = p.def_searchable(name.to_string(), None, self.header.origin); Some(id) } pub fn lower(&self, id: FnID, p: &mut UProgram, output: &mut CompilerOutput) { @@ -42,7 +42,7 @@ impl PFunction { instructions: Vec::new(), program: p, output, - span: self.body.span, + origin: self.body.origin, }; if let Some(src) = self.body.lower(&mut ctx) { ctx.instructions.push(UInstrInst { @@ -65,7 +65,7 @@ pub struct FnLowerCtx<'a> { pub program: &'a mut UProgram, pub instructions: Vec, pub output: &'a mut CompilerOutput, - pub span: FileSpan, + pub origin: FileSpan, } impl FnLowerCtx<'_> { @@ -73,7 +73,7 @@ impl FnLowerCtx<'_> { let name = node.inner.as_ref()?; let res = self.program.get_idents(name); if res.is_none() { - self.err_at(node.span, format!("Identifier '{}' not found", name)); + self.err_at(node.origin, format!("Identifier '{}' not found", name)); } res } @@ -81,29 +81,29 @@ impl FnLowerCtx<'_> { let ids = self.get_idents(node)?; if ids.get::().is_none() { self.err_at( - node.span, + node.origin, format!("Variable '{}' not found", node.inner.as_ref()?), ); } ids.get::().map(|id| VarInst { id, - span: node.span, + span: node.origin, }) } pub fn err(&mut self, msg: String) { - self.output.err(CompilerMsg::from_span(self.span, msg)) + self.output.err(CompilerMsg::from_span(self.origin, msg)) } pub fn err_at(&mut self, span: FileSpan, msg: String) { self.output.err(CompilerMsg::from_span(span, msg)) } pub fn temp(&mut self, ty: Type) -> VarInst { - self.program.temp_var(self.span, ty) + self.program.temp_var(self.origin, ty) } pub fn temp_subvar(&mut self, ty: Type, parent: FieldRef) -> VarInst { - self.program.temp_subvar(self.span, ty, parent) + self.program.temp_subvar(self.origin, ty, parent) } pub fn push(&mut self, i: UInstruction) { - self.push_at(i, self.span); + self.push_at(i, self.origin); } pub fn push_at(&mut self, i: UInstruction, span: FileSpan) { self.instructions.push(UInstrInst { i, span }); @@ -113,7 +113,7 @@ impl FnLowerCtx<'_> { program: self.program, instructions: Vec::new(), output: self.output, - span: self.span, + origin: self.origin, } } } diff --git a/src/parser/v3/lower/mod.rs b/src/parser/v3/lower/mod.rs index d560485..a67cc60 100644 --- a/src/parser/v3/lower/mod.rs +++ b/src/parser/v3/lower/mod.rs @@ -4,11 +4,34 @@ mod block; mod def; mod expr; mod func; -mod module; mod struc; mod ty; use super::*; +use crate::ir::{Type, UFunc, UProgram}; + +impl PModule { + pub fn lower(&self, name: String, p: &mut UProgram, output: &mut CompilerOutput) { + let id = p.def_searchable(name.clone(), None, self.block.origin); + p.push_name(&name); + let mut fctx = FnLowerCtx { + program: p, + instructions: Vec::new(), + output, + origin: self.block.origin, + }; + self.block.lower(&mut fctx); + let f = UFunc { + args: Vec::new(), + instructions: fctx.instructions, + ret: Type::Unit, + }; + let ty = f.ty(p); + p.write(id, f); + p.pop_name(); + p.expect_mut(p.fn_var.var(id)).ty = ty; + } +} pub use func::FnLowerCtx; @@ -20,10 +43,10 @@ pub trait FnLowerable { impl FnLowerable for Node { type Output = T::Output; fn lower(&self, ctx: &mut FnLowerCtx) -> Option { - let old_span = ctx.span; - ctx.span = self.span; + let old_span = ctx.origin; + ctx.origin = self.origin; let res = self.as_ref()?.lower(ctx); - ctx.span = old_span; + ctx.origin = old_span; res } } diff --git a/src/parser/v3/lower/module.rs b/src/parser/v3/lower/module.rs deleted file mode 100644 index fc0c3f2..0000000 --- a/src/parser/v3/lower/module.rs +++ /dev/null @@ -1,26 +0,0 @@ -use crate::ir::UProgram; - -use super::{CompilerOutput, PModule}; - -impl PModule { - pub fn lower(&self, p: &mut UProgram, output: &mut CompilerOutput) { - let mut structs = Vec::new(); - for s in &self.structs { - structs.push(s.lower_name(p)); - } - for (s, id) in self.structs.iter().zip(structs) { - if let Some(id) = id { - s.lower(id, p, output); - } - } - let mut fns = Vec::new(); - for f in &self.functions { - fns.push(f.lower_name(p)); - } - for (f, id) in self.functions.iter().zip(fns) { - if let Some(id) = id { - f.lower(id, p, output) - } - } - } -} diff --git a/src/parser/v3/lower/struc.rs b/src/parser/v3/lower/struc.rs index 420f8bc..724f41b 100644 --- a/src/parser/v3/lower/struc.rs +++ b/src/parser/v3/lower/struc.rs @@ -85,10 +85,10 @@ impl Node { pub fn lower_name(&self, p: &mut UProgram) -> Option { let s = self.as_ref()?; let name = s.name.as_ref()?.to_string(); - let id = p.def_searchable(name.to_string(), None, s.name.span); + let id = p.def_searchable(name.to_string(), None, s.name.origin); Some(id) } pub fn lower(&self, id: StructID, p: &mut UProgram, output: &mut CompilerOutput) { - self.as_ref().map(|i| i.lower(id, p, output, self.span)); + self.as_ref().map(|i| i.lower(id, p, output, self.origin)); } } diff --git a/src/parser/v3/lower/ty.rs b/src/parser/v3/lower/ty.rs index bb38c9b..68dc862 100644 --- a/src/parser/v3/lower/ty.rs +++ b/src/parser/v3/lower/ty.rs @@ -8,7 +8,7 @@ use super::{CompilerMsg, CompilerOutput, FileSpan, Node, PType}; impl Node { pub fn lower(&self, namespace: &mut UProgram, output: &mut CompilerOutput) -> Type { self.as_ref() - .map(|t| t.lower(namespace, output, self.span)) + .map(|t| t.lower(namespace, output, self.origin)) .unwrap_or(Type::Error) } } @@ -47,6 +47,6 @@ impl Node { pub fn lower(&self, p: &mut UProgram) -> Option { let s = self.as_ref()?; let name = s.name.as_ref()?; - Some(p.def_searchable(name.to_string(), Some(UGeneric {}), self.span)) + Some(p.def_searchable(name.to_string(), Some(UGeneric {}), self.origin)) } } diff --git a/src/parser/v3/node.rs b/src/parser/v3/node.rs index 028ba2a..6a30dd4 100644 --- a/src/parser/v3/node.rs +++ b/src/parser/v3/node.rs @@ -3,30 +3,30 @@ use std::{ ops::{Deref, DerefMut}, }; -use super::FileSpan; +use crate::ir::Origin; pub struct Node { pub inner: Option, - pub span: FileSpan, + pub origin: Origin, } impl Node { - pub fn new(inner: T, span: FileSpan) -> Self { + pub fn new(inner: T, span: Origin) -> Self { Self { inner: Some(inner), - span, + origin: span, } } pub fn bx(self) -> Node> { Node { inner: self.inner.map(|v| Box::new(v)), - span: self.span, + origin: self.origin, } } pub fn map T2>(self, f: F) -> Node { Node { inner: self.inner.map(f), - span: self.span, + origin: self.origin, } } } diff --git a/src/parser/v3/nodes/block.rs b/src/parser/v3/nodes/block.rs index 7d62e66..5817400 100644 --- a/src/parser/v3/nodes/block.rs +++ b/src/parser/v3/nodes/block.rs @@ -1,33 +1,41 @@ use std::fmt::{Debug, Write}; use super::{ - token::Symbol, Node, NodeParsable, PStatement, Parsable, ParseResult, ParserCtx, CompilerMsg, + token::Symbol, CompilerMsg, Node, NodeParsable, PStatementLike, ParseResult, ParserCtx, +}; +use crate::{ + parser::{ParsableWith, TokenInstance}, + util::Padder, }; -use crate::util::Padder; pub struct PBlock { - pub statements: Vec>, - pub result: Option>>, + pub statements: Vec>, + pub ret_last: bool, } -impl Parsable for PBlock { - fn parse(ctx: &mut ParserCtx) -> ParseResult { +impl ParsableWith for PBlock { + type Data = Option; + fn parse(ctx: &mut ParserCtx, end: Option) -> ParseResult { let mut statements = Vec::new(); - let mut result = None; - ctx.expect_sym(Symbol::OpenCurly)?; - if ctx.expect_peek()?.is_symbol(Symbol::CloseCurly) { + let is_end = |t: &TokenInstance| -> bool { end.map(|e| t.is_symbol(e)).unwrap_or(false) }; + if ctx.peek().is_none_or(is_end) { ctx.next(); - return ParseResult::Ok(Self { statements, result }); + return ParseResult::Ok(Self { + statements, + ret_last: false, + }); } let mut expect_semi = false; let mut recover = false; loop { let Some(next) = ctx.peek() else { - recover = true; - ctx.err(CompilerMsg::unexpected_end()); + if end.is_some() { + recover = true; + ctx.err(CompilerMsg::unexpected_end()); + } break; }; - if next.is_symbol(Symbol::CloseCurly) { + if is_end(next) { ctx.next(); break; } @@ -41,9 +49,12 @@ impl Parsable for PBlock { spans: vec![ctx.next_start().char_span()], }); } - let res = PStatement::parse_node(ctx); + let res = PStatementLike::parse_node(ctx); + expect_semi = res + .node + .as_ref() + .is_some_and(|s| matches!(s, PStatementLike::Statement(..))); statements.push(res.node); - expect_semi = true; if res.recover { ctx.seek_syms(&[Symbol::Semicolon, Symbol::CloseCurly]); if ctx.peek().is_none() { @@ -52,26 +63,34 @@ impl Parsable for PBlock { } } } - if expect_semi { - if let Some(s) = statements.pop() { - result = Some(s.bx()); - } - } - ParseResult::from_recover(Self { statements, result }, recover) + ParseResult::from_recover( + Self { + statements, + ret_last: expect_semi, + }, + recover, + ) } } impl Debug for PBlock { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if !self.statements.is_empty() || self.result.is_some() { + if !self.statements.is_empty() { f.write_str("{\n ")?; let mut padder = Padder::new(f); - for s in &self.statements { + let mut end = self.statements.len(); + if self.ret_last { + end -= 1; + } + for i in 0..end { + let s = &self.statements[i]; // they don't expose wrap_buf :grief: padder.write_str(&format!("{s:?};\n"))?; } - if let Some(res) = &self.result { - padder.write_str(&format!("{res:?}\n"))?; + if self.ret_last + && let Some(s) = self.statements.last() + { + padder.write_str(&format!("{s:?}\n"))?; } f.write_char('}')?; } else { diff --git a/src/parser/v3/nodes/expr.rs b/src/parser/v3/nodes/expr.rs index 7f0a52b..e7cea27 100644 --- a/src/parser/v3/nodes/expr.rs +++ b/src/parser/v3/nodes/expr.rs @@ -1,11 +1,11 @@ use std::fmt::{Debug, Write}; -use crate::common::FilePos; +use crate::{common::FilePos, parser::NodeParsableWith}; use super::{ op::{PInfixOp, UnaryOp}, util::parse_list, - CompilerMsg, Keyword, Node, NodeParsable, PAsmBlock, PBlock, PConstruct, PIdent, PLiteral, + CompilerMsg, Keyword, Node, PAsmBlock, PBlock, PConstruct, PIdent, PLiteral, Parsable, ParseResult, ParserCtx, Symbol, }; @@ -47,7 +47,8 @@ impl Parsable for PExpr { ctx.expect_sym(Symbol::CloseParen)?; Self::Group(res.node.bx()) } else if next.is_symbol(Symbol::OpenCurly) { - Self::Block(PBlock::parse_node(ctx)?) + ctx.next(); + Self::Block(PBlock::parse_node(ctx, Some(Symbol::CloseCurly))?) } else if next.is_keyword(Keyword::If) { ctx.next(); let cond = ctx.parse()?.bx(); @@ -71,7 +72,7 @@ impl Parsable for PExpr { return ctx.parse().map(|n| { let n = n.bx(); if let Some(box Self::BinaryOp(op2, n1, n2)) = n.inner { - let span = start.to(n1.span.end); + let span = start.to(n1.origin.end); Self::BinaryOp(op2, Node::new(Self::UnaryOp(op, n1), span).bx(), n2) } else { Self::UnaryOp(op, n) @@ -138,7 +139,7 @@ pub fn fix_precedence( let Some(box PExpr::BinaryOp(op2, n21, n22)) = n2.inner else { unreachable!(); }; - let span = start.to(n21.span.end); + let span = start.to(n21.origin.end); let (n11, op1, n12) = fix_precedence(n1, op, n21, start); n1 = Node::new(PExpr::BinaryOp(op1, n11, n12), span).bx(); op = op2; diff --git a/src/parser/v3/nodes/func.rs b/src/parser/v3/nodes/func.rs index 55f4c80..a5e8985 100644 --- a/src/parser/v3/nodes/func.rs +++ b/src/parser/v3/nodes/func.rs @@ -1,5 +1,5 @@ use super::{ - util::parse_list, PBlock, PIdent, Keyword, Node, Parsable, ParseResult, ParserCtx, + util::parse_list, PBlock, PIdent, Node, Parsable, ParseResult, ParserCtx, Symbol, PType, PVarDef, }; use std::fmt::Debug; @@ -17,7 +17,6 @@ pub struct PFunction { impl Parsable for PFunctionHeader { fn parse(ctx: &mut ParserCtx) -> ParseResult { - ctx.expect_kw(Keyword::Fn)?; let name = ctx.parse()?; ctx.expect_sym(Symbol::OpenParen)?; // let sel = ctx.maybe_parse(); @@ -48,7 +47,8 @@ impl Parsable for PFunctionHeader { impl Parsable for PFunction { fn parse(ctx: &mut ParserCtx) -> ParseResult { let header = ctx.parse()?; - let body = ctx.parse()?; + ctx.expect_sym(Symbol::OpenCurly)?; + let body = ctx.parse_with(Some(Symbol::CloseCurly))?; ParseResult::Ok(Self { header, body }) } } diff --git a/src/parser/v3/nodes/mod.rs b/src/parser/v3/nodes/mod.rs index fb76572..dc62c4a 100644 --- a/src/parser/v3/nodes/mod.rs +++ b/src/parser/v3/nodes/mod.rs @@ -1,35 +1,46 @@ +mod asm_block; +mod asm_fn; +mod asm_instr; mod block; +mod def; mod expr; mod func; -mod module; +mod ident; +mod lit; mod op; mod statement; -mod lit; -mod ident; -mod ty; -mod def; mod struc; -mod util; mod trai; -mod asm_fn; -mod asm_block; -mod asm_instr; +mod ty; +mod util; +pub use asm_block::*; +pub use asm_fn::*; +pub use asm_instr::*; pub use block::*; +pub use def::*; pub use expr::*; pub use func::*; -pub use module::*; -pub use statement::*; -pub use lit::*; pub use ident::*; -pub use ty::*; -pub use def::*; +pub use lit::*; +pub use op::*; +pub use statement::*; pub use struc::*; pub use trai::*; -pub use op::*; -pub use asm_fn::*; -pub use asm_block::*; -pub use asm_instr::*; +pub use ty::*; +use crate::ir::UProgram; -use super::*; +use super::{lower::{FnLowerCtx, FnLowerable}, *}; + +pub struct PModule { + pub block: Node, +} + +impl PModule { + pub fn parse(ctx: &mut ParserCtx) -> Self { + Self { + block: PBlock::parse_node(ctx, None).node, + } + } +} diff --git a/src/parser/v3/nodes/module.rs b/src/parser/v3/nodes/module.rs deleted file mode 100644 index 2db6556..0000000 --- a/src/parser/v3/nodes/module.rs +++ /dev/null @@ -1,99 +0,0 @@ -use super::{ - PFunction, PImpl, Keyword, Node, Parsable, ParseResult, ParserCtx, CompilerMsg, - PStruct, Symbol, Token, PTrait, -}; -use std::fmt::Debug; - -pub struct PModule { - pub traits: Vec>, - pub structs: Vec>, - pub functions: Vec>, - pub impls: Vec>, -} - -impl Parsable for PModule { - fn parse(ctx: &mut ParserCtx) -> ParseResult { - let mut functions = Vec::new(); - let mut structs = Vec::new(); - let mut traits = Vec::new(); - let mut impls = Vec::new(); - loop { - let Some(next) = ctx.peek() else { - break; - }; - if let Token::Keyword(kw) = next.token { - match kw { - Keyword::Fn => { - let res = ctx.parse(); - functions.push(res.node); - if res.recover { - break; - } - } - Keyword::Struct => { - let res = ctx.parse(); - structs.push(res.node); - if res.recover { - break; - } - } - Keyword::Trait => { - let res = ctx.parse(); - traits.push(res.node); - if res.recover { - break; - } - } - Keyword::Impl => { - let res = ctx.parse(); - impls.push(res.node); - if res.recover { - break; - } - } - _ => { - ctx.err(CompilerMsg::unexpected_token(next, "a definition")); - ctx.next(); - } - } - } else if next.is_symbol(Symbol::Semicolon) { - ctx.hint(CompilerMsg::from_instances( - &[next], - "unneeded semicolon".to_string(), - )); - ctx.next(); - } else { - ctx.err(CompilerMsg::unexpected_token(next, "a definition")); - ctx.next(); - } - } - ParseResult::Ok(Self { - functions, - structs, - traits, - impls, - }) - } -} - -impl Debug for PModule { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - for st in &self.structs { - st.fmt(f)?; - writeln!(f)?; - } - for t in &self.traits { - t.fmt(f)?; - writeln!(f)?; - } - for t in &self.impls { - t.fmt(f)?; - writeln!(f)?; - } - for func in &self.functions { - func.fmt(f)?; - writeln!(f)?; - } - Ok(()) - } -} diff --git a/src/parser/v3/nodes/op.rs b/src/parser/v3/nodes/op.rs index 148268c..455eb81 100644 --- a/src/parser/v3/nodes/op.rs +++ b/src/parser/v3/nodes/op.rs @@ -8,7 +8,7 @@ pub enum PInfixOp { Div, LessThan, GreaterThan, - Access, + Member, Assign, } @@ -22,7 +22,7 @@ impl PInfixOp { Self::Sub => 3, Self::Mul => 4, Self::Div => 5, - Self::Access => 6, + Self::Member => 6, } } pub fn str(&self) -> &str { @@ -33,7 +33,7 @@ impl PInfixOp { Self::Div => "/", Self::LessThan => "<", Self::GreaterThan => ">", - Self::Access => ".", + Self::Member => ".", Self::Assign => "=", } } @@ -45,22 +45,10 @@ impl PInfixOp { Self::Div => true, Self::LessThan => true, Self::GreaterThan => true, - Self::Access => false, + Self::Member => false, Self::Assign => true, } } - pub fn traitt(&self) -> &str { - match self { - Self::Add => "Add", - Self::Sub => "Sub", - Self::Mul => "Mul", - Self::Div => "Div", - Self::LessThan => "LessThan", - Self::GreaterThan => "GreaterThan", - Self::Access => "Access", - Self::Assign => "Assign", - } - } } pub enum UnaryOp { @@ -81,7 +69,7 @@ impl PInfixOp { Symbol::Minus => Self::Sub, Symbol::Asterisk => Self::Mul, Symbol::Slash => Self::Div, - Symbol::Dot => Self::Access, + Symbol::Dot => Self::Member, Symbol::Equals => Self::Assign, _ => { return None; diff --git a/src/parser/v3/nodes/statement.rs b/src/parser/v3/nodes/statement.rs index 8809a9b..6e42d76 100644 --- a/src/parser/v3/nodes/statement.rs +++ b/src/parser/v3/nodes/statement.rs @@ -1,4 +1,7 @@ -use super::{Keyword, Node, PExpr, PVarDef, Parsable, ParseResult, ParserCtx, Symbol, Token}; +use super::{ + Keyword, Node, PExpr, PFunction, PStruct, PVarDef, Parsable, ParseResult, ParserCtx, Symbol, + Token, +}; pub enum PStatement { Let(Node, Node), @@ -6,7 +9,17 @@ pub enum PStatement { Expr(Node), } -impl Parsable for PStatement { +pub enum PConstStatement { + Fn(Node), + Struct(Node), +} + +pub enum PStatementLike { + Statement(PStatement), + Const(PConstStatement), +} + +impl Parsable for PStatementLike { fn parse(ctx: &mut ParserCtx) -> ParseResult { let next = ctx.expect_peek()?; match next.token { @@ -14,17 +27,27 @@ impl Parsable for PStatement { ctx.next(); let def = ctx.parse()?; ctx.expect_sym(Symbol::Equals)?; - ctx.parse().map(|expr| Self::Let(def, expr)) + ctx.parse() + .map(|expr| Self::Statement(PStatement::Let(def, expr))) } Token::Keyword(Keyword::Return) => { ctx.next(); if ctx.peek().is_some_and(|t| t.is_symbol(Symbol::Semicolon)) { - ParseResult::Ok(Self::Return(None)) + ParseResult::Ok(Self::Statement(PStatement::Return(None))) } else { - ctx.parse().map(|res| Self::Return(Some(res))) + ctx.parse() + .map(|res| Self::Statement(PStatement::Return(Some(res)))) } } - _ => ctx.parse().map(Self::Expr), + Token::Keyword(Keyword::Fn) => { + ctx.next(); + ParseResult::Ok(Self::Const(PConstStatement::Fn(ctx.parse()?))) + } + Token::Keyword(Keyword::Struct) => { + ctx.next(); + ParseResult::Ok(Self::Const(PConstStatement::Struct(ctx.parse()?))) + } + _ => ctx.parse().map(|n| Self::Statement(PStatement::Expr(n))), } } } @@ -49,3 +72,25 @@ impl std::fmt::Debug for PStatement { Ok(()) } } +impl std::fmt::Debug for PConstStatement { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Fn(fun) => { + fun.fmt(f)?; + } + Self::Struct(s) => { + s.fmt(f)?; + } + } + Ok(()) + } +} + +impl std::fmt::Debug for PStatementLike { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Statement(s) => s.fmt(f), + Self::Const(c) => c.fmt(f), + } + } +} diff --git a/src/parser/v3/nodes/struc.rs b/src/parser/v3/nodes/struc.rs index 7c0a694..6f72593 100644 --- a/src/parser/v3/nodes/struc.rs +++ b/src/parser/v3/nodes/struc.rs @@ -36,7 +36,6 @@ pub enum PConstructFields { impl Parsable for PStruct { fn parse(ctx: &mut ParserCtx) -> ParseResult { - ctx.expect_kw(Keyword::Struct)?; let name = ctx.parse()?; let mut next = ctx.expect_peek()?; let args = if next.is_symbol(Symbol::OpenAngle) { @@ -75,7 +74,7 @@ impl ParsableWith for PConstruct { let next = ctx.expect_peek()?; // TODO: this is not correct span; type should also span generics, which aren't even in // here yet - let span = name_node.span; + let span = name_node.origin; let name = Node::new( PType { name: name_node, diff --git a/src/parser/v3/parse.rs b/src/parser/v3/parse.rs index 6292acb..0f328dc 100644 --- a/src/parser/v3/parse.rs +++ b/src/parser/v3/parse.rs @@ -147,7 +147,7 @@ impl Node { NodeParseResult { node: Self { inner, - span: start.to(end), + origin: start.to(end), }, recover, } @@ -173,7 +173,7 @@ impl Node { let end = ctx.prev_end(); Some(Self { inner, - span: start.to(end), + origin: start.to(end), }) } } @@ -191,3 +191,19 @@ impl NodeParsable for T { Node::::parse(ctx) } } + +pub trait NodeParsableWith { + type Data; + fn parse_node(ctx: &mut ParserCtx, data: Self::Data) -> NodeParseResult + where + Self: Sized; +} +impl, D> NodeParsableWith for T { + type Data = D; + fn parse_node(ctx: &mut ParserCtx, data: Self::Data) -> NodeParseResult + where + Self: Sized, + { + Node::::parse_with(ctx, data) + } +} diff --git a/src/parser/v3/token/symbol.rs b/src/parser/v3/token/symbol.rs index ccaae43..16c5b0e 100644 --- a/src/parser/v3/token/symbol.rs +++ b/src/parser/v3/token/symbol.rs @@ -34,6 +34,7 @@ pub enum Symbol { Pipe, DoublePipe, Comma, + Hash, } impl Symbol { @@ -68,6 +69,7 @@ impl Symbol { '&' => Self::Ampersand, '|' => Self::Pipe, ',' => Self::Comma, + '#' => Self::Hash, _ => return None, }) } @@ -104,7 +106,7 @@ impl Symbol { Self::Dot => match next { '.' => Self::DoubleDot, _ => return, - } + }, _ => return, }; cursor.advance(); @@ -141,6 +143,7 @@ impl Symbol { Self::DoubleAmpersand => "&&", Self::Pipe => "|", Self::DoublePipe => "||", + Self::Hash => "#", } } }