diff --git a/data/err.lang b/data/err.lang index a68d066..62409c4 100644 --- a/data/err.lang +++ b/data/err.lang @@ -19,6 +19,7 @@ fn main() { let a = 3; b }; + exit(3, let, "hello"); } fn test() { diff --git a/data/test.lang b/data/test.lang index 1cabfb2..83bb172 100644 --- a/data/test.lang +++ b/data/test.lang @@ -1,4 +1,4 @@ fn main() { - let x = &"Hello World!"; - print(x); + let x = 3; + exit(x); } diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs index ad1371d..943f74b 100644 --- a/src/compiler/mod.rs +++ b/src/compiler/mod.rs @@ -10,7 +10,7 @@ mod program; mod riscv64; mod target; -use program::*; +pub use program::*; pub fn main() { use std::io::prelude::*; diff --git a/src/compiler/program.rs b/src/compiler/program.rs index ea80c4b..1a8c8eb 100644 --- a/src/compiler/program.rs +++ b/src/compiler/program.rs @@ -59,13 +59,13 @@ impl Deref for WritableSymbol { } } -pub struct SymMap { +pub struct SymMap { i: usize, ro_data: Vec<(Vec, Symbol)>, functions: Vec<(Vec, Symbol)>, } -impl SymMap { +impl SymMap { pub fn new() -> Self { Self { i: 0, diff --git a/src/compiler/riscv64/asm.rs b/src/compiler/riscv64/asm.rs index 58c41ce..50b0bac 100644 --- a/src/compiler/riscv64/asm.rs +++ b/src/compiler/riscv64/asm.rs @@ -3,7 +3,13 @@ use crate::compiler::program::{Addr, Instr, SymTable, Symbol}; use super::*; 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), Call(Symbol), @@ -16,7 +22,13 @@ pub enum AsmInstruction { impl Instr for AsmInstruction { 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) => { if let Some(addr) = sym_map.get(*sym) { let offset = addr.val() as i32 - pos.val() as i32; diff --git a/src/compiler/riscv64/base.rs b/src/compiler/riscv64/base.rs index 9fd259a..6e81ff5 100644 --- a/src/compiler/riscv64/base.rs +++ b/src/compiler/riscv64/base.rs @@ -18,14 +18,14 @@ impl Instruction { pub type Funct3 = Bits32<2, 0>; pub const fn r_type( - funct7: u32, + funct7: Bits32<6, 0>, rs2: Reg, rs1: Reg, funct3: Bits32<2, 0>, rd: Reg, opcode: u32, ) -> I { - I((funct7 << 25) + I((funct7.val() << 25) + (rs2.val() << 20) + (rs1.val() << 15) + (funct3.val() << 12) diff --git a/src/compiler/riscv64/single.rs b/src/compiler/riscv64/single.rs index e5805dd..7bcdb57 100644 --- a/src/compiler/riscv64/single.rs +++ b/src/compiler/riscv64/single.rs @@ -31,9 +31,21 @@ pub const fn sw(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { pub const fn sd(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { s_type(src, base, width::D, offset.to_u(), STORE) } +pub const fn add(dest: Reg, src1: Reg, src2: Reg) -> I { + r_type(Bits32::new(0), src2, src1, ADD, dest, OP) +} pub const fn addi(dest: Reg, src: Reg, imm: BitsI32<11, 0>) -> I { i_type(imm.to_u(), src, ADD, dest, IMM_OP) } +pub const fn andi(dest: Reg, src: Reg, imm: BitsI32<11, 0>) -> I { + i_type(imm.to_u(), src, AND, dest, IMM_OP) +} +pub const fn slli(dest: Reg, src: Reg, imm: BitsI32<4, 0>) -> I { + i_type(Bits32::new(imm.to_u().val()), src, SLL, dest, IMM_OP) +} +pub const fn srli(dest: Reg, src: Reg, imm: BitsI32<4, 0>) -> I { + i_type(Bits32::new(imm.to_u().val()), src, SR, dest, IMM_OP) +} pub const fn jal(dest: Reg, offset: BitsI32<20, 1>) -> I { j_type(offset.to_u(), dest, JAL) } diff --git a/src/ir/mod.rs b/src/ir/mod.rs index 06d5b0e..37baf34 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -1,2 +1,128 @@ +use std::collections::HashMap; + +use crate::parser::{Body, Expr, Function, Ident, Literal, ParserError, Statement, Unresolved}; + +#[derive(Debug)] pub enum IRInstruction { + Li(IRIdent, Literal), + Mv(IRIdent, IRIdent), } + +#[derive(Debug)] +pub struct IRFunction { + instructions: Vec, +} + +impl Function { + pub fn lower(&self, functions: &mut Vec, map: &mut Namespace) -> Result<(), ParserError> { + let Ok(name) = &self.name.inner else { + return Ok(()); + }; + if map.get(name).is_some() { + Err(ParserError { + msg: format!("Already something named '{:?}'", self.name), + spans: vec![self.name.span], + }) + } else { + map.add(name); + let mut instructions = Vec::new(); + self.body.as_ref().map(|b| b.lower(map, &mut instructions)); + functions.push(IRFunction { instructions }); + Ok(()) + } + } +} + +impl Body { + pub fn lower(&self, map: &Namespace, instructions: &mut Vec) { + let mut map = map.clone(); + for statement in &self.statements { + let Ok(statement) = &statement.inner else { + continue; + }; + match statement { + Statement::Let(name, expr) => { + let Ok(name) = &name.inner else { + continue; + }; + let name = map.add(name); + let Ok(expr) = &expr.inner else { + continue; + }; + if let Ok(Some(res)) = expr.lower(&map, instructions) { + instructions.push(match res { + ExprResult::Lit(l) => IRInstruction::Li(name, l), + ExprResult::Ident(i) => IRInstruction::Mv(name, i), + }); + } + } + Statement::Return(e) => todo!(), + Statement::Expr(expr) => todo!(), + } + } + } +} + +impl Expr { + pub fn lower( + &self, + map: &Namespace, + instructions: &mut Vec, + ) -> Result, String> { + Ok(match self { + Expr::Lit(l) => { + let Ok(l) = &l.inner else {return Ok(None)}; + Some(ExprResult::Lit(l.clone())) + }, + Expr::Ident(i) => { + let Ok(i) = &i.inner else {return Ok(None)}; + let Some(id) = map.get(i) else { + return Err(format!("Identifier '{:?}' not found", i)); + }; + Some(ExprResult::Ident(id)) + } + Expr::BinaryOp(_, _, _) => todo!(), + Expr::UnaryOp(_, _) => todo!(), + Expr::Block(_) => todo!(), + Expr::Call(_, _) => todo!(), + Expr::Group(_) => todo!(), + }) + } +} + +enum ExprResult { + Lit(Literal), + Ident(IRIdent), +} + +#[derive(Debug, Clone)] +pub struct Namespace { + pub cur: usize, + pub map: HashMap, +} + +impl Namespace { + pub fn new() -> Self { + Self { + cur: 0, + map: HashMap::new(), + } + } + pub fn get(&self, name: &Ident) -> Option { + self.map.get(name.val()).copied() + } + pub fn reserve(&mut self) -> IRIdent { + let id = IRIdent ( self.cur ); + self.cur += 1; + id + } + pub fn add(&mut self, name: &Ident) -> IRIdent { + let id = self.reserve(); + self.map.insert(name.val().to_string(), id); + id + } +} + +#[derive(Debug, Clone, Copy)] +pub struct IRIdent (usize); + diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 4d841d3..85305a5 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1,6 +1,8 @@ mod v1; mod v2; +pub use v1::*; + pub fn main() { let arg = std::env::args_os().nth(1); if let Some(path) = arg { diff --git a/src/parser/v1/cursor.rs b/src/parser/v1/cursor.rs index b0008e8..70bf0d9 100644 --- a/src/parser/v1/cursor.rs +++ b/src/parser/v1/cursor.rs @@ -36,6 +36,14 @@ impl<'a> TokenCursor<'a> { .is_some_and(|n| n.token != Token::Symbol(symbol)) {} } + pub fn seek_syms(&mut self, syms: &[Symbol]) { + while self + .peek() + .is_some_and(|n| !syms.iter().any(|s| n.is_symbol(*s))) + { + self.next(); + } + } pub fn seek(&mut self, f: impl Fn(&TokenInstance) -> bool) -> Option<&TokenInstance> { loop { if f(self.peek()?) { @@ -53,13 +61,6 @@ impl<'a> TokenCursor<'a> { pub fn expect_peek(&mut self) -> Result<&TokenInstance, ParserError> { self.peek().ok_or(ParserError::unexpected_end()) } - pub fn expect_ident(&mut self) -> Result { - let i = self.expect_next()?; - let Token::Ident(n) = &i.token else { - return Err(ParserError::unexpected_token(&i, "an identifier")); - }; - Ok(n.to_string()) - } pub fn chars(&mut self) -> &mut CharCursor<'a> { &mut self.cursor } diff --git a/src/parser/v1/nodes/body.rs b/src/parser/v1/nodes/body.rs index 8472a2a..2ee99c7 100644 --- a/src/parser/v1/nodes/body.rs +++ b/src/parser/v1/nodes/body.rs @@ -7,13 +7,12 @@ use super::{ use crate::util::Padder; pub struct Body { - statements: Vec, R>>, + pub statements: Vec, R>>, } impl Parsable for Body { fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult { let mut statements = Vec::new(); - let statement_end = &[Symbol::Semicolon, Symbol::CloseCurly]; cursor.expect_sym(Symbol::OpenCurly)?; if cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) { cursor.next(); @@ -44,13 +43,12 @@ impl Parsable for Body { let res = Statement::parse_node(cursor, errors); statements.push(res.node); expect_semi = true; - if res.recover - && cursor - .seek(|t| t.is_symbol_and(|s| statement_end.contains(&s))) - .is_none() - { - recover = true; - break; + if res.recover { + cursor.seek_syms(&[Symbol::Semicolon, Symbol::CloseCurly]); + if cursor.peek().is_none() { + recover = true; + break; + } } } ParseResult::from_recover(Self { statements }, recover) diff --git a/src/parser/v1/nodes/expr.rs b/src/parser/v1/nodes/expr.rs index b3ec73f..dcaf788 100644 --- a/src/parser/v1/nodes/expr.rs +++ b/src/parser/v1/nodes/expr.rs @@ -1,16 +1,16 @@ use std::fmt::{Debug, Write}; -use super::token::{Symbol, Token}; use super::{ - BinaryOperator, Body, Literal, MaybeResolved, Node, NodeParsable, Parsable, ParseResult, - ParserError, ParserErrors, Resolvable, Resolved, TokenCursor, UnaryOperator, Unresolved, + BinaryOperator, Body, Ident, Literal, MaybeResolved, Node, NodeParsable, Parsable, ParseResult, + ParserError, ParserErrors, Resolvable, Resolved, Symbol, TokenCursor, UnaryOperator, + Unresolved, }; type BoxNode = Node>, R>; pub enum Expr { Lit(Node), - Ident(String), + Ident(Node), BinaryOp(BinaryOperator, BoxNode, BoxNode), UnaryOp(UnaryOperator, BoxNode), Block(Node, R>), @@ -53,16 +53,12 @@ impl Parsable for Expr { } else if let Some(val) = Node::maybe_parse(cursor, errors) { Self::Lit(val) } else { - let next = cursor.peek().unwrap(); - match &next.token { - Token::Ident(name) => { - let name = name.to_string(); - cursor.next(); - Self::Ident(name) - } - _ => { - return ParseResult::Err(ParserError::unexpected_token(next, "an expression")); - } + let res = Node::parse(cursor, &mut ParserErrors::new()); + if res.node.is_ok() { + Self::Ident(res.node) + } else { + let next = cursor.expect_peek()?; + return ParseResult::Err(ParserError::unexpected_token(next, "an expression")); } }; let Some(mut next) = cursor.peek() else { @@ -71,13 +67,21 @@ impl Parsable for Expr { while next.is_symbol(Symbol::OpenParen) { cursor.next(); let mut args = Vec::new(); - while !cursor.expect_peek()?.is_symbol(Symbol::CloseParen) { + loop { + let next = cursor.expect_peek()?; + if next.is_symbol(Symbol::CloseParen) { + break; + } let res = Node::, Unresolved>::parse(cursor, errors); args.push(res.node); if res.recover { - cursor.seek_sym(Symbol::CloseParen); + 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 end = cursor.prev_end(); @@ -118,7 +122,7 @@ impl Resolvable> for Expr { fn resolve(self) -> Result, ()> { Ok(match self { Expr::Lit(l) => Expr::Lit(l.resolve()?), - Expr::Ident(n) => Expr::Ident(n), + Expr::Ident(n) => Expr::Ident(n.resolve()?), Expr::BinaryOp(o, e1, e2) => Expr::BinaryOp(o, e1.resolve()?, e2.resolve()?), Expr::UnaryOp(o, e) => Expr::UnaryOp(o, e.resolve()?), Expr::Block(b) => Expr::Block(b.resolve()?), @@ -137,7 +141,7 @@ impl Debug for Expr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Expr::Lit(c) => c.fmt(f)?, - Expr::Ident(n) => f.write_str(n)?, + Expr::Ident(n) => n.fmt(f)?, Expr::Block(b) => b.fmt(f)?, Expr::BinaryOp(op, e1, e2) => { write!(f, "({:?}", *e1)?; diff --git a/src/parser/v1/nodes/func.rs b/src/parser/v1/nodes/func.rs index cc54cf0..74f432c 100644 --- a/src/parser/v1/nodes/func.rs +++ b/src/parser/v1/nodes/func.rs @@ -1,28 +1,28 @@ use super::{ - Body, Keyword, MaybeResolved, Node, Parsable, ParseResult, ParserErrors, Resolvable, Resolved, - Symbol, TokenCursor, Unresolved, + Body, Ident, Keyword, MaybeResolved, Node, Parsable, ParseResult, ParserErrors, Resolvable, + Resolved, Symbol, TokenCursor, Unresolved, }; use std::fmt::Debug; pub struct Function { - pub name: String, + pub name: Node, pub body: Node, R>, } impl Parsable for Function { fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult { cursor.expect_kw(Keyword::Fn)?; - let name = cursor.expect_ident()?; + let name = Node::parse(cursor, errors)?; cursor.expect_sym(Symbol::OpenParen)?; cursor.expect_sym(Symbol::CloseParen)?; - Node::parse(cursor, errors).map(|body| Self {name, body}) + Node::parse(cursor, errors).map(|body| Self { name, body }) } } impl Debug for Function { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str("fn ")?; - f.write_str(&self.name)?; + self.name.fmt(f)?; f.write_str("() ")?; self.body.fmt(f)?; Ok(()) @@ -32,7 +32,7 @@ impl Debug for Function { impl Resolvable> for Function { fn resolve(self) -> Result, ()> { Ok(Function { - name: self.name, + name: self.name.resolve()?, body: self.body.resolve()?, }) } diff --git a/src/parser/v1/nodes/ident.rs b/src/parser/v1/nodes/ident.rs new file mode 100644 index 0000000..92d1b09 --- /dev/null +++ b/src/parser/v1/nodes/ident.rs @@ -0,0 +1,34 @@ +use std::fmt::Debug; +use super::{Parsable, ParseResult, ParserError, Resolvable, Token}; + +pub struct Ident(String); + +impl Ident { + pub fn val(&self) -> &String { + &self.0 + } +} + +impl Parsable for Ident { + fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserErrors) -> ParseResult { + let next = cursor.expect_peek()?; + let Token::Ident(name) = &next.token else { + return ParseResult::Err(ParserError::unexpected_token(next, "an identifier")); + }; + let name = name.to_string(); + cursor.next(); + ParseResult::Ok(Self(name)) + } +} + +impl Debug for Ident { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl Resolvable for Ident { + fn resolve(self) -> Result { + Ok(self) + } +} diff --git a/src/parser/v1/nodes/val.rs b/src/parser/v1/nodes/lit.rs similarity index 81% rename from src/parser/v1/nodes/val.rs rename to src/parser/v1/nodes/lit.rs index 8f235db..0ef626c 100644 --- a/src/parser/v1/nodes/val.rs +++ b/src/parser/v1/nodes/lit.rs @@ -1,4 +1,6 @@ -use super::{CharCursor, MaybeParsable, ParserError, ParserErrors, Resolvable, Symbol, Token, TokenCursor}; +use super::{ + CharCursor, MaybeParsable, ParserError, ParserErrors, Resolvable, Symbol, Token, TokenCursor, +}; use std::fmt::Debug; #[derive(Clone, PartialEq, Eq)] @@ -17,7 +19,10 @@ pub struct Number { } impl MaybeParsable for Literal { - fn maybe_parse(cursor: &mut TokenCursor, _: &mut ParserErrors) -> Result, ParserError> { + fn maybe_parse( + cursor: &mut TokenCursor, + _: &mut ParserErrors, + ) -> Result, ParserError> { let inst = cursor.expect_peek()?; let mut res = match &inst.token { Token::Symbol(Symbol::SingleQuote) => { @@ -42,15 +47,14 @@ impl MaybeParsable for Literal { _ => return Ok(None), }; cursor.next(); - if let Some(next) = cursor.peek() { - if let Self::Number(num) = &mut res { - if let Token::Symbol(Symbol::Dot) = next.token { - let chars = cursor.chars(); - if let Some(c) = chars.peek() { - if c.is_ascii_digit() { + if let (Some(next), Self::Number(num)) = (cursor.peek(), &mut res) { + if next.token.is_symbol(Symbol::Dot) { + 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(); - let decimal = cursor.expect_ident()?; - num.decimal = Some(decimal); } } } @@ -114,4 +118,3 @@ impl Debug for Number { Ok(()) } } - diff --git a/src/parser/v1/nodes/mod.rs b/src/parser/v1/nodes/mod.rs index 45286e8..365b9a4 100644 --- a/src/parser/v1/nodes/mod.rs +++ b/src/parser/v1/nodes/mod.rs @@ -4,7 +4,8 @@ mod func; mod module; mod op; mod statement; -mod val; +mod lit; +mod ident; pub use body::*; pub use expr::*; @@ -12,6 +13,7 @@ pub use func::*; pub use module::*; pub use op::*; pub use statement::*; -pub use val::*; +pub use lit::*; +pub use ident::*; use super::*; diff --git a/src/parser/v1/nodes/statement.rs b/src/parser/v1/nodes/statement.rs index c94adc6..9cfede9 100644 --- a/src/parser/v1/nodes/statement.rs +++ b/src/parser/v1/nodes/statement.rs @@ -1,10 +1,10 @@ use std::fmt::{Debug, Write}; use super::{ - Expr, Keyword, MaybeResolved, Node, Parsable, ParseResult, ParserErrors, Resolvable, Resolved, Symbol, Token, TokenCursor, Unresolved + Expr, Ident, Keyword, MaybeResolved, Node, Parsable, ParseResult, ParserErrors, Resolvable, Resolved, Symbol, Token, TokenCursor, Unresolved }; pub enum Statement { - Let(String, Node, R>), + Let(Node, Node, R>), Return(Node, R>), Expr(Node, R>), } @@ -15,7 +15,7 @@ impl Parsable for Statement { match next.token { Token::Keyword(Keyword::Let) => { cursor.next(); - let name = cursor.expect_ident()?; + let name = Node::parse(cursor, errors)?; cursor.expect_sym(Symbol::Equals)?; Node::parse(cursor, errors).map(|expr| Self::Let(name, expr)) } @@ -31,7 +31,7 @@ impl Parsable for Statement { impl Resolvable> for Statement { fn resolve(self) -> Result, ()> { Ok(match self { - Self::Let(i, e) => Statement::Let(i, e.resolve()?), + Self::Let(i, e) => Statement::Let(i.resolve()?, e.resolve()?), Self::Return(e) => Statement::Return(e.resolve()?), Self::Expr(e) => Statement::Expr(e.resolve()?), }) @@ -43,7 +43,7 @@ impl Debug for Statement { match self { Statement::Let(n, e) => { f.write_str("let ")?; - f.write_str(n)?; + n.fmt(f); f.write_str(" = ")?; e.fmt(f)?; f.write_char(';')?; diff --git a/src/parser/v1/parse.rs b/src/parser/v1/parse.rs index 45abd35..e732c6c 100644 --- a/src/parser/v1/parse.rs +++ b/src/parser/v1/parse.rs @@ -68,17 +68,6 @@ impl FromResidual> for ParseResult { } } -impl ParseResult { - pub fn map U>(self, op: F) -> ParseResult { - match self { - Self::Ok(v) => ParseResult::Ok(op(v)), - Self::Recover(v) => ParseResult::Recover(op(v)), - Self::Err(e) => ParseResult::Err(e), - Self::SubErr => ParseResult::SubErr, - } - } -} - pub struct NodeParseResult { pub node: Node, pub recover: bool, @@ -116,8 +105,8 @@ impl Try for NodeParseResult { } impl FromResidual for NodeParseResult { - fn from_residual(residual: ::Residual) -> Self { - // ??? + fn from_residual(_: ::Residual) -> Self { + // I hope this is unreachable ??? unreachable!() } } diff --git a/src/parser/v1/token/symbol.rs b/src/parser/v1/token/symbol.rs index 043bedc..2ed689a 100644 --- a/src/parser/v1/token/symbol.rs +++ b/src/parser/v1/token/symbol.rs @@ -32,6 +32,7 @@ pub enum Symbol { DoubleAmpersand, Pipe, DoublePipe, + Comma, } impl Symbol { @@ -65,6 +66,7 @@ impl Symbol { '!' => Self::Bang, '&' => Self::Ampersand, '|' => Self::Pipe, + ',' => Self::Comma, _ => return None, }) } @@ -93,11 +95,11 @@ impl Symbol { Self::Ampersand => match next { '&' => Self::DoubleAmpersand, _ => return, - } + }, Self::Pipe => match next { '&' => Self::DoublePipe, _ => return, - } + }, _ => return, }; cursor.advance(); @@ -128,6 +130,7 @@ impl Symbol { Self::SingleQuote => "'", Self::DoubleQuote => "\"", Self::Bang => "!", + Self::Comma => ",", Self::Ampersand => "&", Self::DoubleAmpersand => "&&", Self::Pipe => "|",