diff --git a/src/grammar.pest b/src/grammar.pest
index 70f9810..7c87493 100644
--- a/src/grammar.pest
+++ b/src/grammar.pest
@@ -5,11 +5,14 @@ block_line = _{ expr | (statement ~ MLF)* }
statement = { (decl | type_decl | expr) ~ TERMINATE }
decl = { "let" ~ #name = ident ~ #args = (ident)* ~ "=" ~ expr }
-type_decl = { "type" ~ #name = type_ident ~ "=" ~ type_expr }
-type_expr = { tuple | type_ident }
-tuple = { "#(" ~ type_expr* ~ ")" }
-type_ident = ${ #name = ident ~ #args = type_args? }
-type_args = { "<" ~ type_ident* ~ ">" }
+type_decl = { "type" ~ #name = type_ident ~ "=" ~ type_expr }
+type_expr = { tuple | rec | type_ident }
+tuple = { "#(" ~ MLF ~ tuple_entry* ~ MLF ~ ")" }
+tuple_entry = _{ type_expr ~ MLF }
+rec = { "#{" ~ MLF ~ (rec_field ~ TERMINATE ~ MLF)* ~ rec_field? ~ MLF ~ "}" }
+rec_field = { #field_name = ident ~ ":" ~ #field_type = type_expr* }
+type_ident = ${ #name = ident ~ #args = type_args? }
+type_args = { "<" ~ MLF ~ type_ident* ~ MLF ~ ">" }
expr = { infix_expr | call_expr | term }
term = _{ ident | literal | "(" ~ MLF ~ expr ~ MLF ~ ")" | block }
diff --git a/src/test/types.rs b/src/test/types.rs
index 351974d..58af932 100644
--- a/src/test/types.rs
+++ b/src/test/types.rs
@@ -49,6 +49,40 @@ fn it_parses_tuples() {
]);
}
+#[test]
+fn it_parses_recs() {
+ parses_to!(parser: SnekParser, input: "type MyRec = #{\nfield1: Num\n field2: Num2 }", rule: Rule::statement, tokens: [
+ statement(0, 43, [
+ type_decl(0, 43, [
+ type_ident(5, 10, [
+ ident(5, 10)
+ ]),
+ type_expr(13, 43, [
+ rec(13, 43, [
+ rec_field(16, 27, [
+ ident(16, 22),
+ type_expr(24, 27, [
+ type_ident(24, 27, [
+ ident(24, 27)
+ ])
+ ]),
+ ]),
+ rec_field(29, 41, [
+ ident(29, 35),
+ type_expr(37, 41, [
+ type_ident(37, 41, [
+ ident(37, 41)
+ ])
+ ]),
+ ])
+ ])
+ ])
+ ]),
+ EOI(43, 43)
+ ])
+ ]);
+}
+
#[test]
fn it_parses_generics() {
parses_to!(parser: SnekParser, input: "type MyNum = Num", rule: Rule::statement, tokens: [