aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/parser.rs38
-rw-r--r--tests/src/fib.nim13
-rw-r--r--tests/src/negate.nim5
-rw-r--r--tests/test_parser.rs47
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());
+}