parser now bubbles errors instead of unit type

llvm added to dependencies
This commit is contained in:
2025-10-28 12:28:50 +01:00
parent a0a6a15be3
commit 934d961be8
15 changed files with 132 additions and 67 deletions

49
Cargo.lock generated
View File

@@ -32,6 +32,12 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "bitflags"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32866f4d103c4e438b1db1158aa1b1a80ee078e5d77a59a2f906fd62a577389c"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.9.4" version = "2.9.4"
@@ -86,7 +92,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc 0.2.177",
"libredox", "libredox",
"windows-sys", "windows-sys",
] ]
@@ -102,10 +108,17 @@ name = "fudgerust2"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cfgrammar", "cfgrammar",
"llvm-sys",
"lrlex", "lrlex",
"lrpar", "lrpar",
] ]
[[package]]
name = "gcc"
version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
[[package]] [[package]]
name = "getopts" name = "getopts"
version = "0.2.24" version = "0.2.24"
@@ -143,6 +156,12 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.177" version = "0.2.177"
@@ -155,11 +174,23 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb"
dependencies = [ dependencies = [
"bitflags", "bitflags 2.9.4",
"libc", "libc 0.2.177",
"redox_syscall", "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]] [[package]]
name = "lrlex" name = "lrlex"
version = "0.13.10" version = "0.13.10"
@@ -241,7 +272,7 @@ version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
dependencies = [ dependencies = [
"libc", "libc 0.2.177",
] ]
[[package]] [[package]]
@@ -284,7 +315,7 @@ version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [ dependencies = [
"bitflags", "bitflags 2.9.4",
] ]
[[package]] [[package]]
@@ -322,6 +353,12 @@ version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "semver"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.228" version = "1.0.228"
@@ -389,7 +426,7 @@ checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d"
dependencies = [ dependencies = [
"deranged", "deranged",
"itoa", "itoa",
"libc", "libc 0.2.177",
"num-conv", "num-conv",
"num_threads", "num_threads",
"powerfmt", "powerfmt",

View File

@@ -14,3 +14,4 @@ lrpar = "0.13.10"
cfgrammar = "0.13.10" cfgrammar = "0.13.10"
lrlex = "0.13.10" lrlex = "0.13.10"
lrpar = "0.13.10" lrpar = "0.13.10"
llvm-sys = "0.2.1"

View File

@@ -1,14 +1,27 @@
use std::fmt::Display; use std::fmt::Display;
use crate::ast::errors::ParsingErrorKind::InvalidLiteral;
pub struct ExpectedTokenError { #[derive(Debug, Clone, PartialEq, Hash)]
line: usize, pub struct ParsingError {
column_start: usize, pub kind: ParsingErrorKind,
actual: &'static str, pub line: usize,
expected: Vec<&'static str>, pub column_start: usize,
}
#[derive(Debug, Clone, PartialEq, Hash)]
pub enum ParsingErrorKind {
InvalidLiteral,
UnexpectedToken {
expected: Vec<String>,
actual: String,
},
} }
impl Display for ExpectedTokenError { impl ParsingError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { pub fn invalid_literal() -> ParsingError {
write!(f, "line {} column {}:\nExpected one of {} but got {}", self.line, self.column_start, self.expected.join(", "), self.actual) ParsingError {
kind: InvalidLiteral,
line: 0,
column_start: 0,
}
} }
} }

View File

@@ -1,19 +1,20 @@
pub fn parse_int(s: &str) -> Result<i64, ()> { use crate::ast::errors::ParsingError;
match s.parse::<i64>() { use crate::ast::errors::ParsingErrorKind::InvalidLiteral;
Ok(val) => Ok(val), use lrlex::DefaultLexeme;
Err(_) => { use lrpar::Lexeme;
eprintln!("{} cannot be represented as a i64", s);
Err(()) pub fn parse_int(s: &str) -> Result<i64, ParsingError> {
} s.parse::<i64>().map_err(|_| ParsingError {
} kind: InvalidLiteral,
line: 0,
column_start: 0,
})
} }
pub fn parse_float(s: &str) -> Result<f64, ()> { pub fn parse_float(s: &str) -> Result<f64, ParsingError> {
match s.parse::<f64>() { s.parse::<f64>().map_err(|_| ParsingError {
Ok(val) => Ok(val), kind: InvalidLiteral,
Err(_) => { line: 0,
eprintln!("{} cannot be represented as a f64", s); column_start: 0,
Err(()) })
}
}
} }

View File

@@ -1,5 +1,5 @@
pub mod literal_parsers; pub mod literal_parsers;
mod errors; pub mod errors;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Program { pub struct Program {

11
src/codegen/llvm_ir.rs Normal file
View File

@@ -0,0 +1,11 @@
use crate::ast::Literal;
pub trait LLVMIRTranslation {
fn llvm_translate(&self) -> Result<String, ()>;
}
impl LLVMIRTranslation for crate::ast::Literal {
fn llvm_translate(&self) -> Result<String, ()> {
todo!()
}
}

1
src/codegen/mod.rs Normal file
View File

@@ -0,0 +1 @@
mod llvm_ir;

View File

@@ -29,4 +29,5 @@ else "else"
let "let" let "let"
:= "assign" := "assign"
Type "type" Type "type"
@main "main" \@main "main"
[\n;] "linedelim"

View File

@@ -8,7 +8,7 @@ use std::io::ErrorKind::InvalidInput;
mod ast; mod ast;
mod errors; mod errors;
mod optimising; mod codegen;
mod tests; mod tests;
lrlex_mod!("lexers/fudge.l"); lrlex_mod!("lexers/fudge.l");

View File

@@ -1 +0,0 @@

View File

@@ -1 +0,0 @@
mod constfolding;

View File

@@ -1,40 +1,42 @@
%start Expr %start Expr
%% %%
Expr -> Result<Expression, ParsingError >:
Expr -> Result<Expression, () >:
Expr "op_add" MulExpr { Ok(Expression::Add(Box::new( $1? ), Box::new( $3? ))) } 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? ))) } | Expr "op_sub" MulExpr { Ok(Expression::Sub(Box::new( $1? ), Box::new( $3? ))) }
| MulExpr { $1 } | MulExpr { $1 }
; ;
MulExpr -> Result<Expression, () >: MulExpr -> Result<Expression, ParsingError >:
MulExpr "op_mul" ConstExpr { Ok( Expression::Mul(Box::new($1?), Box::new($3?)) ) } 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_div" ConstExpr { Ok( Expression::Div(Box::new($1?), Box::new($3?)) ) }
| MulExpr "op_mod" ConstExpr { Ok( Expression::Mod(Box::new($1?), Box::new($3?)) ) } | MulExpr "op_mod" ConstExpr { Ok( Expression::Mod(Box::new($1?), Box::new($3?)) ) }
| ConstExpr { $1 } | ConstExpr { $1 }
; ;
ConstExpr -> Result<Expression, () >: ConstExpr -> Result<Expression, ParsingError >:
'(' Expr ')' { $2 } '(' Expr ')' { $2 }
| 'lit_int' { | '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()))?))) Ok(Expression::Lit(Literal::Int(parse_int( $lexer.span_str(v.span()))?)))
} }
| "lit_float" { | "lit_float" {
let v = $1.map_err( | _| ())?; let v = $1.map_err( | _| ParsingError::invalid_literal())?;
Ok(Expression::Lit(Literal::Float(parse_float( $lexer.span_str(v.span()))?))) Ok(Expression::Lit(Literal::Float(parse_float($lexer.span_str(v.span()))?)))
} }
| "ident" { | "ident" {
let v = $1.map_err( | _| ())?; let v = $1.map_err( | _| ParsingError::invalid_literal())?;
Ok(Expression::Ident(String::from( $lexer.span_str(v.span())))) Ok(Expression::Ident(String::from( $lexer.span_str(v.span()))))
} }
; ;
%% %%
// Any functions here are in scope for all the grammar actions above. // 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, Expression, Definition, StructDefinition, Program, TypedIdentifier, TypeArg,StructDefLiteral, TypeId};
use crate::ast::literal_parsers::*; use crate::ast::literal_parsers::*;
use crate::ast::errors::ParsingError;

