diff options
-rw-r--r-- | src/parser.rs | 38 | ||||
-rw-r--r-- | tests/src/fib.nim | 13 | ||||
-rw-r--r-- | tests/src/negate.nim | 5 | ||||
-rw-r--r-- | tests/test_parser.rs | 47 |
4 files changed, 70 insertions, 33 deletions
diff --git a/src/parser.rs b/src/parser.rs index 7739a85..add31d9 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -173,6 +173,7 @@ pub fn lex(input: &str) -> Result<String, &'static str> { result.push('\n'); result.push_str(&" ".repeat(state.level)); result.push('}'); + result.push(';'); state.previous = Previous::Block; } result.push('\n'); @@ -214,6 +215,7 @@ pub fn lex(input: &str) -> Result<String, &'static str> { result.push('\n'); result.push_str(&" ".repeat(state.level)); result.push('}'); + result.push(';'); } return Ok(result); } @@ -240,26 +242,33 @@ pub fn parse_lang(input: &str) -> Result<Vec<Expression>, peg::error::ParseError } else { value }, - kind: Type::Empty + kind: Type::Empty // fixme } } } // types - // still fucking awful - rule empty() -> Type = k:"empty" {Type::Empty} - rule unit() -> Type = k:"unit" {Type::Unit} - rule boolean() -> Type = k:"bool" {Type::Boolean} - rule natural() -> Type = k:"nat" {Type::Natural} - rule integer() -> Type = k:"int" {Type::Integer} - rule function() -> Type = f:kind() w() "->" w() t:kind() { + rule primitive() -> Type = k:$("empty" / "unit" / "bool" / "nat" / "int") { + match k { + "empty" => Type::Empty, + "unit" => Type::Unit, + "bool" => Type::Boolean, + "nat" => Type::Natural, + "int" => Type::Integer, + _ => Type::Empty // never happens + } + } + // fixme: parenthesis necessary, left-recursion issue + rule function() -> Type = "(" w()? f:kind() w()? "->" w()? t:kind() w()? ")" { Type::Function { from: Box::new(f), to: Box::new(t) } } + // todo: records, etc rule kind() -> Type - = k:(empty() / unit() / boolean() / natural() / integer()) { + = k:(function() / primitive()) { k } + // fixme: cannot say e:(expr()), left-recursion issue rule ann() -> Expression - = e:(cond() / abs() / app() / cons() / var()) w() ":" w() k:kind() { + = e:(cond() / abs() / app() / cons() / var()) w()? ":" w() k:kind() { Expression::Annotation { expr: Box::new(e), kind: k @@ -271,8 +280,9 @@ pub fn parse_lang(input: &str) -> Result<Vec<Expression>, peg::error::ParseError id: v } } + // todo: multiple parameters pls rule abs() -> Expression - = "func" "(" p:ident() ")" w() k:function() w() "=" w() "{" f:expr() "}" { + = "func" w() n:ident() w()? "(" p:ident() ")" w()? ":" w()? k:function() w() "=" w() "{" w() f:expr() w() "}" { Expression::Annotation { expr: Box::new(Expression::Abstraction { param: p, func: Box::new(f) }), kind: k @@ -287,7 +297,7 @@ pub fn parse_lang(input: &str) -> Result<Vec<Expression>, peg::error::ParseError } } rule cond() -> Expression - = "if" w() c:expr() w() ":" w() "{" w() t:expr() w() "}" w() "else:" w() "{" w() e:expr() w() "}" { + = "if" w() c:expr() w() "=" w() "{" w() t:expr() w() "};" w() "else" w() "=" w() "{" w() e:expr() w() "}" { Expression::Conditional { if_cond: Box::new(c), if_then: Box::new(t), @@ -295,11 +305,11 @@ pub fn parse_lang(input: &str) -> Result<Vec<Expression>, peg::error::ParseError } } pub rule expr() -> Expression - = w()? e:(cond()) w()? { + = e:(ann() / cond() / abs() / app() / cons() / var()) ";" { e } pub rule file() -> Vec<Expression> - = expr() ++ w() + = expr() ++ "\n" } } return puck::file(input); diff --git a/tests/src/fib.nim b/tests/src/fib.nim new file mode 100644 index 0000000..34d38f0 --- /dev/null +++ b/tests/src/fib.nim @@ -0,0 +1,13 @@ +# fake nim + +func fib(x): int -> int = + if eq(x, 0): + 0 + else: + if eq(x, 1): + 1 + else: # comment + add(fib(sub(x, 1)), fib(sub(x, 2))) + +negate(negate(1)) +fib(5) diff --git a/tests/src/negate.nim b/tests/src/negate.nim new file mode 100644 index 0000000..c775e74 --- /dev/null +++ b/tests/src/negate.nim @@ -0,0 +1,5 @@ +func negate(x): bool -> bool = + if x: + 0 + else: + 1 diff --git a/tests/test_parser.rs b/tests/test_parser.rs index c619745..e33cdfa 100644 --- a/tests/test_parser.rs +++ b/tests/test_parser.rs @@ -52,43 +52,36 @@ fn test_complex_annotations() { } const program: &'static str = -"func foo() = - bar - if this: +"func foo(x): (int -> int) = + if this = that - else: + else = this hello foo bar baz -func foo = +func foo: (bool -> int) = this - if that: - then this "; const lexed: &'static str = -"func foo() = { - bar; - if this: { +"func foo(x): (int -> int) = { + if this = { that; - } - else: { + }; + else = { this; - } -} + }; +}; hello; foo; bar; baz; -func foo = { +func foo: (bool -> int) = { this; - if that: { - then this; - } -}"; +};"; #[test] fn test_lexer() { @@ -96,3 +89,19 @@ fn test_lexer() { assert!(result.is_ok()); assert_eq!(result.unwrap(), lexed); } + +#[test] +fn test_parser() { + let result = parse_lang(lexed); + assert!(result.is_err()); + + let file = std::fs::read_to_string("tests/src/negate.nim"); + assert!(file.is_ok()); + let result = parse_lang(&file.unwrap()); + assert!(result.is_err()); + + let file = std::fs::read_to_string("tests/src/fib.nim"); + assert!(file.is_ok()); + let result = parse_lang(&file.unwrap()); + assert!(result.is_err()); +} |