diff --git a/data/test.lang b/data/test.lang index 83bb172..86a1d26 100644 --- a/data/test.lang +++ b/data/test.lang @@ -1,4 +1,8 @@ fn main() { - let x = 3; - exit(x); + asm { + li a0, 3 + li a7, 93 + ecall + } } + diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs index 943f74b..9431cdd 100644 --- a/src/compiler/mod.rs +++ b/src/compiler/mod.rs @@ -7,7 +7,7 @@ use std::{ mod elf; mod program; -mod riscv64; +pub mod riscv64; mod target; pub use program::*; diff --git a/src/compiler/riscv64/asm.rs b/src/compiler/riscv64/asm.rs index 50b0bac..f17e886 100644 --- a/src/compiler/riscv64/asm.rs +++ b/src/compiler/riscv64/asm.rs @@ -2,34 +2,41 @@ use crate::compiler::program::{Addr, Instr, SymTable, Symbol}; use super::*; +#[derive(Debug, Clone)] pub enum AsmInstruction { - Add(Reg, Reg, Reg), - Addi(Reg, Reg, i32), - Andi(Reg, Reg, i32), - Slli(Reg, Reg, i32), - Srli(Reg, Reg, i32), - Sd(Reg, i32, Reg), - Mv(Reg, Reg), - La(Reg, Symbol), - Jal(Reg, i32), + Add { dest: Reg, src1: Reg, src2: Reg }, + Addi { dest: Reg, src: Reg, imm: i32 }, + Andi { dest: Reg, src: Reg, imm: i32 }, + Slli { dest: Reg, src: Reg, imm: i32 }, + Srli { dest: Reg, src: Reg, imm: i32 }, + Sd { src: Reg, offset: i32, base: Reg }, + Mv { dest: Reg, src: Reg }, + La { dest: Reg, sym: Symbol }, + Jal { dest: Reg, offset: i32 }, Call(Symbol), J(Symbol), Ret, Ecall, - Li(Reg, i32), + Li { dest: Reg, imm: i64 }, } impl Instr for AsmInstruction { - fn push(&self, data: &mut Vec, sym_map: &SymTable, pos: Addr, missing: bool) -> Option { + fn push( + &self, + data: &mut Vec, + sym_map: &SymTable, + pos: Addr, + missing: bool, + ) -> Option { let last = match self { - Self::Add(dest, src1, src2) => add(*dest, *src1, *src2), - Self::Addi(dest, src, imm) => addi(*dest, *src, BitsI32::new(*imm)), - Self::Andi(dest, src, imm) => andi(*dest, *src, BitsI32::new(*imm)), - Self::Slli(dest, src, imm) => slli(*dest, *src, BitsI32::new(*imm)), - Self::Srli(dest, src, imm) => srli(*dest, *src, BitsI32::new(*imm)), - Self::Sd(src, offset, base) => sd(*src, BitsI32::new(*offset), *base), - Self::Mv(dest, src) => addi(*dest, *src, BitsI32::new(0)), - Self::La(dest, sym) => { + Self::Add { dest, src1, src2 } => add(*dest, *src1, *src2), + Self::Addi { dest, src, imm } => addi(*dest, *src, BitsI32::new(*imm)), + Self::Andi { dest, src, imm } => andi(*dest, *src, BitsI32::new(*imm)), + Self::Slli { dest, src, imm } => slli(*dest, *src, BitsI32::new(*imm)), + Self::Srli { dest, src, imm } => srli(*dest, *src, BitsI32::new(*imm)), + Self::Sd { src, offset, base } => sd(*src, BitsI32::new(*offset), *base), + Self::Mv { dest, src } => addi(*dest, *src, BitsI32::new(0)), + Self::La { dest, sym } => { if let Some(addr) = sym_map.get(*sym) { let offset = addr.val() as i32 - pos.val() as i32; data.extend(auipc(*dest, BitsI32::new(0)).to_le_bytes()); @@ -39,7 +46,7 @@ impl Instr for AsmInstruction { return Some(*sym); } } - Self::Jal(dest, offset) => jal(*dest, BitsI32::new(*offset)), + Self::Jal { dest, offset } => jal(*dest, BitsI32::new(*offset)), Self::J(sym) => { if let Some(addr) = sym_map.get(*sym) { let offset = addr.val() as i32 - pos.val() as i32; @@ -60,7 +67,7 @@ impl Instr for AsmInstruction { } Self::Ret => ret(), Self::Ecall => ecall(), - Self::Li(reg, val) => addi(*reg, zero, BitsI32::new(*val)), + Self::Li { dest, imm } => addi(*dest, zero, BitsI32::new(*imm as i32)), }; data.extend(last.to_le_bytes()); None diff --git a/src/compiler/riscv64/mod.rs b/src/compiler/riscv64/mod.rs index 7fb6867..7f888c7 100644 --- a/src/compiler/riscv64/mod.rs +++ b/src/compiler/riscv64/mod.rs @@ -2,14 +2,17 @@ mod asm; mod base; mod funct; mod opcode; +mod parse; mod reg; mod single; use super::{create_program, elf, SymMap}; use crate::util::BitsI32; +pub use asm::*; use base::*; use funct::{op::*, width}; use opcode::*; +pub use parse::*; pub use reg::*; use single::*; @@ -22,23 +25,35 @@ pub fn gen() -> Vec { let print_stuff = table.reserve(); let start = table.push_fn(vec![ I::Call(*print_stuff), - I::Li(a0, 0), - I::Li(a7, 93), + I::Li { dest: a0, imm: 0 }, + I::Li { dest: a7, imm: 93 }, I::Ecall, - I::Jal(zero, 0), + I::Jal { + dest: zero, + offset: 0, + }, ]); table.write_fn( print_stuff, vec![ - I::Li(a0, 1), - I::La(a1, msg), - I::Li(a2, len as i32), - I::Li(a7, 64), + I::Li { dest: a0, imm: 1 }, + I::La { dest: a1, sym: msg }, + I::Li { + dest: a2, + imm: len as i64, + }, + I::Li { dest: a7, imm: 64 }, I::Ecall, - I::Li(a0, 1), - I::La(a1, msg2), - I::Li(a2, len2 as i32), - I::Li(a7, 64), + I::Li { dest: a0, imm: 1 }, + I::La { + dest: a1, + sym: msg2, + }, + I::Li { + dest: a2, + imm: len2 as i64, + }, + I::Li { dest: a7, imm: 64 }, I::Ecall, I::Ret, ], diff --git a/src/compiler/riscv64/parse.rs b/src/compiler/riscv64/parse.rs new file mode 100644 index 0000000..7f39da8 --- /dev/null +++ b/src/compiler/riscv64/parse.rs @@ -0,0 +1,104 @@ +use super::{reg::*, AsmInstruction, Reg}; +use crate::parser::{Parsable, ParseResult, ParserMsg, ParserOutput, Symbol, Token}; + +impl Parsable for AsmInstruction { + fn parse( + cursor: &mut crate::parser::TokenCursor, + output: &mut ParserOutput, + ) -> ParseResult { + let t = cursor.expect_next()?; + let span = t.span; + match &t.token { + Token::Word(w) => ParseResult::Ok(match w.as_str() { + "ecall" => Self::Ecall, + "li" => { + let dest = Reg::parse(cursor, output)?; + cursor.expect_sym(Symbol::Comma)?; + let imm = i64::parse(cursor, output)?; + Self::Li { dest, imm } + } + _ => { + return ParseResult::Err(ParserMsg::from_span( + span, + format!("Unknown instruction {}", w), + )) + } + }), + _ => return ParseResult::Err(ParserMsg::unexpected_token(&t, "assembly or }")), + } + } +} + +impl Parsable for Reg { + fn parse( + cursor: &mut crate::parser::TokenCursor, + output: &mut ParserOutput, + ) -> ParseResult { + let next = cursor.expect_next()?; + let Token::Word(word) = next.token else { + return ParseResult::Err(ParserMsg::unexpected_token(&next, "a riscv register")); + }; + ParseResult::Ok(match word.as_str() { + "zero" => zero, + "ra" => ra, + "sp" => sp, + "gp" => gp, + "tp" => tp, + "t0" => t0, + "t1" => t1, + "t2" => t2, + "fp" => fp, + "s0" => s0, + "s1" => s1, + "a0" => a0, + "a1" => a1, + "a2" => a2, + "a3" => a3, + "a4" => a4, + "a5" => a5, + "a6" => a6, + "a7" => a7, + "s2" => s2, + "s3" => s3, + "s4" => s4, + "s5" => s5, + "s6" => s6, + "s7" => s7, + "s8" => s8, + "s9" => s9, + "s10" => s10, + "s11" => s11, + "t3" => t3, + "t4" => t4, + "t5" => t5, + "t6" => t6, + other => { + return ParseResult::Err(ParserMsg::from_span( + next.span, + format!("Unknown reg name {}", other), + )); + } + }) + } +} + +impl Parsable for i64 { + fn parse( + cursor: &mut crate::parser::TokenCursor, + _output: &mut ParserOutput, + ) -> ParseResult { + let next = cursor.expect_next()?; + let span = next.span; + let Token::Word(word) = next.token else { + return ParseResult::Err(ParserMsg::unexpected_token(&next, "an i32")); + }; + let res = word.parse::(); + match res { + Ok(int) => ParseResult::Ok(int), + Err(_) => ParseResult::Err(ParserMsg::from_span( + span, + format!("Expected an i32, found {}", word), + )), + } + } +} diff --git a/src/parser/v3/token/file.rs b/src/ir/file.rs similarity index 100% rename from src/parser/v3/token/file.rs rename to src/ir/file.rs diff --git a/src/ir/mod.rs b/src/ir/mod.rs index db7f61f..f800255 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -1,278 +1,8 @@ -use std::{ - collections::HashMap, - ops::{Deref, DerefMut}, -}; +mod namespace; +mod structure; +mod file; -use crate::parser::{ - Body, Expr, FileSpan, Function, Ident, Literal, Module, ParserError, ParserErrors, Statement, -}; +pub use namespace::*; +pub use structure::*; +pub use file::*; -#[derive(Debug)] -pub enum IRInstruction { - Li(Var, Literal), - Mv(Var, Var), - Not(Var, Var), - Noti(Var, Literal), - La(Var, IRIdent), - Call(FnIdent, Vec), -} - -#[derive(Debug)] -pub struct IRFunction { - instructions: Vec, -} - -impl Module { - pub fn lower(&self, map: &mut Namespace, errors: &mut ParserErrors) { - for f in &self.functions { - if let Some(f) = f.as_ref() { - f.lower(map, errors); - } - } - } -} - -impl Function { - pub fn lower(&self, map: &mut Namespace, errors: &mut ParserErrors) { - let Some(name) = self.name.as_ref() else { - return; - }; - if map.get(name).is_some() { - errors.add(ParserError { - msg: format!("Already something named '{:?}'", self.name), - spans: vec![self.name.span], - }); - } else { - let f = map.reserve_fn(self.name.span); - let mut instructions = Vec::new(); - if let Some(b) = self.body.as_ref() { - b.lower(map, &mut instructions, errors) - } - map.write_fn(name, f, IRFunction { instructions }); - } - } -} - -impl Body { - pub fn lower( - &self, - map: &mut Namespace, - instructions: &mut Vec, - errors: &mut ParserErrors, - ) { - let mut map = map.push(); - for statement in &self.statements { - let Some(statement) = statement.as_ref() else { - continue; - }; - match statement { - Statement::Let(name_node, expr) => { - let Some(name) = name_node.as_ref() else { - continue; - }; - let Some(expr) = expr.as_ref() else { - continue; - }; - let res = expr.lower(&mut map, instructions, errors); - let name = map.add_var(name, name_node.span); - if let Some(res) = res { - instructions.push(match res { - ExprResult::Lit(l) => IRInstruction::Li(name, l), - ExprResult::Var(i) => IRInstruction::Mv(name, i), - ExprResult::Fn(f) => todo!(), - }); - } - } - Statement::Return(e) => todo!(), - Statement::Expr(expr) => { - expr.as_ref().map(|e| e.lower(&mut map, instructions, errors)); - } - } - } - } -} - -impl Expr { - pub fn lower( - &self, - map: &mut Namespace, - instructions: &mut Vec, - errors: &mut ParserErrors, - ) -> Option { - match self { - Expr::Lit(l) => Some(ExprResult::Lit(l.as_ref()?.clone())), - Expr::Ident(i) => { - let Some(id) = map.get(i.as_ref()?) else { - errors.add(ParserError::identifier_not_found(i)); - return None; - }; - match id.ty() { - IdentTypeMatch::Var(var) => Some(ExprResult::Var(var)), - IdentTypeMatch::Fn(f) => Some(ExprResult::Fn(f)), - } - } - Expr::BinaryOp(_, _, _) => todo!(), - Expr::UnaryOp(op, e) => { - let res = e.as_ref()?.lower(&mut map, instructions, errors)?; - let res = match op { - crate::parser::UnaryOperator::Not => { - let temp = map.reserve_var(e.span); - match res { - ExprResult::Lit(l) => instructions.push(IRInstruction::Noti(temp, l)), - ExprResult::Var(i) => instructions.push(IRInstruction::Not(temp, i)), - ExprResult::Fn(_) => { - errors.add(ParserError::from_span( - e.span, - "Cannot call not on a function".to_string(), - )); - return None; - } - } - temp - } - crate::parser::UnaryOperator::Ref => todo!(), - }; - Some(ExprResult::Var(res)) - } - Expr::Block(_) => todo!(), - Expr::Call(e, args) => { - let e = e.as_ref()?.lower(&mut map, instructions, errors); - let args = args.iter().map(|a| a.as_ref()?.lower(map, instructions, errors)).collect(); - if let Some(r) = e { - let fun = match r { - ExprResult::Lit(literal) => todo!(), - ExprResult::Var(var) => todo!(), - ExprResult::Fn(f) => { - instructions.push(IRInstruction::Call(f, args)); - }, - }; - } else { - todo!(); - } - }, - Expr::Group(e) => e.as_ref()?.lower(&mut map, instructions, errors), - } - } -} - -pub enum ExprResult { - Lit(Literal), - Var(Var), - Fn(FnIdent), -} - -#[derive(Debug)] -pub struct Namespace { - pub fns: Vec>, - pub vars: usize, - pub stack: Vec>, -} - -impl Namespace { - pub fn new() -> Self { - Self { - fns: Vec::new(), - vars: 0, - stack: vec![HashMap::new()], - } - } - pub fn push(&mut self) -> NamespaceGuard { - self.stack.push(HashMap::new()); - NamespaceGuard(self) - } - pub fn get(&self, name: &Ident) -> Option { - for map in self.stack.iter().rev() { - let res = map.get(name.val()); - if res.is_some() { - return res.copied(); - } - } - None - } - pub fn reserve_var(&mut self, origin: FileSpan) -> Var { - let i = self.vars; - self.vars += 1; - Var(IRIdent { - origin, - ty: IdentType::Var, - i, - }) - } - pub fn reserve_fn(&mut self, origin: FileSpan) -> FnIdent { - let i = self.fns.len(); - self.fns.push(None); - FnIdent(IRIdent { - origin, - ty: IdentType::Fn, - i, - }) - } - pub fn write_fn(&mut self, name: &Ident, id: FnIdent, f: IRFunction) -> IRIdent { - self.insert(name, id.0); - self.fns[id.0.i] = Some(f); - id.0 - } - pub fn add_var(&mut self, name: &Ident, origin: FileSpan) -> Var { - let id = self.reserve_var(origin); - self.insert(name, id.0); - id - } - fn insert(&mut self, name: &Ident, id: IRIdent) { - let last = self.stack.len() - 1; - self.stack[last].insert(name.val().to_string(), id); - } -} - -pub struct NamespaceGuard<'a>(&'a mut Namespace); - -impl Drop for NamespaceGuard<'_> { - fn drop(&mut self) { - self.0.stack.pop(); - } -} - -impl Deref for NamespaceGuard<'_> { - type Target = Namespace; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for NamespaceGuard<'_> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -#[derive(Debug, Clone, Copy)] -pub struct IRIdent { - origin: FileSpan, - ty: IdentType, - i: usize, -} - -#[derive(Debug, Clone, Copy)] -pub struct FnIdent(IRIdent); -#[derive(Debug, Clone, Copy)] -pub struct Var(IRIdent); - -#[derive(Debug, Clone, Copy)] -pub enum IdentType { - Var, - Fn, -} - -#[derive(Debug, Clone, Copy)] -pub enum IdentTypeMatch { - Var(Var), - Fn(FnIdent), -} - -impl IRIdent { - pub fn ty(self) -> IdentTypeMatch { - match self.ty { - IdentType::Var => IdentTypeMatch::Var(Var(self)), - IdentType::Fn => IdentTypeMatch::Fn(FnIdent(self)), - } - } -} diff --git a/src/ir/namespace.rs b/src/ir/namespace.rs new file mode 100644 index 0000000..24ffe2e --- /dev/null +++ b/src/ir/namespace.rs @@ -0,0 +1,241 @@ +use std::{ + collections::HashMap, + fmt::Debug, + ops::{Deref, DerefMut}, +}; + +use super::{BuiltinType, FileSpan, FnDef, Function, Type, TypeDef, VarDef}; + +pub struct Namespace { + pub fn_defs: Vec, + pub var_defs: Vec, + pub type_defs: Vec, + pub fns: Vec>, + pub temp: usize, + pub stack: Vec>, +} + +impl Namespace { + pub fn new() -> Self { + let mut s = Self { + fn_defs: Vec::new(), + var_defs: Vec::new(), + type_defs: Vec::new(), + fns: Vec::new(), + temp: 0, + stack: vec![HashMap::new()], + }; + for b in BuiltinType::enumerate() { + s.def_type(b.def()); + } + s + } + pub fn push(&mut self) -> NamespaceGuard { + self.stack.push(HashMap::new()); + NamespaceGuard(self) + } + pub fn get(&self, name: &str) -> Option { + for map in self.stack.iter().rev() { + let res = map.get(name); + if res.is_some() { + return res.cloned(); + } + } + None + } + pub fn get_var(&self, id: VarIdent) -> &VarDef { + &self.var_defs[id.0] + } + pub fn get_fn(&self, id: FnIdent) -> &FnDef { + &self.fn_defs[id.0] + } + pub fn get_type(&self, id: TypeIdent) -> &TypeDef { + &self.type_defs[id.0] + } + pub fn alias_fn(&mut self, name: &str, id: FnIdent) { + self.insert(name, Ident::Fn(id)); + } + pub fn name_var(&mut self, def: &VarDef, var: VarIdent) { + self.insert(&def.name, Ident::Var(var)); + } + pub fn def_var(&mut self, var: VarDef) -> VarIdent { + let i = self.var_defs.len(); + self.var_defs.push(var); + VarIdent(i) + } + pub fn temp_var(&mut self, origin: FileSpan, ty: Type) -> VarIdent { + let v = self.def_var(VarDef { + name: format!("temp{}", self.temp), + origin: super::Origin::File(origin), + ty, + }); + self.temp += 1; + v + } + pub fn def_fn(&mut self, def: FnDef) -> FnIdent { + let i = self.fn_defs.len(); + let id = FnIdent(i); + self.insert(&def.name, Ident::Fn(id)); + self.fn_defs.push(def); + self.fns.push(None); + id + } + pub fn def_type(&mut self, def: TypeDef) -> TypeIdent { + let i = self.type_defs.len(); + let id = TypeIdent(i); + self.insert(&def.name, Ident::Type(id)); + self.type_defs.push(def); + id + } + pub fn type_name(&self, ty: &Type) -> String { + let mut str = String::new(); + match ty { + Type::Concrete(t) => { + str += &self.get_type(*t).name; + } + Type::Generic { base, args } => { + str += &self.get_type(*base).name; + if let Some(arg) = args.first() { + str = str + "<" + &self.type_name(arg); + } + for arg in args.iter().skip(1) { + str = str + ", " + &self.type_name(arg); + } + if !args.is_empty() { + str += ">"; + } + } + Type::Fn { args, ret } => { + str += "fn("; + if let Some(arg) = args.first() { + str += &self.type_name(arg); + } + for arg in args.iter().skip(1) { + str = str + ", " + &self.type_name(arg); + } + str += ") -> "; + str += &self.type_name(ret); + } + Type::Ref(t) => { + str = str + "&" + &self.type_name(t); + } + Type::Error => str += "{error}", + Type::Infer => str += "{inferred}", + } + str + } + fn insert(&mut self, name: &str, id: Ident) { + let idx = self.stack.len() - 1; + let last = &mut self.stack[idx]; + if let Some(l) = last.get_mut(name) { + l.insert(id); + } else { + last.insert(name.to_string(), Idents::new(id)); + } + } + pub fn write_fn(&mut self, id: FnIdent, f: Function) { + self.fns[id.0] = Some(f); + } +} + +pub struct NamespaceGuard<'a>(&'a mut Namespace); + +impl Drop for NamespaceGuard<'_> { + fn drop(&mut self) { + self.0.stack.pop(); + } +} + +impl Deref for NamespaceGuard<'_> { + type Target = Namespace; + fn deref(&self) -> &Self::Target { + self.0 + } +} + +impl DerefMut for NamespaceGuard<'_> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.0 + } +} + +#[derive(Debug, Clone, Copy)] +pub enum Ident { + Var(VarIdent), + Fn(FnIdent), + Type(TypeIdent), +} + +#[derive(Debug, Clone, Copy)] +pub struct Idents { + pub latest: Ident, + pub var: Option, + pub func: Option, + pub var_func: Option, + pub ty: Option, +} + +impl Idents { + fn new(latest: Ident) -> Self { + let mut s = Self { + latest, + var: None, + func: None, + var_func: None, + ty: None, + }; + s.insert(latest); + s + } + fn insert(&mut self, i: Ident) { + self.latest = i; + match i { + Ident::Var(v) => { + self.var = Some(v); + self.var_func = Some(VarOrFnIdent::Var(v)); + } + Ident::Fn(f) => { + self.func = Some(f); + self.var_func = Some(VarOrFnIdent::Fn(f)); + } + Ident::Type(t) => self.ty = Some(t), + } + } +} + +#[derive(Clone, Copy)] +pub struct TypeIdent(usize); +#[derive(Clone, Copy)] +pub struct VarIdent(usize); +#[derive(Clone, Copy)] +pub struct FnIdent(usize); + +#[derive(Debug, Clone, Copy)] +pub enum VarOrFnIdent { + Var(VarIdent), + Fn(FnIdent), +} + +impl TypeIdent { + pub fn builtin(ty: &BuiltinType) -> Self { + Self(*ty as usize) + } +} + +impl Debug for VarIdent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "v{}", self.0) + } +} + +impl Debug for TypeIdent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "t{}", self.0) + } +} + +impl Debug for FnIdent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "f{}", self.0) + } +} diff --git a/src/ir/old.rs b/src/ir/old.rs new file mode 100644 index 0000000..2ac5328 --- /dev/null +++ b/src/ir/old.rs @@ -0,0 +1,226 @@ +#[derive(Debug)] +pub enum IRInstruction { + Li(Var, Literal), + Mv(Var, Var), + Not(Var, Var), + Add(Var, Var, Var), + La(Var, IRIdent), + Call(Var, FnIdent, Vec), +} + +#[derive(Debug)] +pub struct IRFunction { + args: Vec, + instructions: Vec, +} + +impl Module { + pub fn lower(&self, map: &mut Namespace, errors: &mut ParserErrors) { + let mut fns = Vec::new(); + for f in &self.functions { + if let Some(f) = f.as_ref() { + if let Some(id) = f.reserve(map, errors) { + fns.push((id, f)); + } + } + } + for (id, f) in fns { + f.lower(id, map, errors); + } + } +} + +impl Function { + pub fn reserve(&self, map: &mut Namespace, errors: &mut ParserErrors) -> Option { + let name = self.name.as_ref()?; + if let Some(other) = map.get(name) { + errors.add(ParserError { + msg: format!("Already {:?} named '{:?}'", other.ty, self.name), + spans: vec![self.name.span, other.origin], + }); + None + } else { + Some(map.reserve_fn(name, self.name.span)) + } + } + pub fn lower( + &self, + ident: FnIdent, + map: &mut Namespace, + errors: &mut ParserErrors, + ) -> Option<()> { + let mut instructions = Vec::new(); + let mut map = map.push(); + let mut args = Vec::new(); + for arg in &self.args { + args.push(map.def_var(arg.as_ref()?, arg.span)?); + } + if let Some(b) = self.body.as_ref() { + b.lower(&mut map, &mut instructions, errors) + } + map.write_fn(ident, IRFunction { instructions, args }); + Some(()) + } +} + +impl Body { + pub fn lower( + &self, + map: &mut Namespace, + instructions: &mut Vec, + errors: &mut ParserErrors, + ) { + let mut map = map.push(); + for statement in &self.statements { + let Some(statement) = statement.as_ref() else { + continue; + }; + match statement { + Statement::Let(name_node, expr) => { + let Some(name) = name_node.as_ref() else { + continue; + }; + let res = expr.lower(&mut map, instructions, errors); + if let Some(res) = res { + match res { + ExprResult::Var(v) => map.name_var(name, v), + ExprResult::Fn(f) => todo!(), + }; + } + } + Statement::Return(e) => todo!(), + Statement::Expr(expr) => { + expr.lower(&mut map, instructions, errors); + } + } + } + } +} + +impl Node> { + pub fn lower( + &self, + map: &mut Namespace, + instructions: &mut Vec, + errors: &mut ParserErrors, + ) -> Option { + self.as_ref()?.lower(self.span, map, instructions, errors) + } +} + +impl Node { + pub fn lower( + &self, + map: &mut Namespace, + instructions: &mut Vec, + errors: &mut ParserErrors, + ) -> Option { + self.as_ref()?.lowerr(self.span, map, instructions, errors) + } +} + +impl Expr { + pub fn lowerr( + &self, + span: FileSpan, + map: &mut Namespace, + instructions: &mut Vec, + errors: &mut ParserErrors, + ) -> Option { + match self { + Expr::Lit(l) => { + let temp = map.temp_var(span); + instructions.push(IRInstruction::Li(temp, l.as_ref()?.clone())); + Some(ExprResult::Var(temp)) + }, + Expr::Ident(i) => { + let Some(id) = map.get(i.as_ref()?) else { + errors.add(ParserError::identifier_not_found(i)); + return None; + }; + match id.ty() { + IdentTypeMatch::Var(var) => Some(ExprResult::Var(var)), + IdentTypeMatch::Fn(f) => Some(ExprResult::Fn(f)), + } + } + Expr::BinaryOp(op, e1, e2) => { + let res1 = e1.lower(map, instructions, errors)?; + let res2 = e2.lower(map, instructions, errors)?; + let (ExprResult::Var(v1), ExprResult::Var(v2)) = (res1, res2) else { + errors.add(ParserError::from_span(span, "Cannot operate on functions".to_string())); + return None; + }; + let temp = map.temp_var(span); + match op { + crate::parser::BinaryOperator::Add => { + instructions.push(IRInstruction::Add(temp, v1, v2)) + } + crate::parser::BinaryOperator::Sub => todo!(), + crate::parser::BinaryOperator::Mul => todo!(), + crate::parser::BinaryOperator::Div => todo!(), + crate::parser::BinaryOperator::LessThan => todo!(), + crate::parser::BinaryOperator::GreaterThan => todo!(), + crate::parser::BinaryOperator::Access => todo!(), + crate::parser::BinaryOperator::Assign => todo!(), + } + Some(ExprResult::Var(temp)) + } + Expr::UnaryOp(op, e) => { + let res = e.lower(map, instructions, errors)?; + let res = match op { + crate::parser::UnaryOperator::Not => { + let temp = map.temp_var(span); + match res { + ExprResult::Var(i) => instructions.push(IRInstruction::Not(temp, i)), + ExprResult::Fn(_) => { + errors.add(ParserError::from_span( + span, + "Cannot call not on a function".to_string(), + )); + return None; + } + } + temp + } + crate::parser::UnaryOperator::Ref => todo!(), + }; + Some(ExprResult::Var(res)) + } + Expr::Block(_) => todo!(), + Expr::Call(e, args) => { + let fe = e.lower(map, instructions, errors); + let mut nargs = Vec::new(); + for arg in args.iter() { + let arg = arg.lower(map, instructions, errors)?; + nargs.push(arg); + } + if let Some(r) = fe { + match r { + ExprResult::Fn(f) => { + let temp = map.temp_var(span); + instructions.push(IRInstruction::Call(temp, f, nargs)); + Some(ExprResult::Var(temp)) + } + o => { + errors.add(ParserError::from_span( + span, + "Expected function".to_string(), + )); + None + } + } + } else { + None + } + } + Expr::Group(e) => e.lower(map, instructions, errors), + } + } +} + +#[derive(Debug)] +pub enum ExprResult { + Var(Var), + Fn(FnIdent), +} + diff --git a/src/ir/structure/def.rs b/src/ir/structure/def.rs new file mode 100644 index 0000000..0ab1110 --- /dev/null +++ b/src/ir/structure/def.rs @@ -0,0 +1,37 @@ +use super::{FileSpan, Type}; +use std::fmt::Debug; + +pub struct FnDef { + pub name: String, + pub args: Vec, + pub ret: Type, + pub origin: Origin, +} + +pub struct TypeDef { + pub name: String, + pub args: usize, + pub origin: Origin, +} + +#[derive(Clone)] +pub struct VarDef { + pub name: String, + pub ty: Type, + pub origin: Origin, +} + +#[derive(Debug, Clone, Copy)] +pub enum Origin { + Builtin, + File(FileSpan), +} + +impl FnDef { + pub fn ty(&self) -> Type { + Type::Fn { + args: self.args.iter().map(|a| a.ty.clone()).collect(), + ret: Box::new(self.ret.clone()), + } + } +} diff --git a/src/ir/structure/func.rs b/src/ir/structure/func.rs new file mode 100644 index 0000000..1e8d7ea --- /dev/null +++ b/src/ir/structure/func.rs @@ -0,0 +1,56 @@ +use crate::compiler::riscv64::AsmInstruction; + +use super::{FnIdent, VarIdent}; + +#[derive(Debug)] +pub struct Function { + instructions: Vec, +} + +#[derive(Debug)] +pub enum Instruction { + Mv { + dest: VarIdent, + src: VarIdent, + }, + Ref { + dest: VarIdent, + src: VarIdent, + }, + Lf { + dest: VarIdent, + src: FnIdent, + }, + Call { + dest: VarIdent, + f: FnIdent, + args: Vec, + }, + AsmBlock { + instructions: Vec, + }, + Ret { + src: VarIdent, + }, +} + +pub struct Instructions { + vec: Vec, +} + +impl Function { + pub fn new(instructions: Instructions) -> Self { + Self { + instructions: instructions.vec, + } + } +} + +impl Instructions { + pub fn new() -> Self { + Self { vec: Vec::new() } + } + pub fn push(&mut self, i: Instruction) { + self.vec.push(i); + } +} diff --git a/src/ir/structure/mod.rs b/src/ir/structure/mod.rs new file mode 100644 index 0000000..93fd016 --- /dev/null +++ b/src/ir/structure/mod.rs @@ -0,0 +1,9 @@ +mod def; +mod func; +mod ty; + +use super::*; +pub use def::*; +pub use func::*; +pub use ty::*; + diff --git a/src/ir/structure/ty.rs b/src/ir/structure/ty.rs new file mode 100644 index 0000000..e8d7ad5 --- /dev/null +++ b/src/ir/structure/ty.rs @@ -0,0 +1,35 @@ +use super::{Origin, TypeDef, TypeIdent}; + +#[derive(Clone)] +pub enum Type { + Concrete(TypeIdent), + Generic { base: TypeIdent, args: Vec }, + Fn { args: Vec, ret: Box }, + Ref(Box), + Infer, + Error, +} + +#[repr(usize)] +#[derive(Debug, Clone, Copy)] +pub enum BuiltinType { + Unit, +} + +impl BuiltinType { + pub fn enumerate() -> &'static [Self; 1] { + &[Self::Unit] + } + pub fn def(&self) -> TypeDef { + match self { + BuiltinType::Unit => TypeDef { + name: "()".to_string(), + args: 0, + origin: Origin::Builtin, + }, + } + } + pub fn id(&self) -> TypeIdent { + TypeIdent::builtin(self) + } +} diff --git a/src/main.rs b/src/main.rs index 6c15b86..7f505d7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,54 @@ #![feature(box_patterns)] #![feature(try_trait_v2)] -mod util; +use std::io::{stdout, BufRead, BufReader}; + +use ir::Namespace; +use parser::{Module, NodeParsable, ParserOutput, Statement, TokenCursor}; + mod compiler; mod ir; mod parser; +mod util; fn main() { let arg = std::env::args_os().nth(1); if let Some(path) = arg { let file = std::fs::read_to_string(path).expect("failed to read file"); - println!("{file}"); - parser::parse_file(&file); + run_file(&file); } else { - parser::run_stdin(); + run_stdin(); } // compiler::main(); } + +fn run_file(file: &str) { + let mut output = ParserOutput::new(); + let res = Module::parse_node(&mut TokenCursor::from(file), &mut output); + println!("{:?}", res.node); + if let Some(module) = res.node.as_ref() { + let mut namespace = Namespace::new(); + module.lower(&mut namespace.push(), &mut output); + println!("{:?}", namespace.fns); + } + output.write_for(&mut stdout(), file); +} + +pub fn run_stdin() { + for line in BufReader::new(std::io::stdin()).lines() { + let mut output = ParserOutput::new(); + let str = &line.expect("failed to read line"); + let mut cursor = TokenCursor::from(&str[..]); + if let Some(expr) = Statement::parse_node(&mut cursor, &mut output) + .node + .as_ref() + { + if cursor.next().is_none() { + println!("{:?}", expr); + } else { + println!("uhhhh ehehe"); + } + } + output.write_for(&mut stdout(), str); + } +} diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 65b5018..5bc0935 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1,5 +1,5 @@ -mod v1; -mod v2; +// mod v1; +// mod v2; mod v3; pub use v3::*; diff --git a/src/parser/v3/cursor.rs b/src/parser/v3/cursor.rs index 70bf0d9..c4f0a99 100644 --- a/src/parser/v3/cursor.rs +++ b/src/parser/v3/cursor.rs @@ -1,6 +1,7 @@ -use super::error::ParserError; +use crate::ir::FilePos; + +use super::error::ParserMsg; use super::token::{CharCursor, Keyword, Symbol, Token, TokenInstance}; -use super::FilePos; pub struct TokenCursor<'a> { cursor: CharCursor<'a>, @@ -15,19 +16,19 @@ impl<'a> TokenCursor<'a> { self.next_pos = self.cursor.next_pos(); std::mem::replace(&mut self.next, TokenInstance::parse(&mut self.cursor)) } - pub fn expect_next(&mut self) -> Result { - self.peek().ok_or(ParserError::unexpected_end())?; + pub fn expect_next(&mut self) -> Result { + self.peek().ok_or(ParserMsg::unexpected_end())?; Ok(self.next().unwrap()) } - pub fn expect_token(&mut self, t: Token) -> Result<(), ParserError> { + pub fn expect_token(&mut self, t: Token) -> Result<(), ParserMsg> { let next = self.expect_next()?; if t == next.token { Ok(()) } else { - Err(ParserError::unexpected_token(&next, &format!("{t:?}"))) + Err(ParserMsg::unexpected_token(&next, &format!("{t:?}"))) } } - pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), ParserError> { + pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), ParserMsg> { self.expect_token(Token::Symbol(symbol)) } pub fn seek_sym(&mut self, symbol: Symbol) { @@ -52,14 +53,14 @@ impl<'a> TokenCursor<'a> { self.next(); } } - pub fn expect_kw(&mut self, kw: Keyword) -> Result<(), ParserError> { + pub fn expect_kw(&mut self, kw: Keyword) -> Result<(), ParserMsg> { self.expect_token(Token::Keyword(kw)) } pub fn peek(&self) -> Option<&TokenInstance> { self.next.as_ref() } - pub fn expect_peek(&mut self) -> Result<&TokenInstance, ParserError> { - self.peek().ok_or(ParserError::unexpected_end()) + pub fn expect_peek(&mut self) -> Result<&TokenInstance, ParserMsg> { + self.peek().ok_or(ParserMsg::unexpected_end()) } pub fn chars(&mut self) -> &mut CharCursor<'a> { &mut self.cursor diff --git a/src/parser/v3/error.rs b/src/parser/v3/error.rs index 1057903..e0a07f8 100644 --- a/src/parser/v3/error.rs +++ b/src/parser/v3/error.rs @@ -1,21 +1,21 @@ -use super::{ - token::{FileSpan, TokenInstance}, - FilePos, Ident, Node, -}; +use crate::ir::{FilePos, FileSpan}; + +use super::{token::TokenInstance, Ident, Node}; #[derive(Debug, Clone)] -pub struct ParserError { +pub struct ParserMsg { pub msg: String, pub spans: Vec, } -pub struct ParserErrors { - pub errs: Vec, +pub struct ParserOutput { + pub errs: Vec, + pub hints: Vec, } -impl ParserError { +impl ParserMsg { pub fn from_instances(instances: &[&TokenInstance], msg: String) -> Self { - ParserError { + ParserMsg { msg, spans: instances.iter().map(|i| i.span).collect(), } @@ -49,14 +49,14 @@ impl ParserError { } pub fn unexpected_token(inst: &TokenInstance, expected: &str) -> Self { let t = &inst.token; - ParserError::from_instances( + ParserMsg::from_instances( &[inst], format!("unexpected token {t:?}; expected {expected}"), ) } - pub fn write_for(&self, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> { + pub fn write_for(&self, ty: &str, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> { let after = if self.spans.is_empty() { "" } else { ":" }; - writeln!(writer, "error: {}{}", self.msg, after)?; + writeln!(writer, "{}: {}{}", ty, self.msg, after)?; for span in &self.spans { span.write_for(writer, file)?; } @@ -64,11 +64,25 @@ impl ParserError { } } -impl ParserErrors { +impl ParserOutput { pub fn new() -> Self { - Self { errs: Vec::new() } + Self { + errs: Vec::new(), + hints: Vec::new(), + } } - pub fn add(&mut self, err: ParserError) { + pub fn err(&mut self, err: ParserMsg) { self.errs.push(err); } + pub fn hint(&mut self, err: ParserMsg) { + self.hints.push(err); + } + pub fn write_for(&self, out: &mut impl std::io::Write, file: &str) { + for err in &self.errs { + err.write_for("error", out, file).unwrap(); + } + for hint in &self.hints { + hint.write_for("hint", out, file).unwrap(); + } + } } diff --git a/src/parser/v3/lower/block.rs b/src/parser/v3/lower/block.rs new file mode 100644 index 0000000..f2e7464 --- /dev/null +++ b/src/parser/v3/lower/block.rs @@ -0,0 +1,58 @@ +use crate::ir::Instruction; + +use super::{Block, ExprResult, FnLowerCtx, Node, Statement}; + +impl Node { + pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + self.as_ref()?.lower(ctx) + } +} + +impl Block { + pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + let ctx = &mut ctx.sub(); + for statement in &self.statements { + statement.lower(ctx); + } + self.result.as_ref()?.lower(ctx) + } +} + +impl Node> { + pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + self.as_ref()?.lower(ctx) + } +} + +impl Node { + pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + self.as_ref()?.lower(ctx) + } +} + +impl Statement { + pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + match self { + super::Statement::Let(def, e) => { + let def = def.lower(ctx.map, ctx.output)?; + let res = e.lower(ctx); + if let Some(res) = res { + match res { + ExprResult::Var(v) => ctx.map.name_var(&def, v), + ExprResult::Fn(_) => todo!(), + } + } + None + } + super::Statement::Return(e) => { + let res = e.lower(ctx)?; + match res { + ExprResult::Var(v) => ctx.push(Instruction::Ret { src: v }), + _ => todo!(), + } + None + } + super::Statement::Expr(e) => e.lower(ctx), + } + } +} diff --git a/src/parser/v3/lower/def.rs b/src/parser/v3/lower/def.rs new file mode 100644 index 0000000..4b0aa0e --- /dev/null +++ b/src/parser/v3/lower/def.rs @@ -0,0 +1,59 @@ +use crate::ir::{FileSpan, NamespaceGuard, Origin, Type, VarDef}; + +use super::{Node, ParserMsg, ParserOutput, Type as PType, VarDef as PVarDef}; + +impl Node { + pub fn lower( + &self, + namespace: &mut NamespaceGuard, + output: &mut ParserOutput, + ) -> Option { + let s = self.as_ref()?; + let name = s.name.as_ref()?.val().clone(); + let ty = match &s.ty { + Some(ty) => ty.lower(namespace, output), + None => Type::Infer, + }; + Some(VarDef { + name, + ty, + origin: Origin::File(self.span), + }) + } +} + +impl Node { + pub fn lower(&self, namespace: &mut NamespaceGuard, output: &mut ParserOutput) -> Type { + self.as_ref() + .map(|t| t.lower(namespace, output, self.span)) + .unwrap_or(Type::Error) + } +} + +impl PType { + pub fn lower( + &self, + namespace: &mut NamespaceGuard, + output: &mut ParserOutput, + span: FileSpan, + ) -> Type { + match namespace.get(&self.name).map(|ids| ids.ty).flatten() { + Some(id) => { + if self.args.is_empty() { + Type::Concrete(id) + } else { + let args = self + .args + .iter() + .map(|n| n.lower(namespace, output)) + .collect(); + Type::Generic { base: id, args } + } + } + None => { + output.err(ParserMsg::from_span(span, "Type not found".to_string())); + Type::Error + } + } + } +} diff --git a/src/parser/v3/lower/expr.rs b/src/parser/v3/lower/expr.rs new file mode 100644 index 0000000..9b90269 --- /dev/null +++ b/src/parser/v3/lower/expr.rs @@ -0,0 +1,136 @@ +use super::{func::FnLowerCtx, Expr as PExpr, Node, UnaryOp}; +use crate::ir::{FnIdent, Instruction, Type, VarIdent, VarOrFnIdent}; + +impl PExpr { + pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + Some(match self { + PExpr::Lit(l) => match l.as_ref()? { + super::Literal::String(s) => todo!(), + super::Literal::Char(c) => todo!(), + super::Literal::Number(n) => todo!(), + super::Literal::Unit => { + todo!(); + } + }, + PExpr::Ident(i) => { + let name = i.as_ref()?.val(); + let Some(id) = ctx.get(name) else { + ctx.err(format!("Identifier '{}' not found.", name)); + return None; + }; + let Some(vf) = id.var_func else { + ctx.err(format!("Variable or function '{}' not found; Found type, but types cannot be used here.", name)); + return None; + }; + match vf { + VarOrFnIdent::Var(var) => ExprResult::Var(var), + VarOrFnIdent::Fn(f) => ExprResult::Fn(f), + } + } + PExpr::BinaryOp(op, e1, e2) => { + let res1 = e1.lower(ctx)?; + let res2 = e2.lower(ctx)?; + op.traitt(); + todo!(); + } + PExpr::UnaryOp(op, e) => { + let res = e.lower(ctx)?; + match op { + UnaryOp::Ref => ExprResult::Var(match res { + ExprResult::Var(v) => { + let temp = ctx.temp(ctx.map.get_var(v).ty.clone()); + ctx.push(Instruction::Ref { dest: temp, src: v }); + temp + } + ExprResult::Fn(f) => { + let temp = ctx.temp(Type::Ref(Box::new(ctx.map.get_fn(f).ty()))); + ctx.push(Instruction::Lf { dest: temp, src: f }); + temp + } + }), + UnaryOp::Deref => match res { + ExprResult::Var(v) => match &ctx.map.get_var(v).ty { + Type::Ref(inner) => { + todo!() + } + t => { + ctx.err(format!( + "Cannot dereference type {:?}", + ctx.map.type_name(t) + )); + return None; + } + }, + ExprResult::Fn(f) => { + ctx.err("Cannot dereference functions".to_string()); + return None; + } + }, + UnaryOp::Not => todo!(), + } + } + PExpr::Block(b) => b.lower(ctx)?, + PExpr::AsmBlock(b) => { + ctx.push(Instruction::AsmBlock { + instructions: b.as_ref()?.instructions.clone(), + }); + return None; + } + PExpr::Call(e, args) => { + let fe = e.lower(ctx)?; + let mut nargs = Vec::new(); + for arg in args.iter() { + let arg = arg.lower(ctx)?; + nargs.push(match arg { + ExprResult::Var(v) => v, + ExprResult::Fn(_) => todo!(), + }); + } + match fe { + ExprResult::Fn(f) => { + let temp = ctx.temp(ctx.map.get_fn(f).ret.clone()); + ctx.push(Instruction::Call { + dest: temp, + f, + args: nargs, + }); + ExprResult::Var(temp) + } + o => { + ctx.err(format!("Expected function, found {:?}", o)); + return None; + } + } + } + PExpr::Group(e) => e.lower(ctx)?, + }) + } +} + +impl Node { + pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + self.inner.as_ref()?.lower(&mut FnLowerCtx { + map: ctx.map, + instructions: ctx.instructions, + output: ctx.output, + span: self.span, + }) + } +} + +impl Node> { + pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + self.inner.as_ref()?.lower(&mut FnLowerCtx { + map: ctx.map, + instructions: ctx.instructions, + output: ctx.output, + span: self.span, + }) + } +} + +#[derive(Debug)] +pub enum ExprResult { + Var(VarIdent), + Fn(FnIdent), +} diff --git a/src/parser/v3/lower/func.rs b/src/parser/v3/lower/func.rs new file mode 100644 index 0000000..28b41ce --- /dev/null +++ b/src/parser/v3/lower/func.rs @@ -0,0 +1,101 @@ +use super::{Function as PFunction, Node, ParserMsg, ParserOutput}; +use crate::ir::{ + BuiltinType, FileSpan, FnDef, FnIdent, Function, Idents, Instruction, Instructions, + NamespaceGuard, Origin, Type, VarDef, VarIdent, +}; + +impl Node { + pub fn lower_header( + &self, + map: &mut NamespaceGuard, + output: &mut ParserOutput, + ) -> Option { + self.as_ref()?.lower_header(map, output) + } + pub fn lower_body(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) -> Option { + if let Some(f) = self.as_ref() { + Some(f.lower_body(map, output)) + } else { + None + } + } +} + +impl PFunction { + pub fn lower_header( + &self, + map: &mut NamespaceGuard, + output: &mut ParserOutput, + ) -> Option { + let header = self.header.as_ref()?; + let name = header.name.as_ref()?; + let args = header + .args + .iter() + .map(|a| { + a.lower(map, output).unwrap_or(VarDef { + name: "{error}".to_string(), + origin: Origin::File(a.span), + ty: Type::Error, + }) + }) + .collect(); + let ret = match &header.ret { + Some(ty) => ty.lower(map, output), + None => Type::Concrete(BuiltinType::Unit.id()), + }; + // ignoring self var for now + Some(map.def_fn(FnDef { + name: name.val().clone(), + origin: Origin::File(self.header.span), + args, + ret, + })) + } + pub fn lower_body(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) -> Function { + let mut instructions = Instructions::new(); + let mut ctx = FnLowerCtx { + instructions: &mut instructions, + map, + output, + span: self.body.span, + }; + if let Some(res) = self.body.lower(&mut ctx) { + match res { + super::ExprResult::Var(v) => instructions.push(Instruction::Ret { src: v }), + super::ExprResult::Fn(_) => todo!(), + } + } + Function::new(instructions) + } +} + +pub struct FnLowerCtx<'a, 'n> { + pub map: &'a mut NamespaceGuard<'n>, + pub instructions: &'a mut Instructions, + pub output: &'a mut ParserOutput, + pub span: FileSpan, +} + +impl<'a, 'n> FnLowerCtx<'a, 'n> { + pub fn get(&self, name: &str) -> Option { + self.map.get(name) + } + pub fn err(&mut self, msg: String) { + self.output.err(ParserMsg::from_span(self.span, msg)) + } + pub fn temp(&mut self, ty: Type) -> VarIdent { + self.map.temp_var(self.span, ty) + } + pub fn push(&mut self, i: Instruction) { + self.instructions.push(i); + } + pub fn sub<'b>(&'b mut self) -> FnLowerCtx<'b, 'n> { + FnLowerCtx { + map: self.map, + instructions: self.instructions, + output: self.output, + span: self.span, + } + } +} diff --git a/src/parser/v3/lower/mod.rs b/src/parser/v3/lower/mod.rs new file mode 100644 index 0000000..f6849fa --- /dev/null +++ b/src/parser/v3/lower/mod.rs @@ -0,0 +1,12 @@ +mod block; +mod def; +mod expr; +mod func; +mod module; + +use super::*; +use block::*; +use def::*; +use expr::*; +use func::*; +use module::*; diff --git a/src/parser/v3/lower/module.rs b/src/parser/v3/lower/module.rs new file mode 100644 index 0000000..d694dbb --- /dev/null +++ b/src/parser/v3/lower/module.rs @@ -0,0 +1,21 @@ +use crate::ir::NamespaceGuard; + +use super::{Module, ParserOutput}; + +impl Module { + pub fn lower(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) { + let mut fns = Vec::new(); + for f in &self.functions { + if let Some(id) = f.lower_header(map, output) { + fns.push(Some(id)); + } else { + fns.push(None) + } + } + for (f, id) in self.functions.iter().zip(fns) { + if let (Some(res), Some(id)) = (f.lower_body(map, output), id) { + map.write_fn(id, res); + } + } + } +} diff --git a/src/parser/v3/mod.rs b/src/parser/v3/mod.rs index ad94c87..d63d5b9 100644 --- a/src/parser/v3/mod.rs +++ b/src/parser/v3/mod.rs @@ -1,7 +1,6 @@ -use std::io::{stdout, BufRead, BufReader}; - mod cursor; mod error; +mod lower; mod node; mod nodes; mod parse; @@ -9,43 +8,8 @@ mod token; pub use cursor::*; pub use error::*; +pub use lower::*; pub use node::*; pub use nodes::*; pub use parse::*; pub use token::*; - -use crate::ir::Namespace; - -pub fn parse_file(file: &str) { - let mut errors = ParserErrors::new(); - let res = Module::parse_node(&mut TokenCursor::from(file), &mut errors); - println!("{:?}", res.node); - let out = &mut stdout(); - if let Some(module) = res.node.as_ref() { - let mut namespace = Namespace::new(); - module.lower(&mut namespace, &mut errors); - println!("{:?}", namespace); - } - for err in errors.errs { - err.write_for(out, file).unwrap(); - } -} - -pub fn run_stdin() { - for line in BufReader::new(std::io::stdin()).lines() { - let mut errors = ParserErrors::new(); - let str = &line.expect("failed to read line"); - let mut cursor = TokenCursor::from(&str[..]); - if let Some(expr) = Statement::parse_node(&mut cursor, &mut errors).node.as_ref() { - if cursor.next().is_none() { - println!("{:?}", expr); - } else { - println!("uhhhh ehehe"); - } - } - let out = &mut stdout(); - for err in errors.errs { - err.write_for(out, str).unwrap(); - } - } -} diff --git a/src/parser/v3/node.rs b/src/parser/v3/node.rs index 39b6c88..e591566 100644 --- a/src/parser/v3/node.rs +++ b/src/parser/v3/node.rs @@ -3,7 +3,7 @@ use std::{ ops::{Deref, DerefMut}, }; -use super::FileSpan; +use crate::ir::FileSpan; pub struct Node { pub inner: Option, diff --git a/src/parser/v3/nodes/asm_block.rs b/src/parser/v3/nodes/asm_block.rs new file mode 100644 index 0000000..6275180 --- /dev/null +++ b/src/parser/v3/nodes/asm_block.rs @@ -0,0 +1,23 @@ +use crate::compiler::riscv64::AsmInstruction; + +use super::{Parsable, ParseResult, Symbol}; + +#[derive(Debug)] +pub struct AsmBlock { + pub instructions: Vec, +} + +impl Parsable for AsmBlock { + fn parse( + cursor: &mut super::TokenCursor, + output: &mut super::ParserOutput, + ) -> ParseResult { + cursor.expect_sym(Symbol::OpenCurly)?; + let mut instructions = Vec::new(); + while !cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) { + instructions.push(AsmInstruction::parse(cursor, output)?); + } + cursor.expect_sym(Symbol::CloseCurly)?; + ParseResult::Ok(Self { instructions }) + } +} diff --git a/src/parser/v3/nodes/asm_fn.rs b/src/parser/v3/nodes/asm_fn.rs new file mode 100644 index 0000000..7e4c412 --- /dev/null +++ b/src/parser/v3/nodes/asm_fn.rs @@ -0,0 +1,53 @@ +use crate::compiler::riscv64::{AsmInstruction, Reg}; + +use super::{ + util::parse_list, AsmBlock, Ident, Keyword, Node, Parsable, ParseResult, SelfVar, Symbol, +}; + +#[derive(Debug)] +pub struct AsmFunctionHeader { + pub name: Node, + pub sel: Option>, + pub args: Vec>, +} + +#[derive(Debug)] +pub struct AsmFunction { + pub header: Node, + pub body: Node, +} + +impl Parsable for AsmFunctionHeader { + fn parse( + cursor: &mut super::TokenCursor, + output: &mut super::ParserOutput, + ) -> ParseResult { + cursor.expect_kw(Keyword::Asm)?; + cursor.expect_kw(Keyword::Fn)?; + let name = Node::parse(cursor, output)?; + cursor.expect_sym(Symbol::OpenParen)?; + let sel = Node::maybe_parse(cursor, output); + if sel.is_some() { + if let Err(err) = cursor.expect_sym(Symbol::Comma) { + output.err(err); + cursor.seek_syms(&[Symbol::Comma, Symbol::CloseParen]); + if cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Comma)) { + cursor.next(); + } + } + } + let args = parse_list(cursor, output, Symbol::CloseParen)?; + ParseResult::Ok(Self { name, sel, args }) + } +} + +impl Parsable for AsmFunction { + fn parse( + cursor: &mut super::TokenCursor, + output: &mut super::ParserOutput, + ) -> ParseResult { + let header = Node::parse(cursor, output)?; + let body = Node::parse(cursor, output)?; + ParseResult::Ok(Self { header, body }) + } +} diff --git a/src/parser/v3/nodes/body.rs b/src/parser/v3/nodes/block.rs similarity index 75% rename from src/parser/v3/nodes/body.rs rename to src/parser/v3/nodes/block.rs index d9ca192..f222691 100644 --- a/src/parser/v3/nodes/body.rs +++ b/src/parser/v3/nodes/block.rs @@ -1,29 +1,31 @@ use std::fmt::{Debug, Write}; use super::{ - token::Symbol, Node, NodeParsable, Parsable, ParseResult, ParserError, - ParserErrors, Statement, TokenCursor, + token::Symbol, Node, NodeParsable, Parsable, ParseResult, ParserMsg, ParserOutput, Statement, + TokenCursor, }; use crate::util::Padder; -pub struct Body { +pub struct Block { pub statements: Vec>, + pub result: Option>>, } -impl Parsable for Body { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult { +impl Parsable for Block { + fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult { let mut statements = Vec::new(); + let mut result = None; cursor.expect_sym(Symbol::OpenCurly)?; if cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) { cursor.next(); - return ParseResult::Ok(Self { statements }); + return ParseResult::Ok(Self { statements, result }); } let mut expect_semi = false; let mut recover = false; loop { let Some(next) = cursor.peek() else { recover = true; - errors.add(ParserError::unexpected_end()); + errors.err(ParserMsg::unexpected_end()); break; }; if next.is_symbol(Symbol::CloseCurly) { @@ -35,7 +37,7 @@ impl Parsable for Body { expect_semi = false; continue; } else if expect_semi { - errors.add(ParserError { + errors.err(ParserMsg { msg: "expected ';'".to_string(), spans: vec![cursor.next_pos().char_span()], }); @@ -51,11 +53,16 @@ impl Parsable for Body { } } } - ParseResult::from_recover(Self { statements }, recover) + if expect_semi { + if let Some(s) = statements.pop() { + result = Some(s.bx()); + } + } + ParseResult::from_recover(Self { statements, result }, recover) } } -impl Debug for Body { +impl Debug for Block { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if self.statements.first().is_some() { f.write_str("{\n ")?; diff --git a/src/parser/v3/nodes/def.rs b/src/parser/v3/nodes/def.rs new file mode 100644 index 0000000..af930b4 --- /dev/null +++ b/src/parser/v3/nodes/def.rs @@ -0,0 +1,82 @@ +use std::fmt::Debug; + +use super::{Ident, MaybeParsable, Node, Parsable, ParseResult, ParserMsg, Symbol, Token, Type}; + +pub struct VarDef { + pub name: Node, + pub ty: Option>, +} + +impl Parsable for VarDef { + fn parse( + cursor: &mut super::TokenCursor, + errors: &mut super::ParserOutput, + ) -> ParseResult { + let name = Node::parse(cursor, errors)?; + if cursor.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) { + cursor.next(); + Node::parse(cursor, errors).map(|ty| Self { name, ty: Some(ty) }) + } else { + ParseResult::Ok(Self { name, ty: None }) + } + } +} + +pub struct SelfVar { + pub ty: SelfType, +} + +#[derive(PartialEq)] +pub enum SelfType { + Ref, + Take, +} + +impl MaybeParsable for SelfVar { + fn maybe_parse( + cursor: &mut super::TokenCursor, + errors: &mut super::ParserOutput, + ) -> Result, super::ParserMsg> { + if let Some(mut next) = cursor.peek() { + let mut ty = SelfType::Take; + if next.is_symbol(Symbol::Ampersand) { + cursor.next(); + ty = SelfType::Ref; + next = cursor.expect_peek()?; + } + if let Token::Word(name) = &next.token { + if name == "self" { + cursor.next(); + return Ok(Some(Self { ty })); + } + } + if ty != SelfType::Take { + return Err(ParserMsg::unexpected_token(next, "self")); + } + } + Ok(None) + } +} + +impl Debug for VarDef { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.name.fmt(f)?; + if let Some(ty) = &self.ty { + write!(f, ": {:?}", ty)?; + } + Ok(()) + } +} + +impl Debug for SelfVar { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self.ty { + SelfType::Ref => "&self", + SelfType::Take => "self", + } + ) + } +} diff --git a/src/parser/v3/nodes/expr.rs b/src/parser/v3/nodes/expr.rs index a304cf3..c5e73bc 100644 --- a/src/parser/v3/nodes/expr.rs +++ b/src/parser/v3/nodes/expr.rs @@ -1,8 +1,10 @@ use std::fmt::{Debug, Write}; use super::{ - BinaryOperator, Body, Ident, Literal, Node, NodeParsable, Parsable, ParseResult, ParserError, - ParserErrors, Symbol, TokenCursor, UnaryOperator, + op::{BinaryOp, UnaryOp}, + util::parse_list, + AsmBlock, Block, Ident, Keyword, Literal, Node, NodeParsable, Parsable, ParseResult, ParserMsg, + ParserOutput, Symbol, TokenCursor, }; type BoxNode = Node>; @@ -10,15 +12,16 @@ type BoxNode = Node>; pub enum Expr { Lit(Node), Ident(Node), - BinaryOp(BinaryOperator, BoxNode, BoxNode), - UnaryOp(UnaryOperator, BoxNode), - Block(Node), + BinaryOp(BinaryOp, BoxNode, BoxNode), + UnaryOp(UnaryOp, BoxNode), + Block(Node), Call(BoxNode, Vec>), Group(BoxNode), + AsmBlock(Node), } impl Parsable for Expr { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult { + fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult { let start = cursor.next_pos(); let next = cursor.expect_peek()?; let mut e1 = if next.is_symbol(Symbol::OpenParen) { @@ -30,17 +33,20 @@ impl Parsable for Expr { cursor.next_pos().char_span(), ))); } - let res = Node::parse(cursor, errors); + let res = Node::parse(cursor, output); if res.recover { cursor.seek_sym(Symbol::CloseParen); } cursor.expect_sym(Symbol::CloseParen)?; Self::Group(res.node.bx()) } else if next.is_symbol(Symbol::OpenCurly) { - Self::Block(Body::parse_node(cursor, errors)?) - } else if let Some(op) = UnaryOperator::from_token(next) { + Self::Block(Block::parse_node(cursor, output)?) + } else if next.is_keyword(Keyword::Asm) { cursor.next(); - return Node::parse(cursor, errors).map(|n| { + Self::AsmBlock(Node::parse(cursor, output)?) + } else if let Some(op) = UnaryOp::from_token(next) { + cursor.next(); + return Node::parse(cursor, output).map(|n| { let n = n.bx(); if let Some(box Self::BinaryOp(op2, n1, n2)) = n.inner { let span = start.to(n1.span.end); @@ -49,15 +55,15 @@ impl Parsable for Expr { Self::UnaryOp(op, n) } }); - } else if let Some(val) = Node::maybe_parse(cursor, errors) { + } else if let Some(val) = Node::maybe_parse(cursor, output) { Self::Lit(val) } else { - let res = Node::parse(cursor, &mut ParserErrors::new()); + let res = Node::parse(cursor, &mut ParserOutput::new()); if res.node.is_some() { Self::Ident(res.node) } else { let next = cursor.expect_peek()?; - return ParseResult::Err(ParserError::unexpected_token(next, "an expression")); + return ParseResult::Err(ParserMsg::unexpected_token(next, "an expression")); } }; let Some(mut next) = cursor.peek() else { @@ -65,24 +71,7 @@ impl Parsable for Expr { }; while next.is_symbol(Symbol::OpenParen) { cursor.next(); - let mut args = Vec::new(); - loop { - let next = cursor.expect_peek()?; - if next.is_symbol(Symbol::CloseParen) { - break; - } - let res = Node::::parse(cursor, errors); - args.push(res.node); - if res.recover { - cursor.seek_syms(&[Symbol::CloseParen, Symbol::Comma]); - } - let next = cursor.expect_peek()?; - if !next.is_symbol(Symbol::Comma) { - break; - } - cursor.next(); - } - cursor.expect_sym(Symbol::CloseParen)?; + let args = parse_list(cursor, output, Symbol::CloseParen)?; let end = cursor.prev_end(); e1 = Self::Call(Node::new(Box::new(e1), start.to(end)), args); let Some(next2) = cursor.peek() else { @@ -92,10 +81,10 @@ impl Parsable for Expr { } let end = cursor.prev_end(); let mut recover = false; - let res = if let Some(mut op) = BinaryOperator::from_token(&next.token) { + let res = if let Some(mut op) = BinaryOp::from_token(&next.token) { cursor.next(); let mut n1 = Node::new(e1, start.to(end)).bx(); - let res = Node::parse(cursor, errors); + let res = Node::parse(cursor, output); let mut n2 = res.node.bx(); recover = res.recover; if let Some(box Self::BinaryOp(op2, _, _)) = n2.as_ref() { @@ -150,6 +139,7 @@ impl Debug for Expr { write!(f, "{:?})", *e)?; } Expr::Group(inner) => inner.fmt(f)?, + Expr::AsmBlock(inner) => inner.fmt(f)?, } Ok(()) } diff --git a/src/parser/v3/nodes/func.rs b/src/parser/v3/nodes/func.rs index 23b5248..08ee048 100644 --- a/src/parser/v3/nodes/func.rs +++ b/src/parser/v3/nodes/func.rs @@ -1,28 +1,90 @@ -use super::{Body, Ident, Keyword, Node, Parsable, ParseResult, ParserErrors, Symbol, TokenCursor}; +use super::{ + util::parse_list, Block, Ident, Keyword, Node, Parsable, ParseResult, ParserOutput, SelfVar, + Symbol, TokenCursor, Type, VarDef, +}; use std::fmt::Debug; -pub struct Function { +pub struct FunctionHeader { pub name: Node, - pub body: Node, + pub sel: Option>, + pub args: Vec>, + pub ret: Option>, } -impl Parsable for Function { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult { +pub struct Function { + pub header: Node, + pub body: Node, +} + +impl Parsable for FunctionHeader { + fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult { cursor.expect_kw(Keyword::Fn)?; - let name = Node::parse(cursor, errors)?; + let name = Node::parse(cursor, output)?; cursor.expect_sym(Symbol::OpenParen)?; - cursor.expect_sym(Symbol::CloseParen)?; - Node::parse(cursor, errors).map(|body| Self { name, body }) + let sel = Node::maybe_parse(cursor, output); + if sel.is_some() { + if let Err(err) = cursor.expect_sym(Symbol::Comma) { + output.err(err); + cursor.seek_syms(&[Symbol::Comma, Symbol::CloseParen]); + if cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Comma)) { + cursor.next(); + } + } + } + let args = parse_list(cursor, output, Symbol::CloseParen)?; + let ret = if cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Arrow)) { + cursor.next(); + Some(Node::parse(cursor, output)?) + } else { + None + }; + ParseResult::Ok(Self { + name, + args, + sel, + ret, + }) } } -impl Debug for Function { +impl Parsable for Function { + fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult { + let header = Node::parse(cursor, output)?; + let body = Node::parse(cursor, output)?; + ParseResult::Ok(Self { header, body }) + } +} + +impl Debug for FunctionHeader { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str("fn ")?; self.name.fmt(f)?; - f.write_str("() ")?; + f.write_str("(")?; + if let Some(s) = &self.sel { + s.fmt(f)?; + if self.args.first().is_some() { + f.write_str(", ")?; + } + } + if let Some(a) = self.args.first() { + a.fmt(f)?; + } + for arg in self.args.iter().skip(1) { + f.write_str(", ")?; + arg.fmt(f)?; + } + f.write_str(")")?; + if let Some(ret) = &self.ret { + write!(f, " -> {:?}", ret)?; + } + Ok(()) + } +} +impl Debug for Function { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.header.fmt(f)?; + f.write_str(" ")?; self.body.fmt(f)?; Ok(()) } } - diff --git a/src/parser/v3/nodes/ident.rs b/src/parser/v3/nodes/ident.rs index 0c6f941..8e7cdf6 100644 --- a/src/parser/v3/nodes/ident.rs +++ b/src/parser/v3/nodes/ident.rs @@ -1,5 +1,5 @@ use std::fmt::Debug; -use super::{Parsable, ParseResult, ParserError, Token}; +use super::{Parsable, ParseResult, ParserMsg, Token}; pub struct Ident(String); @@ -10,10 +10,10 @@ impl Ident { } impl Parsable for Ident { - fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserErrors) -> ParseResult { + fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserOutput) -> ParseResult { let next = cursor.expect_peek()?; - let Token::Ident(name) = &next.token else { - return ParseResult::Err(ParserError::unexpected_token(next, "an identifier")); + let Token::Word(name) = &next.token else { + return ParseResult::Err(ParserMsg::unexpected_token(next, "an identifier")); }; let name = name.to_string(); cursor.next(); diff --git a/src/parser/v3/nodes/lit.rs b/src/parser/v3/nodes/lit.rs index b80679c..7efe138 100644 --- a/src/parser/v3/nodes/lit.rs +++ b/src/parser/v3/nodes/lit.rs @@ -1,6 +1,4 @@ -use super::{ - CharCursor, MaybeParsable, ParserError, ParserErrors, Symbol, Token, TokenCursor, -}; +use super::{CharCursor, MaybeParsable, ParserMsg, ParserOutput, Symbol, Token, TokenCursor}; use std::fmt::Debug; #[derive(Clone, PartialEq, Eq)] @@ -21,49 +19,72 @@ pub struct Number { impl MaybeParsable for Literal { fn maybe_parse( cursor: &mut TokenCursor, - _: &mut ParserErrors, - ) -> Result, ParserError> { + _: &mut ParserOutput, + ) -> Result, ParserMsg> { let inst = cursor.expect_peek()?; - let mut res = match &inst.token { + Ok(Some(match &inst.token { Token::Symbol(Symbol::SingleQuote) => { let chars = cursor.chars(); let c = chars.expect_next()?; chars.expect('\'')?; + cursor.next(); Self::Char(c) } - Token::Symbol(Symbol::DoubleQuote) => Self::String(string_from(cursor.chars())?), - Token::Ident(text) => { + Token::Symbol(Symbol::DoubleQuote) => { + let res = Self::String(string_from(cursor.chars())?); + cursor.next(); + res + } + Token::Word(text) => { let first = text.chars().next().unwrap(); - if first.is_ascii_digit() { - Self::Number(Number { - whole: text.to_string(), - decimal: None, - ty: None, - }) - } else { + if !first.is_ascii_digit() { return Ok(None); } - } - _ => return Ok(None), - }; - cursor.next(); - if let (Some(next), Self::Number(num)) = (cursor.peek(), &mut res) { - if next.token.is_symbol(Symbol::Dot) { + let (whole, ty) = parse_whole_num(text); + let mut num = Number { + whole, + decimal: None, + ty, + }; cursor.next(); - if let Some(next) = cursor.peek() { - if let Token::Ident(i) = &next.token { - if i.chars().next().unwrap().is_ascii_digit() { - num.decimal = Some(i.to_string()); - cursor.next(); + if num.ty.is_none() && cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Dot)) { + cursor.next(); + if let Some(next) = cursor.peek() { + if let Token::Word(i) = &next.token { + if i.chars().next().unwrap().is_ascii_digit() { + let (decimal, ty) = parse_whole_num(i); + num.decimal = Some(decimal); + num.ty = ty; + cursor.next(); + } } } } + Self::Number(num) } - } - Ok(Some(res)) + _ => return Ok(None), + })) } } -pub fn string_from(cursor: &mut CharCursor) -> Result { + +pub fn parse_whole_num(text: &str) -> (String, Option) { + let mut whole = String::new(); + let mut ty = String::new(); + for c in text.chars() { + if ty.is_empty() { + if c.is_ascii_digit() { + whole.push(c); + } else if c != '_' { + ty.push(c); + } + } else { + ty.push(c); + } + } + (whole, if ty.is_empty() { None } else { Some(ty) }) +} + +pub fn string_from(cursor: &mut CharCursor) -> Result { let mut str = String::new(); loop { let c = cursor.expect_next()?; @@ -107,7 +128,7 @@ impl Debug for Number { write!(f, ".{}", d)?; } if let Some(ty) = &self.ty { - write!(f, "T{}", ty)?; + write!(f, "_{}", ty)?; } Ok(()) } diff --git a/src/parser/v3/nodes/mod.rs b/src/parser/v3/nodes/mod.rs index 365b9a4..08e1c60 100644 --- a/src/parser/v3/nodes/mod.rs +++ b/src/parser/v3/nodes/mod.rs @@ -1,4 +1,4 @@ -mod body; +mod block; mod expr; mod func; mod module; @@ -6,14 +6,28 @@ mod op; mod statement; mod lit; mod ident; +mod ty; +mod def; +mod struc; +mod util; +mod trai; +mod asm_fn; +mod asm_block; -pub use body::*; +pub use block::*; pub use expr::*; pub use func::*; pub use module::*; -pub use op::*; pub use statement::*; pub use lit::*; pub use ident::*; +pub use ty::*; +pub use def::*; +pub use struc::*; +pub use trai::*; +pub use op::*; +pub use asm_fn::*; +pub use asm_block::*; + use super::*; diff --git a/src/parser/v3/nodes/module.rs b/src/parser/v3/nodes/module.rs index ab3fd64..58aa602 100644 --- a/src/parser/v3/nodes/module.rs +++ b/src/parser/v3/nodes/module.rs @@ -1,35 +1,113 @@ use super::{ - Function, Keyword, Node, Parsable, ParseResult, ParserError, ParserErrors, TokenCursor, + AsmFunction, Function, Impl, Keyword, Node, Parsable, ParseResult, ParserMsg, ParserOutput, + Struct, Symbol, Token, TokenCursor, Trait, }; use std::fmt::Debug; pub struct Module { + pub traits: Vec>, + pub structs: Vec>, pub functions: Vec>, + pub asm_fns: Vec>, + pub impls: Vec>, } impl Parsable for Module { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult { + fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult { let mut functions = Vec::new(); + let mut structs = Vec::new(); + let mut traits = Vec::new(); + let mut impls = Vec::new(); + let mut asm_fns = Vec::new(); loop { let Some(next) = cursor.peek() else { - return ParseResult::Ok(Self { functions }); + break; }; - if next.is_keyword(Keyword::Fn) { - let res = Node::parse(cursor, errors); - functions.push(res.node); - if res.recover { - return ParseResult::Recover(Self { functions }); + if let Token::Keyword(kw) = next.token { + match kw { + Keyword::Fn => { + let res = Node::parse(cursor, errors); + functions.push(res.node); + if res.recover { + break; + } + } + Keyword::Struct => { + let res = Node::parse(cursor, errors); + structs.push(res.node); + if res.recover { + break; + } + } + Keyword::Trait => { + let res = Node::parse(cursor, errors); + traits.push(res.node); + if res.recover { + break; + } + } + Keyword::Impl => { + let res = Node::parse(cursor, errors); + impls.push(res.node); + if res.recover { + break; + } + } + Keyword::Asm => { + let res = Node::parse(cursor, errors); + asm_fns.push(res.node); + if res.recover { + break; + } + } + _ => { + errors.err(ParserMsg::unexpected_token(next, "a definition")); + cursor.next(); + } } + } else if next.is_symbol(Symbol::Semicolon) { + errors.hint(ParserMsg::from_instances( + &[next], + "unneeded semicolon".to_string(), + )); + cursor.next(); } else { - errors.add(ParserError::unexpected_token(next, "fn")); + errors.err(ParserMsg::unexpected_token(next, "a definition")); cursor.next(); } } + ParseResult::Ok(Self { + functions, + structs, + traits, + impls, + asm_fns, + }) } } impl Debug for Module { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.functions.fmt(f) + 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)?; + } + for func in &self.asm_fns { + func.fmt(f)?; + writeln!(f)?; + } + Ok(()) } } diff --git a/src/parser/v3/nodes/op.rs b/src/parser/v3/nodes/op.rs index e066530..70044d6 100644 --- a/src/parser/v3/nodes/op.rs +++ b/src/parser/v3/nodes/op.rs @@ -1,7 +1,7 @@ use super::{Symbol, Token}; #[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum BinaryOperator { +pub enum BinaryOp { Add, Sub, Mul, @@ -12,7 +12,7 @@ pub enum BinaryOperator { Assign, } -impl BinaryOperator { +impl BinaryOp { pub fn presedence(&self) -> u32 { match self { Self::Assign => 0, @@ -37,6 +37,39 @@ impl BinaryOperator { Self::Assign => "=", } } + pub fn pad(&self) -> bool { + match self { + Self::Add => true, + Self::Sub => true, + Self::Mul => true, + Self::Div => true, + Self::LessThan => true, + Self::GreaterThan => true, + Self::Access => 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 { + Not, + Ref, + Deref, +} + +impl BinaryOp { pub fn from_token(token: &Token) -> Option { let Token::Symbol(symbol) = token else { return None; @@ -55,30 +88,14 @@ impl BinaryOperator { } }) } - pub fn pad(&self) -> bool { - match self { - Self::Add => true, - Self::Sub => true, - Self::Mul => true, - Self::Div => true, - Self::LessThan => true, - Self::GreaterThan => true, - Self::Access => false, - Self::Assign => true, - } - } } -pub enum UnaryOperator { - Not, - Ref, -} - -impl UnaryOperator { +impl UnaryOp { pub fn str(&self) -> &str { match self { Self::Not => "!", Self::Ref => "&", + Self::Deref => "*", } } pub fn from_token(token: &Token) -> Option { @@ -88,6 +105,7 @@ impl UnaryOperator { Some(match symbol { Symbol::Ampersand => Self::Ref, Symbol::Bang => Self::Not, + Symbol::Asterisk => Self::Deref, _ => { return None; } diff --git a/src/parser/v3/nodes/statement.rs b/src/parser/v3/nodes/statement.rs index fa0827b..06dc9ce 100644 --- a/src/parser/v3/nodes/statement.rs +++ b/src/parser/v3/nodes/statement.rs @@ -1,23 +1,23 @@ use super::{ - Expr, Ident, Keyword, Node, Parsable, ParseResult, ParserErrors, Symbol, Token, TokenCursor, + Expr, Keyword, Node, Parsable, ParseResult, ParserOutput, Symbol, Token, TokenCursor, VarDef, }; use std::fmt::{Debug, Write}; pub enum Statement { - Let(Node, Node), + Let(Node, Node), Return(Node), Expr(Node), } impl Parsable for Statement { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult { + fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult { let next = cursor.expect_peek()?; match next.token { Token::Keyword(Keyword::Let) => { cursor.next(); - let name = Node::parse(cursor, errors)?; + let def = Node::parse(cursor, errors)?; cursor.expect_sym(Symbol::Equals)?; - Node::parse(cursor, errors).map(|expr| Self::Let(name, expr)) + Node::parse(cursor, errors).map(|expr| Self::Let(def, expr)) } Token::Keyword(Keyword::Return) => { cursor.next(); diff --git a/src/parser/v3/nodes/struc.rs b/src/parser/v3/nodes/struc.rs new file mode 100644 index 0000000..779cb2f --- /dev/null +++ b/src/parser/v3/nodes/struc.rs @@ -0,0 +1,45 @@ +use std::fmt::Debug; + +use super::{ + util::parse_list, Ident, Keyword, Node, Parsable, ParseResult, ParserMsg, ParserOutput, + Symbol, TokenCursor, Type, VarDef, +}; + +#[derive(Debug)] +pub struct Struct { + pub name: Node, + pub fields: StructFields, +} + +#[derive(Debug)] +pub enum StructFields { + Named(Vec>), + Tuple(Vec>), + None, +} + +impl Parsable for Struct { + fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult { + cursor.expect_kw(Keyword::Struct)?; + let name = Node::parse(cursor, errors)?; + let next = cursor.expect_peek()?; + let fields = if next.is_symbol(Symbol::Semicolon) { + cursor.next(); + StructFields::None + } else if next.is_symbol(Symbol::OpenCurly) { + cursor.next(); + StructFields::Named(parse_list(cursor, errors, Symbol::CloseCurly)?) + } else if next.is_symbol(Symbol::OpenParen) { + cursor.next(); + StructFields::Tuple(parse_list(cursor, errors, Symbol::CloseParen)?) + } else { + errors.err(ParserMsg::unexpected_token(next, "`;`, `(`, or `{`")); + return ParseResult::Recover(Struct { + name, + fields: StructFields::None, + }); + }; + ParseResult::Ok(Struct { name, fields }) + } +} + diff --git a/src/parser/v3/nodes/trai.rs b/src/parser/v3/nodes/trai.rs new file mode 100644 index 0000000..43ff099 --- /dev/null +++ b/src/parser/v3/nodes/trai.rs @@ -0,0 +1,36 @@ +use super::{util::{parse_list, parse_list_nosep}, Function, FunctionHeader, Ident, Keyword, Node, Parsable, Symbol, Type}; + +#[derive(Debug)] +pub struct Trait { + pub name: Node, + pub fns: Vec> +} + +#[derive(Debug)] +pub struct Impl { + pub trait_: Node, + pub for_: Node, + pub fns: Vec> +} + +impl Parsable for Trait { + fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserOutput) -> super::ParseResult { + cursor.expect_kw(Keyword::Trait)?; + let name = Node::parse(cursor, errors)?; + cursor.expect_sym(Symbol::OpenCurly)?; + let fns = parse_list(cursor, errors, Symbol::CloseCurly)?; + super::ParseResult::Ok(Self {name, fns}) + } +} + +impl Parsable for Impl { + fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserOutput) -> super::ParseResult { + cursor.expect_kw(Keyword::Impl)?; + let trait_ = Node::parse(cursor, errors)?; + cursor.expect_kw(Keyword::For)?; + let for_ = Node::parse(cursor, errors)?; + cursor.expect_sym(Symbol::OpenCurly)?; + let fns = parse_list_nosep(cursor, errors, Symbol::CloseCurly)?; + super::ParseResult::Ok(Self {trait_, for_, fns}) + } +} diff --git a/src/parser/v3/nodes/ty.rs b/src/parser/v3/nodes/ty.rs new file mode 100644 index 0000000..c5387a6 --- /dev/null +++ b/src/parser/v3/nodes/ty.rs @@ -0,0 +1,61 @@ +use std::fmt::Debug; + +use super::{util::parse_list, Node, Parsable, ParseResult, ParserMsg, Symbol, Token}; + +pub struct Type { + pub name: String, + pub args: Vec>, +} + +impl Type { + pub fn unit() -> Self { + Self { + name: "()".to_string(), + args: Vec::new(), + } + } +} + +impl Parsable for Type { + fn parse( + cursor: &mut super::TokenCursor, + errors: &mut super::ParserOutput, + ) -> ParseResult { + let next = cursor.expect_peek()?; + let res = if next.is_symbol(Symbol::Ampersand) { + cursor.next(); + let arg = Node::parse(cursor, errors)?; + Self { + name: "&".to_string(), + args: vec![arg], + } + } else { + let Token::Word(name) = &next.token else { + return ParseResult::Err(ParserMsg::unexpected_token(next, "a type identifier")); + }; + let n = name.to_string(); + cursor.next(); + let mut args = Vec::new(); + if let Some(next) = cursor.peek() { + if next.is_symbol(Symbol::OpenAngle) { + cursor.next(); + args = parse_list(cursor, errors, Symbol::CloseAngle)?; + } + } + Self { name: n, args } + }; + ParseResult::Ok(res) + } +} + +impl Debug for Type { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.name)?; + if self.name == "&" { + write!(f, "{:?}", self.args[0])?; + } else if !self.args.is_empty() { + write!(f, "<{:?}>", self.args)?; + } + Ok(()) + } +} diff --git a/src/parser/v3/nodes/util.rs b/src/parser/v3/nodes/util.rs new file mode 100644 index 0000000..125d0d5 --- /dev/null +++ b/src/parser/v3/nodes/util.rs @@ -0,0 +1,57 @@ +use super::{Node, Parsable, ParserMsg, ParserOutput, Symbol, TokenCursor}; + +pub fn parse_list_sep( + cursor: &mut TokenCursor, + errors: &mut ParserOutput, + sep: Symbol, + end: Symbol, +) -> Result>, ParserMsg> { + let mut vals = Vec::new(); + loop { + let next = cursor.expect_peek()?; + if next.is_symbol(end) { + break; + } + let res = Node::parse(cursor, errors); + vals.push(res.node); + if res.recover { + cursor.seek_syms(&[end, sep]); + } + let next = cursor.expect_peek()?; + if !next.is_symbol(sep) { + break; + } + cursor.next(); + } + cursor.expect_sym(end)?; + Ok(vals) +} + +pub fn parse_list( + cursor: &mut TokenCursor, + errors: &mut ParserOutput, + end: Symbol, +) -> Result>, ParserMsg> { + parse_list_sep(cursor, errors, Symbol::Comma, end) +} + +pub fn parse_list_nosep( + cursor: &mut TokenCursor, + errors: &mut ParserOutput, + end: Symbol, +) -> Result>, ParserMsg> { + let mut vals = Vec::new(); + loop { + let next = cursor.expect_peek()?; + if next.is_symbol(end) { + break; + } + let res = Node::parse(cursor, errors); + vals.push(res.node); + if res.recover { + cursor.seek_sym(end); + } + } + cursor.expect_sym(end)?; + Ok(vals) +} diff --git a/src/parser/v3/parse.rs b/src/parser/v3/parse.rs index e5a58ff..c7c5522 100644 --- a/src/parser/v3/parse.rs +++ b/src/parser/v3/parse.rs @@ -3,12 +3,14 @@ use std::{ ops::{ControlFlow, FromResidual, Try}, }; -use super::{Node, ParserError, ParserErrors, TokenCursor}; +use crate::ir::FilePos; + +use super::{Node, ParserMsg, ParserOutput, TokenCursor}; pub enum ParseResult { Ok(T), Recover(T), - Err(ParserError), + Err(ParserMsg), SubErr, } @@ -23,18 +25,15 @@ impl ParseResult { } impl Try for ParseResult { - type Output = Result; - type Residual = Option; + type Output = T; + type Residual = Option; fn from_output(output: Self::Output) -> Self { - match output { - Ok(v) => Self::Ok(v), - Err(v) => Self::Recover(v), - } + Self::Ok(output) } fn branch(self) -> ControlFlow { match self { - ParseResult::Ok(v) => ControlFlow::Continue(Ok(v)), - ParseResult::Recover(v) => ControlFlow::Continue(Err(v)), + ParseResult::Ok(v) => ControlFlow::Continue(v), + ParseResult::Recover(v) => ControlFlow::Break(None), ParseResult::Err(e) => ControlFlow::Break(Some(e)), ParseResult::SubErr => ControlFlow::Break(None), } @@ -50,8 +49,8 @@ impl FromResidual for ParseResult { } } -impl FromResidual> for ParseResult { - fn from_residual(residual: Result) -> Self { +impl FromResidual> for ParseResult { + fn from_residual(residual: Result) -> Self { match residual { Err(e) => Self::Err(e), } @@ -112,24 +111,24 @@ impl FromResidual for NodeParseResult { } pub trait Parsable: Sized { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult; + fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult; } pub trait MaybeParsable: Sized { fn maybe_parse( cursor: &mut TokenCursor, - errors: &mut ParserErrors, - ) -> Result, ParserError>; + errors: &mut ParserOutput, + ) -> Result, ParserMsg>; } impl Node { - pub fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> NodeParseResult { - let start = cursor.next_pos(); - let (inner, recover) = match T::parse(cursor, errors) { + pub fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> NodeParseResult { + let start = cursor.peek().map(|t| t.span.start).unwrap_or(FilePos::start()); + let (inner, recover) = match T::parse(cursor, output) { ParseResult::Ok(v) => (Some(v), false), ParseResult::Recover(v) => (Some(v), true), ParseResult::Err(e) => { - errors.add(e); + output.err(e); (None, true) } ParseResult::SubErr => (None, true), @@ -146,12 +145,12 @@ impl Node { } impl Node { - pub fn maybe_parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Option { + pub fn maybe_parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> Option { let start = cursor.next_pos(); let inner = match T::maybe_parse(cursor, errors) { Ok(v) => Some(v?), Err(e) => { - errors.add(e); + errors.err(e); None } }; @@ -164,12 +163,12 @@ impl Node { } pub trait NodeParsable { - fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> NodeParseResult + fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> NodeParseResult where Self: Sized; } impl NodeParsable for T { - fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> NodeParseResult + fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> NodeParseResult where Self: Sized, { diff --git a/src/parser/v3/token/cursor.rs b/src/parser/v3/token/cursor.rs index 02796f6..365c759 100644 --- a/src/parser/v3/token/cursor.rs +++ b/src/parser/v3/token/cursor.rs @@ -1,7 +1,7 @@ use std::{iter::Peekable, str::Chars}; -use super::super::ParserError; -use super::FilePos; +use crate::ir::FilePos; +use super::super::ParserMsg; pub struct CharCursor<'a> { chars: Peekable>, @@ -15,12 +15,12 @@ impl CharCursor<'_> { self.advance(); Some(res) } - pub fn expect(&mut self, c: char) -> Result<(), ParserError> { + pub fn expect(&mut self, c: char) -> Result<(), ParserMsg> { let next = self.expect_next()?; if next == c { Ok(()) } else { - Err(ParserError::at( + Err(ParserMsg::at( self.prev_pos, format!("unexpected char '{next}'; expected '{c}'"), )) @@ -46,8 +46,8 @@ impl CharCursor<'_> { self.next_pos.col += 1; } } - pub fn expect_next(&mut self) -> Result { - self.next().ok_or(ParserError::unexpected_end()) + pub fn expect_next(&mut self) -> Result { + self.next().ok_or(ParserMsg::unexpected_end()) } pub fn next_pos(&self) -> FilePos { self.next_pos diff --git a/src/parser/v3/token/keyword.rs b/src/parser/v3/token/keyword.rs index f22782c..85d656a 100644 --- a/src/parser/v3/token/keyword.rs +++ b/src/parser/v3/token/keyword.rs @@ -4,15 +4,25 @@ pub enum Keyword { Let, If, Return, + Struct, + Trait, + Impl, + For, + Asm, } impl Keyword { pub fn from_string(str: &str) -> Option { Some(match str { "fn" => Self::Fn, + "struct" => Self::Struct, "let" => Self::Let, "if" => Self::If, + "for" => Self::For, "return" => Self::Return, + "trait" => Self::Trait, + "impl" => Self::Impl, + "asm" => Self::Asm, _ => return None, }) } diff --git a/src/parser/v3/token/mod.rs b/src/parser/v3/token/mod.rs index 59e25f6..2679231 100644 --- a/src/parser/v3/token/mod.rs +++ b/src/parser/v3/token/mod.rs @@ -1,19 +1,19 @@ mod cursor; -mod file; mod keyword; mod symbol; use std::ops::Deref; pub use cursor::*; -pub use file::*; pub use keyword::*; pub use symbol::*; +use crate::ir::FileSpan; + #[derive(Debug, PartialEq, Eq, Clone)] pub enum Token { Symbol(Symbol), - Ident(String), + Word(String), Keyword(Keyword), } @@ -51,7 +51,7 @@ impl TokenInstance { let token = if let Some(keyword) = Keyword::from_string(&word) { Token::Keyword(keyword) } else { - Token::Ident(word) + Token::Word(word) }; Some(Self { token, diff --git a/src/parser/v3/token/symbol.rs b/src/parser/v3/token/symbol.rs index 2ed689a..ccaae43 100644 --- a/src/parser/v3/token/symbol.rs +++ b/src/parser/v3/token/symbol.rs @@ -17,6 +17,7 @@ pub enum Symbol { Slash, DoubleSlash, Dot, + DoubleDot, OpenParen, CloseParen, OpenCurly, @@ -100,6 +101,10 @@ impl Symbol { '&' => Self::DoublePipe, _ => return, }, + Self::Dot => match next { + '.' => Self::DoubleDot, + _ => return, + } _ => return, }; cursor.advance(); @@ -119,6 +124,7 @@ impl Symbol { Self::Slash => "/", Self::DoubleSlash => "//", Self::Dot => ".", + Self::DoubleDot => "..", Self::OpenParen => "(", Self::CloseParen => ")", Self::OpenCurly => "{",