View File

@@ -2,10 +2,10 @@
%% %%
program -> Result<Program, ()>: program -> Result<Program, ParsingError>:
definitionlist maindef { definitionlist maindef {
Ok(Program { Ok(Program {
definition_list: $1?, definition_list: $1.map_err(|_| ParsingError::invalid_literal())?,
main_def: $2? main_def: $2?
}) })
@@ -18,8 +18,8 @@ program -> Result<Program, ()>:
} }
; ;
maindef -> Result<Expression, ()>: maindef -> Result<Expression, ParsingError>:
"main" "assign" Expr {$3} "main" "assign" Expr "linedelim" {$3}
; ;
definitionlist -> Result<Vec<Definition>, ()>: definitionlist -> Result<Vec<Definition>, ()>:
@@ -33,11 +33,11 @@ definitionlist -> Result<Vec<Definition>, ()>:
; ;
definition -> Result<Definition, ()>: definition -> Result<Definition, ()>:
"let" "ident" "assign" Expr { "let" "ident" "assign" Expr "linedelim" {
let v = $2.map_err(|_| ())?; let v = $2.map_err(|_| ())?;
Ok(Definition::Binding { Ok(Definition::Binding {
name: String::from($lexer.span_str(v.span())), name: String::from($lexer.span_str(v.span())),
value: $4? value: $4.map_err(|_|())?
}) })
} }
| "type" "ident" "assign" structdefliteral { | "type" "ident" "assign" structdefliteral {
@@ -51,31 +51,32 @@ definition -> Result<Definition, ()>:
} }
; ;
Expr -> Result<Expression, () >: Expr -> Result<Expression, ParsingError >:
Expr "op_add" MulExpr { Ok(Expression::Add(Box::new( $1? ), Box::new( $3? ))) } 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? ))) } | Expr "op_sub" MulExpr { Ok(Expression::Sub(Box::new( $1? ), Box::new( $3? ))) }
| MulExpr { $1 } | MulExpr { $1 }
; ;
MulExpr -> Result<Expression, () >: MulExpr -> Result<Expression, ParsingError >:
MulExpr "op_mul" ConstExpr { Ok( Expression::Mul(Box::new($1?), Box::new($3?)) ) } 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_div" ConstExpr { Ok( Expression::Div(Box::new($1?), Box::new($3?)) ) }
| MulExpr "op_mod" ConstExpr { Ok( Expression::Mod(Box::new($1?), Box::new($3?)) ) } | MulExpr "op_mod" ConstExpr { Ok( Expression::Mod(Box::new($1?), Box::new($3?)) ) }
| ConstExpr { $1 } | ConstExpr { $1 }
; ;
ConstExpr -> Result<Expression, () >: ConstExpr -> Result<Expression, ParsingError >:
'(' Expr ')' { $2 } '(' Expr ')' { $2 }
| 'lit_int' { | '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()))?))) Ok(Expression::Lit(Literal::Int(parse_int( $lexer.span_str(v.span()))?)))
} }
| "lit_float" { | "lit_float" {
let v = $1.map_err( | _| ())?; let v = $1.map_err( | _| ParsingError::invalid_literal())?;
Ok(Expression::Lit(Literal::Float(parse_float( $lexer.span_str(v.span()))?))) Ok(Expression::Lit(Literal::Float(parse_float($lexer.span_str(v.span()))?)))
} }
| "ident" { | "ident" {
let v = $1.map_err( | _| ())?; let v = $1.map_err( | _| ParsingError::invalid_literal())?;
Ok(Expression::Ident(String::from( $lexer.span_str(v.span())))) Ok(Expression::Ident(String::from( $lexer.span_str(v.span()))))
} }
; ;
@@ -117,6 +118,7 @@ typearg -> Result<TypeArg, ()>:
// Any functions here are in scope for all the grammar actions above. // 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, Expression, Definition, StructDefinition, Program, TypedIdentifier, TypeArg,StructDefLiteral, TypeId};
use crate::ast::literal_parsers::*; use crate::ast::literal_parsers::*;
use crate::ast::errors::ParsingError;

