@@ -213,22 +213,48 @@ fn expr<'sc>() -> impl Parser<Token<'sc>, ast::Expr, Error = ParseError<'sc>> +
213
213
. delimited_by ( just ( Token :: ParenOpen ) , just ( Token :: ParenClose ) ) ;
214
214
215
215
let call = ident ( )
216
- . then ( args)
216
+ . then ( args. clone ( ) )
217
217
. map ( |( name, args) | ast:: Expr :: Call { name, args } ) ;
218
218
219
+ let tuple = args. map ( ast:: Expr :: Tuple ) ;
220
+
219
221
let atom = choice ( (
220
222
immediate ( ) . map ( ast:: Expr :: Immediate ) ,
221
223
unary_op ( expr. clone ( ) ) ,
222
224
code_block_expr ( expr. clone ( ) ) . map ( ast:: Expr :: Block ) ,
223
225
if_expr ( expr. clone ( ) ) ,
224
226
call,
227
+ tuple,
225
228
ident ( ) . map ( ast:: Expr :: Ident ) ,
226
229
) ) ;
227
230
228
- comparison_op ( additive_op ( multiplicative_op ( atom) ) )
231
+ comparison_op ( additive_op ( multiplicative_op ( tuple_index ( atom) ) ) )
229
232
} )
230
233
}
231
234
235
+ fn tuple_index < ' sc , P > (
236
+ parser : P ,
237
+ ) -> impl Parser < Token < ' sc > , ast:: Expr , Error = ParseError < ' sc > > + Clone
238
+ where
239
+ P : Parser < Token < ' sc > , ast:: Expr , Error = ParseError < ' sc > > + Clone ,
240
+ {
241
+ // This extracts a `usize` index. Fails for everything else (therefore, `t.0.0` is not
242
+ // supported - but `t.0 .0` is fine).
243
+ let index = filter_map ( |span, token| match token {
244
+ Token :: IntLiteral ( num_str) => num_str
245
+ . parse :: < usize > ( )
246
+ . map_err ( |_| ParseError :: InvalidIntegerForTupleIndex { span, index : token } ) ,
247
+ _ => Err ( ParseError :: InvalidTupleIndex { span, index : token } ) ,
248
+ } ) ;
249
+
250
+ parser
251
+ . then ( just ( Token :: Dot ) . ignore_then ( index) . repeated ( ) )
252
+ . foldl ( |expr, index| ast:: Expr :: TupleIndex {
253
+ tuple : Box :: new ( expr) ,
254
+ index,
255
+ } )
256
+ }
257
+
232
258
fn multiplicative_op < ' sc , P > (
233
259
parser : P ,
234
260
) -> impl Parser < Token < ' sc > , ast:: Expr , Error = ParseError < ' sc > > + Clone
@@ -321,12 +347,20 @@ fn ident<'sc>() -> impl Parser<Token<'sc>, ast::Ident, Error = ParseError<'sc>>
321
347
}
322
348
323
349
fn type_ < ' sc > ( ) -> impl Parser < Token < ' sc > , ast:: Type , Error = ParseError < ' sc > > + Clone {
324
- choice ( (
325
- just ( Token :: Real ) . to ( ast:: Type :: Real ) ,
326
- just ( Token :: Int ) . to ( ast:: Type :: Int ) ,
327
- just ( Token :: Bool ) . to ( ast:: Type :: Bool ) ,
328
- just ( Token :: String ) . to ( ast:: Type :: String ) ,
329
- ) )
350
+ recursive ( |type_| {
351
+ let tuple = type_
352
+ . separated_by ( just ( Token :: Comma ) )
353
+ . allow_trailing ( )
354
+ . delimited_by ( just ( Token :: ParenOpen ) , just ( Token :: ParenClose ) ) ;
355
+
356
+ choice ( (
357
+ just ( Token :: Real ) . to ( ast:: Type :: Real ) ,
358
+ just ( Token :: Int ) . to ( ast:: Type :: Int ) ,
359
+ just ( Token :: Bool ) . to ( ast:: Type :: Bool ) ,
360
+ just ( Token :: String ) . to ( ast:: Type :: String ) ,
361
+ tuple. map ( ast:: Type :: Tuple ) ,
362
+ ) )
363
+ } )
330
364
}
331
365
332
366
fn immediate < ' sc > ( ) -> impl Parser < Token < ' sc > , ast:: Immediate , Error = ParseError < ' sc > > + Clone {
@@ -373,6 +407,25 @@ fn check(actual: &str, expect: expect_test::Expect) {
373
407
expect. assert_eq ( actual) ;
374
408
}
375
409
410
+ #[ test]
411
+ fn types ( ) {
412
+ check ( & run_parser ! ( type_( ) , "int" ) , expect_test:: expect![ "Int" ] ) ;
413
+ check ( & run_parser ! ( type_( ) , "real" ) , expect_test:: expect![ "Real" ] ) ;
414
+ check ( & run_parser ! ( type_( ) , "bool" ) , expect_test:: expect![ "Bool" ] ) ;
415
+ check (
416
+ & run_parser ! ( type_( ) , "string" ) ,
417
+ expect_test:: expect![ "String" ] ,
418
+ ) ;
419
+ check (
420
+ & run_parser ! ( type_( ) , "(int, real, string)" ) ,
421
+ expect_test:: expect![ "Tuple([Int, Real, String])" ] ,
422
+ ) ;
423
+ check (
424
+ & run_parser ! ( type_( ) , "(int, (real, int), string)" ) ,
425
+ expect_test:: expect![ "Tuple([Int, Tuple([Real, Int]), String])" ] ,
426
+ ) ;
427
+ }
428
+
376
429
#[ test]
377
430
fn let_decls ( ) {
378
431
check (
@@ -839,7 +892,7 @@ fn code_blocks() {
839
892
check (
840
893
& format ! ( "{:?}" , run_parser!( let_decl( expr( ) ) , "let x = {};" ) ) ,
841
894
expect_test:: expect![ [
842
- r#""@9..10: found \"}\" but expected \"!\", \"+\", \"-\", \"{\", \"if\", \"var\", \"let\", or \"constraint\"\n""#
895
+ r#""@9..10: found \"}\" but expected \"!\", \"+\", \"-\", \"{\", \"(\", \" if\", \"var\", \"let\", or \"constraint\"\n""#
843
896
] ] ,
844
897
) ;
845
898
}
@@ -881,6 +934,93 @@ fn if_exprs() {
881
934
) ;
882
935
}
883
936
937
+ #[ test]
938
+ fn tuple_expressions ( ) {
939
+ check (
940
+ & run_parser ! ( expr( ) , r#"(0,)"# ) ,
941
+ expect_test:: expect![ "Tuple([Immediate(Int(0))])" ] ,
942
+ ) ;
943
+
944
+ check (
945
+ & run_parser ! ( expr( ) , r#"(0, 1.0, "foo")"# ) ,
946
+ expect_test:: expect![ [
947
+ r#"Tuple([Immediate(Int(0)), Immediate(Real(1.0)), Immediate(String("foo"))])"#
948
+ ] ] ,
949
+ ) ;
950
+
951
+ check (
952
+ & run_parser ! ( expr( ) , r#"(0, (1.0, "bar"), "foo")"# ) ,
953
+ expect_test:: expect![ [
954
+ r#"Tuple([Immediate(Int(0)), Tuple([Immediate(Real(1.0)), Immediate(String("bar"))]), Immediate(String("foo"))])"#
955
+ ] ] ,
956
+ ) ;
957
+
958
+ check (
959
+ & run_parser ! ( expr( ) , r#"( { 42 }, if cond { 2 } else { 3 }, foo() )"# ) ,
960
+ expect_test:: expect![ [
961
+ r#"Tuple([Block(Block { statements: [], final_expr: Immediate(Int(42)) }), If(IfExpr { condition: Ident(Ident("cond")), then_block: Block { statements: [], final_expr: Immediate(Int(2)) }, else_block: Block { statements: [], final_expr: Immediate(Int(3)) } }), Call { name: Ident("foo"), args: [] }])"#
962
+ ] ] ,
963
+ ) ;
964
+
965
+ check (
966
+ & run_parser ! ( expr( ) , r#"t.0 + t.9999999"# ) ,
967
+ expect_test:: expect![ [
968
+ r#"BinaryOp { op: Add, lhs: TupleIndex { tuple: Ident(Ident("t")), index: 0 }, rhs: TupleIndex { tuple: Ident(Ident("t")), index: 9999999 } }"#
969
+ ] ] ,
970
+ ) ;
971
+
972
+ check (
973
+ & run_parser ! ( expr( ) , r#"(0, 1).0"# ) ,
974
+ expect_test:: expect![
975
+ "TupleIndex { tuple: Tuple([Immediate(Int(0)), Immediate(Int(1))]), index: 0 }"
976
+ ] ,
977
+ ) ;
978
+
979
+ check (
980
+ & run_parser ! ( expr( ) , r#"t.0 .0"# ) ,
981
+ expect_test:: expect![ [
982
+ r#"TupleIndex { tuple: TupleIndex { tuple: Ident(Ident("t")), index: 0 }, index: 0 }"#
983
+ ] ] ,
984
+ ) ;
985
+
986
+ check (
987
+ & run_parser ! ( expr( ) , r#"foo().0"# ) ,
988
+ expect_test:: expect![ [
989
+ r#"TupleIndex { tuple: Call { name: Ident("foo"), args: [] }, index: 0 }"#
990
+ ] ] ,
991
+ ) ;
992
+
993
+ check (
994
+ & run_parser ! ( expr( ) , r#"{ (0, 0) }.0"# ) ,
995
+ expect_test:: expect![ "TupleIndex { tuple: Block(Block { statements: [], final_expr: Tuple([Immediate(Int(0)), Immediate(Int(0))]) }), index: 0 }" ] ,
996
+ ) ;
997
+
998
+ check (
999
+ & run_parser ! ( expr( ) , r#"if true { (0, 0) } else { (0, 0) }.0"# ) ,
1000
+ expect_test:: expect![ "TupleIndex { tuple: If(IfExpr { condition: Immediate(Bool(true)), then_block: Block { statements: [], final_expr: Tuple([Immediate(Int(0)), Immediate(Int(0))]) }, else_block: Block { statements: [], final_expr: Tuple([Immediate(Int(0)), Immediate(Int(0))]) } }), index: 0 }" ] ,
1001
+ ) ;
1002
+
1003
+ // This parses because `1 + 2` is an expression, but it should fail in semantic analysis.
1004
+ check (
1005
+ & run_parser ! ( expr( ) , "1 + 2 .3" ) ,
1006
+ expect_test:: expect![ "BinaryOp { op: Add, lhs: Immediate(Int(1)), rhs: TupleIndex { tuple: Immediate(Int(2)), index: 3 } }" ] ,
1007
+ ) ;
1008
+
1009
+ check (
1010
+ & run_parser ! ( let_decl( expr( ) ) , "let x = t.0xa;" ) ,
1011
+ expect_test:: expect![ [ r#"
1012
+ @10..13: Invalid integer value "0xa" for tuple index
1013
+ "# ] ] ,
1014
+ ) ;
1015
+
1016
+ check (
1017
+ & run_parser ! ( let_decl( expr( ) ) , "let x = t.xx;" ) ,
1018
+ expect_test:: expect![ [ r#"
1019
+ @10..12: Invalid value "xx" for tuple index
1020
+ "# ] ] ,
1021
+ ) ;
1022
+ }
1023
+
884
1024
#[ test]
885
1025
fn basic_program ( ) {
886
1026
let src = r#"
@@ -907,7 +1047,7 @@ fn with_errors() {
907
1047
check (
908
1048
& run_parser ! ( yurt_program( ) , "let low_val: bad = 1.23" ) ,
909
1049
expect_test:: expect![ [ r#"
910
- @13..16: found "bad" but expected "real", "int", "bool", or "string"
1050
+ @13..16: found "bad" but expected "(", " real", "int", "bool", or "string"
911
1051
"# ] ] ,
912
1052
) ;
913
1053
}
@@ -924,7 +1064,7 @@ fn fn_errors() {
924
1064
check (
925
1065
& run_parser ! ( yurt_program( ) , "fn foo() -> real {}" ) ,
926
1066
expect_test:: expect![ [ r#"
927
- @18..19: found "}" but expected "!", "+", "-", "{", "if", "var", "let", or "constraint"
1067
+ @18..19: found "}" but expected "!", "+", "-", "{", "(", " if", "var", "let", or "constraint"
928
1068
"# ] ] ,
929
1069
) ;
930
1070
}
0 commit comments