From 934d961be8f661031824ff11d53696ab3070a03d Mon Sep 17 00:00:00 2001 From: Iwan Snel Date: Tue, 28 Oct 2025 12:28:50 +0100 Subject: [PATCH] parser now bubbles errors instead of unit type llvm added to dependencies --- Cargo.lock | 49 +++++++++++++++++++++++++++++----- Cargo.toml | 1 + src/ast/errors.rs | 33 ++++++++++++++++------- src/ast/literal_parsers.rs | 35 ++++++++++++------------ src/ast/mod.rs | 2 +- src/codegen/llvm_ir.rs | 11 ++++++++ src/codegen/mod.rs | 1 + src/lexers/fudge.l | 3 ++- src/main.rs | 2 +- src/optimising/constfolding.rs | 1 - src/optimising/mod.rs | 1 - src/parsers/expr_only.y | 18 +++++++------ src/parsers/fudge.y | 28 ++++++++++--------- src/tests/literals.rs | 10 +++---- test.txt | 4 ++- 15 files changed, 132 insertions(+), 67 deletions(-) create mode 100644 src/codegen/llvm_ir.rs create mode 100644 src/codegen/mod.rs delete mode 100644 src/optimising/constfolding.rs delete mode 100644 src/optimising/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 5af3309..31b6fa7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,6 +32,12 @@ dependencies = [ "serde", ] +[[package]] +name = "bitflags" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32866f4d103c4e438b1db1158aa1b1a80ee078e5d77a59a2f906fd62a577389c" + [[package]] name = "bitflags" version = "2.9.4" @@ -86,7 +92,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" dependencies = [ "cfg-if", - "libc", + "libc 0.2.177", "libredox", "windows-sys", ] @@ -102,10 +108,17 @@ name = "fudgerust2" version = "0.1.0" dependencies = [ "cfgrammar", + "llvm-sys", "lrlex", "lrpar", ] +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" + [[package]] name = "getopts" version = "0.2.24" @@ -143,6 +156,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "libc" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122" + [[package]] name = "libc" version = "0.2.177" @@ -155,11 +174,23 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ - "bitflags", - "libc", + "bitflags 2.9.4", + "libc 0.2.177", "redox_syscall", ] +[[package]] +name = "llvm-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5e8322ae48d7a8831627ca58aeb0601f97d7e4119d6c733118c4a3ea2c04e29" +dependencies = [ + "bitflags 0.3.3", + "gcc", + "libc 0.1.12", + "semver", +] + [[package]] name = "lrlex" version = "0.13.10" @@ -241,7 +272,7 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" dependencies = [ - "libc", + "libc 0.2.177", ] [[package]] @@ -284,7 +315,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags", + "bitflags 2.9.4", ] [[package]] @@ -322,6 +353,12 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "semver" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" + [[package]] name = "serde" version = "1.0.228" @@ -389,7 +426,7 @@ checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "itoa", - "libc", + "libc 0.2.177", "num-conv", "num_threads", "powerfmt", diff --git a/Cargo.toml b/Cargo.toml index 20eb97d..2b26a2e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,4 @@ lrpar = "0.13.10" cfgrammar = "0.13.10" lrlex = "0.13.10" lrpar = "0.13.10" +llvm-sys = "0.2.1" \ No newline at end of file diff --git a/src/ast/errors.rs b/src/ast/errors.rs index 7e47ffc..1f80597 100644 --- a/src/ast/errors.rs +++ b/src/ast/errors.rs @@ -1,14 +1,27 @@ use std::fmt::Display; +use crate::ast::errors::ParsingErrorKind::InvalidLiteral; -pub struct ExpectedTokenError { - line: usize, - column_start: usize, - actual: &'static str, - expected: Vec<&'static str>, -} +#[derive(Debug, Clone, PartialEq, Hash)] +pub struct ParsingError { + pub kind: ParsingErrorKind, + pub line: usize, + pub column_start: usize, +} +#[derive(Debug, Clone, PartialEq, Hash)] +pub enum ParsingErrorKind { + InvalidLiteral, + UnexpectedToken { + expected: Vec, + actual: String, + }, +} -impl Display for ExpectedTokenError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "line {} column {}:\nExpected one of {} but got {}", self.line, self.column_start, self.expected.join(", "), self.actual) +impl ParsingError { + pub fn invalid_literal() -> ParsingError { + ParsingError { + kind: InvalidLiteral, + line: 0, + column_start: 0, + } } -} \ No newline at end of file +} diff --git a/src/ast/literal_parsers.rs b/src/ast/literal_parsers.rs index 4dc0943..7efa38b 100644 --- a/src/ast/literal_parsers.rs +++ b/src/ast/literal_parsers.rs @@ -1,19 +1,20 @@ -pub fn parse_int(s: &str) -> Result { - match s.parse::() { - Ok(val) => Ok(val), - Err(_) => { - eprintln!("{} cannot be represented as a i64", s); - Err(()) - } - } +use crate::ast::errors::ParsingError; +use crate::ast::errors::ParsingErrorKind::InvalidLiteral; +use lrlex::DefaultLexeme; +use lrpar::Lexeme; + +pub fn parse_int(s: &str) -> Result { + s.parse::().map_err(|_| ParsingError { + kind: InvalidLiteral, + line: 0, + column_start: 0, + }) } -pub fn parse_float(s: &str) -> Result { - match s.parse::() { - Ok(val) => Ok(val), - Err(_) => { - eprintln!("{} cannot be represented as a f64", s); - Err(()) - } - } -} \ No newline at end of file +pub fn parse_float(s: &str) -> Result { + s.parse::().map_err(|_| ParsingError { + kind: InvalidLiteral, + line: 0, + column_start: 0, + }) +} diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 354e0f1..107b09b 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1,5 +1,5 @@ pub mod literal_parsers; -mod errors; +pub mod errors; #[derive(Debug, Clone, PartialEq)] pub struct Program { diff --git a/src/codegen/llvm_ir.rs b/src/codegen/llvm_ir.rs new file mode 100644 index 0000000..dd94037 --- /dev/null +++ b/src/codegen/llvm_ir.rs @@ -0,0 +1,11 @@ +use crate::ast::Literal; + +pub trait LLVMIRTranslation { + fn llvm_translate(&self) -> Result; +} + +impl LLVMIRTranslation for crate::ast::Literal { + fn llvm_translate(&self) -> Result { + todo!() + } +} diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs new file mode 100644 index 0000000..16ec4a5 --- /dev/null +++ b/src/codegen/mod.rs @@ -0,0 +1 @@ +mod llvm_ir; diff --git a/src/lexers/fudge.l b/src/lexers/fudge.l index 416e1d5..8b461bc 100644 --- a/src/lexers/fudge.l +++ b/src/lexers/fudge.l @@ -29,4 +29,5 @@ else "else" let "let" := "assign" Type "type" -@main "main" +\@main "main" +[\n;] "linedelim" diff --git a/src/main.rs b/src/main.rs index 399d0f8..e378dff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,7 @@ use std::io::ErrorKind::InvalidInput; mod ast; mod errors; -mod optimising; +mod codegen; mod tests; lrlex_mod!("lexers/fudge.l"); diff --git a/src/optimising/constfolding.rs b/src/optimising/constfolding.rs deleted file mode 100644 index 8b13789..0000000 --- a/src/optimising/constfolding.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/optimising/mod.rs b/src/optimising/mod.rs deleted file mode 100644 index 126d1c3..0000000 --- a/src/optimising/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod constfolding; diff --git a/src/parsers/expr_only.y b/src/parsers/expr_only.y index 721bdbf..d353428 100644 --- a/src/parsers/expr_only.y +++ b/src/parsers/expr_only.y @@ -1,40 +1,42 @@ %start Expr %% - -Expr -> Result: +Expr -> Result: Expr "op_add" MulExpr { Ok(Expression::Add(Box::new( $1? ), Box::new( $3? ))) } | Expr "op_sub" MulExpr { Ok(Expression::Sub(Box::new( $1? ), Box::new( $3? ))) } | MulExpr { $1 } ; -MulExpr -> Result: +MulExpr -> Result: MulExpr "op_mul" ConstExpr { Ok( Expression::Mul(Box::new($1?), Box::new($3?)) ) } | MulExpr "op_div" ConstExpr { Ok( Expression::Div(Box::new($1?), Box::new($3?)) ) } | MulExpr "op_mod" ConstExpr { Ok( Expression::Mod(Box::new($1?), Box::new($3?)) ) } | ConstExpr { $1 } ; -ConstExpr -> Result: +ConstExpr -> Result: '(' Expr ')' { $2 } + | 'lit_int' { - let v = $1.map_err( | _| ())?; + let v = $1.map_err( | _| ParsingError::invalid_literal() )?; Ok(Expression::Lit(Literal::Int(parse_int( $lexer.span_str(v.span()))?))) } | "lit_float" { - let v = $1.map_err( | _| ())?; - Ok(Expression::Lit(Literal::Float(parse_float( $lexer.span_str(v.span()))?))) + let v = $1.map_err( | _| ParsingError::invalid_literal())?; + Ok(Expression::Lit(Literal::Float(parse_float($lexer.span_str(v.span()))?))) } | "ident" { -let v = $1.map_err( | _| ())?; + let v = $1.map_err( | _| ParsingError::invalid_literal())?; Ok(Expression::Ident(String::from( $lexer.span_str(v.span())))) } ; + %% // Any functions here are in scope for all the grammar actions above. use crate::ast::{Literal, Expression, Definition, StructDefinition, Program, TypedIdentifier, TypeArg,StructDefLiteral, TypeId}; use crate::ast::literal_parsers::*; +use crate::ast::errors::ParsingError; diff --git a/src/parsers/fudge.y b/src/parsers/fudge.y index da4a5a3..b993bc2 100644 --- a/src/parsers/fudge.y +++ b/src/parsers/fudge.y @@ -2,10 +2,10 @@ %% -program -> Result: +program -> Result: definitionlist maindef { Ok(Program { - definition_list: $1?, + definition_list: $1.map_err(|_| ParsingError::invalid_literal())?, main_def: $2? }) @@ -18,8 +18,8 @@ program -> Result: } ; -maindef -> Result: - "main" "assign" Expr {$3} +maindef -> Result: + "main" "assign" Expr "linedelim" {$3} ; definitionlist -> Result, ()>: @@ -33,11 +33,11 @@ definitionlist -> Result, ()>: ; definition -> Result: - "let" "ident" "assign" Expr { + "let" "ident" "assign" Expr "linedelim" { let v = $2.map_err(|_| ())?; Ok(Definition::Binding { name: String::from($lexer.span_str(v.span())), - value: $4? + value: $4.map_err(|_|())? }) } | "type" "ident" "assign" structdefliteral { @@ -51,31 +51,32 @@ definition -> Result: } ; -Expr -> Result: +Expr -> Result: Expr "op_add" MulExpr { Ok(Expression::Add(Box::new( $1? ), Box::new( $3? ))) } | Expr "op_sub" MulExpr { Ok(Expression::Sub(Box::new( $1? ), Box::new( $3? ))) } | MulExpr { $1 } ; -MulExpr -> Result: +MulExpr -> Result: MulExpr "op_mul" ConstExpr { Ok( Expression::Mul(Box::new($1?), Box::new($3?)) ) } | MulExpr "op_div" ConstExpr { Ok( Expression::Div(Box::new($1?), Box::new($3?)) ) } | MulExpr "op_mod" ConstExpr { Ok( Expression::Mod(Box::new($1?), Box::new($3?)) ) } | ConstExpr { $1 } ; -ConstExpr -> Result: +ConstExpr -> Result: '(' Expr ')' { $2 } + | 'lit_int' { - let v = $1.map_err( | _| ())?; + let v = $1.map_err( | _| ParsingError::invalid_literal() )?; Ok(Expression::Lit(Literal::Int(parse_int( $lexer.span_str(v.span()))?))) } | "lit_float" { - let v = $1.map_err( | _| ())?; - Ok(Expression::Lit(Literal::Float(parse_float( $lexer.span_str(v.span()))?))) + let v = $1.map_err( | _| ParsingError::invalid_literal())?; + Ok(Expression::Lit(Literal::Float(parse_float($lexer.span_str(v.span()))?))) } | "ident" { -let v = $1.map_err( | _| ())?; + let v = $1.map_err( | _| ParsingError::invalid_literal())?; Ok(Expression::Ident(String::from( $lexer.span_str(v.span())))) } ; @@ -117,6 +118,7 @@ typearg -> Result: // Any functions here are in scope for all the grammar actions above. use crate::ast::{Literal, Expression, Definition, StructDefinition, Program, TypedIdentifier, TypeArg,StructDefLiteral, TypeId}; use crate::ast::literal_parsers::*; +use crate::ast::errors::ParsingError; diff --git a/src/tests/literals.rs b/src/tests/literals.rs index 9fa2e50..61e7af0 100644 --- a/src/tests/literals.rs +++ b/src/tests/literals.rs @@ -1,6 +1,7 @@ use lrlex::lrlex_mod; use lrpar::lrpar_mod; +use crate::ast::errors::ParsingError; use crate::ast::{Expression, Literal, Program}; lrlex_mod!("lexers/fudge.l"); @@ -21,19 +22,14 @@ macro_rules! test_literal_list { }; } -fn parse_expr(input: &str) -> Result { +fn parse_expr(input: &str) -> Result { let lexerdef = expr_only_l::lexerdef(); let lexer = lexerdef.lexer(&input); let (res, errs) = expr_only_y::parse(&lexer); - if let Some(parsed_res) = res { - parsed_res - } else { - Err(()) - } + res.expect("REASON") } #[test] fn test_int_literal() { - let matches_parsed_int = |s: &str| match parse_expr(s) { Ok(i) => matches!(i, Expression::Lit(Literal::Int(_))), Err(_) => false, diff --git a/test.txt b/test.txt index 62d19a3..0b18636 100644 --- a/test.txt +++ b/test.txt @@ -1 +1,3 @@ -13 / 14 % 17 * \ No newline at end of file +let a := 1 + +@main := a \ No newline at end of file