diff options
-rw-r--r-- | Cargo.lock | 54 | ||||
-rw-r--r-- | Cargo.toml | 6 | ||||
-rw-r--r-- | src/parser.rs | 84 |
3 files changed, 143 insertions, 1 deletions
@@ -3,5 +3,59 @@ version = 3 [[package]] +name = "peg" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a07f2cafdc3babeebc087e499118343442b742cc7c31b4d054682cc598508554" +dependencies = [ + "peg-macros", + "peg-runtime", +] + +[[package]] +name = "peg-macros" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a90084dc05cf0428428e3d12399f39faad19b0909f64fb9170c9fdd6d9cd49b" +dependencies = [ + "peg-runtime", + "proc-macro2", + "quote", +] + +[[package]] +name = "peg-runtime" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa00462b37ead6d11a82c9d568b26682d78e0477dc02d1966c013af80969739" + +[[package]] +name = "proc-macro2" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +dependencies = [ + "proc-macro2", +] + +[[package]] name = "type-systems" version = "0.1.0" +dependencies = [ + "peg", +] + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" @@ -4,3 +4,9 @@ version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +peg = "0.8.1" + +[features] +trace = ["peg/trace"] diff --git a/src/parser.rs b/src/parser.rs index 3223619..cb86ea7 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,6 +1,88 @@ use crate::ast::*; +// (λx:T.y): T z pub fn parse(input: &str) -> Expression { - let input = input.trim(); + return parse_str(input).expect("invalid expression"); +} + +/// Parses a lambda-calculus-like language into an AST. +pub fn parse_str(input: &str) -> Result<Expression, peg::error::ParseError<peg::str::LineCol>> { + // this is kinda awful + // i miss my nim pegs + peg::parser!{ + grammar lambda() for str { + rule identifier() -> String + = i:['a'..='z' | 'A'..='Z' | '0'..='9']+ { + i.iter().collect::<String>() + } + rule kind() -> Type + = k:identifier() { + match k.as_str() { + "unit" => Type::Unit, + "bool" => Type::Bool, + "int" => Type::Natural, + _ => panic!("invalid type") + } + } + rule annotation() -> Expression + = e:(conditional() / abstraction() / application() / constant() / variable()) " "* ":" " "* k:kind() { + Expression::Annotation { + expr: Box::new(e), + kind: k + } + } + rule constant() -> Expression + = c:['0'..='9']+ { + Expression::Constant { + term: Term { + val: c.iter().collect::<String>().parse::<Value>().unwrap(), + kind: Type::Empty + } + } + } + rule variable() -> Expression + = v:identifier() { + Expression::Variable { + id: v + } + } + // fixme: lambda is causing problems with rust-peg + rule abstraction() -> Expression + = "λ" " "* p:identifier() " "+ "." " "+ f:expression() { + Expression::Abstraction { + param: p, + func: Box::new(f) + } + } + rule application() -> Expression + = "(" f:(abstraction() / annotation()) ")" " "+ a:expression() { + Expression::Application { + func: Box::new(f), + arg: Box::new(a) + } + } + rule conditional() -> Expression + = "if" " "+ c:expression() " "+ "then" " "+ t:expression() " "+ "else" " "+ e:expression() { + Expression::Conditional { + if_cond: Box::new(c), + if_then: Box::new(t), + if_else: Box::new(e) + } + } + pub rule expression() -> Expression + = e:(conditional() / annotation() / abstraction() / application() / constant() / variable()) { + e + } + pub rule ast() -> Vec<Expression> + = expression() ** ("\n"+) + } + } + // assert_eq!(lambda::expression("(λx:bool.x)").unwrap(), lambda::expression("(λx: bool . x)").unwrap()); + + return lambda::expression(input.trim()); +} + +/// Parses a Nim-like language into an AST. +pub fn parse_file(path: &str) -> Vec<Expression> { todo!(); } |