View File

@@ -1,6 +1,7 @@
use lrlex::lrlex_mod; use lrlex::lrlex_mod;
use lrpar::lrpar_mod; use lrpar::lrpar_mod;
use crate::ast::errors::ParsingError;
use crate::ast::{Expression, Literal, Program}; use crate::ast::{Expression, Literal, Program};
lrlex_mod!("lexers/fudge.l"); lrlex_mod!("lexers/fudge.l");
@@ -21,19 +22,14 @@ macro_rules! test_literal_list {
}; };
} }
fn parse_expr(input: &str) -> Result<Expression, ()> { fn parse_expr(input: &str) -> Result<Expression, ParsingError> {
let lexerdef = expr_only_l::lexerdef(); let lexerdef = expr_only_l::lexerdef();
let lexer = lexerdef.lexer(&input); let lexer = lexerdef.lexer(&input);
let (res, errs) = expr_only_y::parse(&lexer); let (res, errs) = expr_only_y::parse(&lexer);
if let Some(parsed_res) = res { res.expect("REASON")
parsed_res
} else {
Err(())
}
} }
#[test] #[test]
fn test_int_literal() { fn test_int_literal() {
let matches_parsed_int = |s: &str| match parse_expr(s) { let matches_parsed_int = |s: &str| match parse_expr(s) {
Ok(i) => matches!(i, Expression::Lit(Literal::Int(_))), Ok(i) => matches!(i, Expression::Lit(Literal::Int(_))),
Err(_) => false, Err(_) => false,

View File

@@ -1 +1,3 @@
13 / 14 % 17 * let a := 1
@main := a