diff --git a/src/parser/parser.rs b/src/parser/parser.rs index b8d0c0f..d4de401 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -78,6 +78,7 @@ fn parse_simple_expr(tokens: &mut Tokens) -> ParseResult { parse_string, parse_bool, parse_fn, + parse_record, |t| t.between(&Token::OpenParen, &Token::CloseParen, parse_expr), ]) } @@ -110,6 +111,40 @@ fn parse_args(tokens: &mut Tokens) -> ParseResult> { }) } +fn parse_record(tokens: &mut Tokens) -> ParseResult { + if let Some(vect) = tokens.between(&Token::OpenCurly, &Token::CloseCurly, |tokens| { + tokens.many_sep_by(&Token::Comma, parse_record_field_expr) + })? { + Ok(Some(ast::Expr::Value(ast::Value::Record(ast::Record( + vect.into_iter().collect(), + ))))) + } else { + Ok(None) + } +} + +fn parse_record_field_expr(tokens: &mut Tokens) -> ParseResult<(ast::Label, ast::Expr)> { + if let Some(label) = parse_identifier_label(tokens)? { + if let Some(_) = tokens.next_if(&Token::Colon) { + if let Some(expr) = parse_expr(tokens)? { + Ok(Some((label, expr))) + } else { + Err(Error::UnexpectedTokenForParser( + "parse_record_field_expr_expr".into(), + tokens.next(), + )) + } + } else { + Err(Error::UnexpectedToken { + expected: Token::Colon, + got: tokens.next(), + }) + } + } else { + Ok(None) + } +} + fn parse_string(tokens: &mut Tokens) -> ParseResult { if let Some(LocatedToken { token: Token::String(string), @@ -143,12 +178,20 @@ fn parse_identifier_arg(tokens: &mut Tokens) -> ParseResult { } fn parse_identifier_name(tokens: &mut Tokens) -> ParseResult { + Ok(parse_identifier_string(tokens)?.map(|string| ast::Name(string))) +} + +fn parse_identifier_label(tokens: &mut Tokens) -> ParseResult { + Ok(parse_identifier_string(tokens)?.map(|string| ast::Label(string))) +} + +fn parse_identifier_string(tokens: &mut Tokens) -> ParseResult { if let Some(LocatedToken { token: Token::Identifier(string), .. }) = tokens.next_if(&Token::Identifier("".into())) { - Ok(Some(ast::Name(string))) + Ok(Some(string)) } else { Ok(None) } @@ -195,6 +238,12 @@ mod tests { insta::assert_debug_snapshot!(result); } #[test] + fn record() { + let program = "{ hello: 17, hi: \"cool\"}".to_string(); + let result = parse(&mut scan(program), parse_expr); + insta::assert_debug_snapshot!(result); + } + #[test] fn fn_def() { let program = "fn(a1, boco, c_c) { 108 }".to_string(); let result = parse(&mut scan(program), parse_expr); diff --git a/src/parser/snapshots/ayin__parser__parser__tests__record.snap b/src/parser/snapshots/ayin__parser__parser__tests__record.snap new file mode 100644 index 0000000..b6ee964 --- /dev/null +++ b/src/parser/snapshots/ayin__parser__parser__tests__record.snap @@ -0,0 +1,28 @@ +--- +source: src/parser/parser.rs +expression: result +--- +Ok( + Value( + Record( + Record( + { + Label( + "hello", + ): Value( + Int( + 17, + ), + ), + Label( + "hi", + ): Value( + String( + "cool", + ), + ), + }, + ), + ), + ), +)