scilla-parser 2.0.0

Scilla smart contract parser written in Rust
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
use crate::ast::nodes::*;
use crate::parser::lexer;

grammar<'err, 'input>(errors: &'err mut Vec<lexer::ParseError>);



extern {
    type Location = lexer::SourcePosition;
    type Error = lexer::ParseError;

    enum lexer::Token<&'input str> {
        "+" => lexer::Token::Plus,
        "*" => lexer::Token::Asterisk,
        ";" => lexer::Token::Semicolon,
        ":" => lexer::Token::Colon,
        "." => lexer::Token::Dot,
        "|" => lexer::Token::Pipe,
        "[" => lexer::Token::OpenBracket,
        "]" => lexer::Token::CloseBracket,
        "(" => lexer::Token::OpenParen,
        ")" => lexer::Token::CloseParen,
        "{" => lexer::Token::OpenBrace,
        "}" => lexer::Token::CloseBrace,
        "," => lexer::Token::Comma,
        "=>" => lexer::Token::DoubleArrow,
        "->" => lexer::Token::Arrow,
        "=" => lexer::Token::Equals,
        "&" => lexer::Token::Ampersand,
        "<-" => lexer::Token::LeftArrow,
        ":=" => lexer::Token::ColonEquals,
        "@" => lexer::Token::At,
        "-" => lexer::Token::Minus,
        "_" => lexer::Token::Underscore,
        "forall" => lexer::Token::Forall,
        "builtin" => lexer::Token::Builtin,
        "library" => lexer::Token::Library,
        "import" => lexer::Token::Import,
        "let" => lexer::Token::Let,
        "in" => lexer::Token::In,
        "match" => lexer::Token::Match,
        "with" => lexer::Token::With,
        "end" => lexer::Token::End,
        "fun" => lexer::Token::Fun,
        "tfun" => lexer::Token::Tfun,
        "contract" => lexer::Token::Contract,
        "transition" => lexer::Token::Transition,
        "send" => lexer::Token::Send,
        "event" => lexer::Token::Event,
        "Event" => lexer::Token::EventType,
        "field" => lexer::Token::Field,
        "accept" => lexer::Token::Accept,
        "exists" => lexer::Token::Exists,
        "delete" => lexer::Token::Delete,
        "throw" => lexer::Token::Throw,
        "Map" => lexer::Token::Map,
        "scilla_version" => lexer::Token::ScillaVersion,
        "type" => lexer::Token::Type,
        "of" => lexer::Token::Of,
        "as" => lexer::Token::As,
        "procedure" => lexer::Token::Procedure,
        "Emp" => lexer::Token::Emp,
        "ByStr" => lexer::Token::ByStr,

        r"ByStr[0-9]+" => lexer::Token::ByStrWithSize(<&'input str>), 
        
        r"[+-]?[0-9]+" => lexer::Token::Number(<&'input str>), 
        r"0(x|X)([a-fA-F0-9][a-fA-F0-9])*" => lexer::Token::HexNumber(<&'input str>), 
        r#""(?:\\.|[^"])*""# => lexer::Token::StringLiteral(<&'input str>), 

        r"[a-z][a-zA-Z0-9_]*" => lexer::Token::Identifier(<&'input str>), 
        r"[_][a-zA-Z0-9_]*" => lexer::Token::SpecialIdentifier(<&'input str>), 
        r"[A-Z][a-zA-Z0-9_]*" => lexer::Token::CustomIdentifier(<&'input str>), 
        r"['][A-Z][a-zA-Z0-9_]*" => lexer::Token::TemplateIdentifier(<&'input str>), 
    }
}




// The rule that defines a byte string type in Scilla.
// A byte string type in Scilla is a built-in type that represents a sequence of bytes.
// The `BYSTR` keyword is used to define a byte string type in Scilla.
//
// <typeByteStr> ::= "ByStr" <digit>+
//
// This rule allows for byte string types to be defined in a Scilla contract.
//
// @syntax typeByteStr
// @return A byte string type in Scilla.
pub ByteString : NodeByteStr = {
	<start:@L> <node:r"ByStr[0-9]+"> <end:@R> => NodeByteStr::Type(WithMetaData::<String> {
        node: String::from(node),
        start,
        end
    }),

}



// The rule that defines an identifier type name in Scilla.
// An identifier type name is a custom type name, a byte string type name, or an event type name.
// An identifier type name consists of the following components:
//
// TODO: Missing BNF
//
// This rule allows for identifier type names to be defined in a Scilla contract.
//
// @syntax identifierTypeName
// @return An identifier type name as a custom type name, a byte string type name, or an event type name.
pub TypeNameIdentifier: WithMetaData<NodeTypeNameIdentifier> = {
	<start:@L> <node:ByteString> <end:@R> => WithMetaData::<NodeTypeNameIdentifier> { 
        node: NodeTypeNameIdentifier::ByteStringType(node),  
        start,
        end
    },
    <start:@L> "Event" <end:@R> => WithMetaData::<NodeTypeNameIdentifier> { 
        node: NodeTypeNameIdentifier::EventType,  
        start,
        end
    },
    <start:@L> <node:TypeOrEnumLikeIdentifierId> <end:@R> => WithMetaData::<NodeTypeNameIdentifier> { 
        node: NodeTypeNameIdentifier::TypeOrEnumLikeIdentifier(node),	
        start,
        end
    }
}


// The rule that defines a single Scilla import name.
// An imported name allows a Scilla program to use a type or function defined in another Scilla program.
// An imported name can be a regular name or an alias for a name.
// An imported name consists of the following components:
//
// <importedName> ::= (<identifierTypeName> | 'ByStr' <digit>+ | 'Event') ['as' (<identifierTypeName> | 'ByStr' <digit>+ | 'Event')]
//
// This rule allows for a single imported name to be specified with an optional alias.
//
// @syntax importedName
// @return A single imported name with an optional alias.
pub ImportedName: WithMetaData<NodeImportedName> = {
	<start:@L> <node:TypeNameIdentifier> <end:@R> => WithMetaData::<NodeImportedName> {
        node: NodeImportedName::RegularImport(node),
        start,
        end
    },
	<start:@L> <n:TypeNameIdentifier> "as" <v:TypeNameIdentifier> <end:@R> => 
        WithMetaData::<NodeImportedName> {
            node: NodeImportedName::AliasedImport(n,v),
            start,
            end
        }
}


//
// The rule that defines Scilla import declarations.
// An import declaration allows a Scilla program to use types and functions defined in other Scilla programs.
// This rule follows following grammar:
//
// <importDeclarations> ::= 'import' <importedName>+
//
// The rule allows for multiple imported names to be specified in a single import declaration.
//
// @syntax importDeclarations
// @return A list of one or more imported names.
//
pub ImportDeclarations: WithMetaData<NodeImportDeclarations> = {
	<prev:ImportDeclarations>
	<start:@L> "import" <n:ImportedName> <end:@R> => 
        WithMetaData::<NodeImportDeclarations> {
            node: {
    		let mut ret = NodeImportDeclarations {
    			import_list: prev.node.import_list.clone()
    		};
    		ret.import_list.push(n);
    		ret
    	},
        start,
        end
    },
	<start:@L> "import" <n:ImportedName+> <end:@R>  => WithMetaData::<NodeImportDeclarations> {
        node: NodeImportDeclarations {
    		import_list: n
	   },
       start,
       end
    }
}


// The rule that defines a meta identifier in Scilla.
// A meta identifier is an identifier in a Scilla contract that can be in a namespace or a hexspace.
// A meta identifier consists of the following components:
//
// <metaIdentifier> ::= <identifierRegular> ['.' <identifierRegular>]
//                    | <hex> '.' <identifierRegular> 
//                    | 'ByStr'<digit>+
// <identifierRegular> ::= <upperCaseCharacter><alphaNumericUnderscore>* | 'ByStr'<digit>+ | 'Event'
// TODO: Transalate regex
// <hex> ::= [0][x]([a-fA-F0-9] [a-fA-F0-9])*
//
// This rule allows for meta identifiers to be defined in a Scilla contract.
//
// @syntax metaIdentifier
// @return A meta identifier as a Scilla identifier name in a namespace or a hexspace, or a ByStr value.

pub MetaIdentifier : WithMetaData<NodeMetaIdentifier> = {
	<start:@L> <node:TypeNameIdentifier> <end:@R> => WithMetaData::<NodeMetaIdentifier> {
        node: NodeMetaIdentifier::MetaName(node),
        start,
        end
    },
	<start:@L> <l:TypeNameIdentifier> "." <r:TypeNameIdentifier> <end:@R> => WithMetaData::<NodeMetaIdentifier> {
        node: NodeMetaIdentifier::MetaNameInNamespace(l,r),
        start,
        end
    },
	<start:@L> <l:HexNumber> "." <r:TypeNameIdentifier> <end:@R> => WithMetaData::<NodeMetaIdentifier> {
        node: NodeMetaIdentifier::MetaNameInHexspace(l,r),
        start,
        end
    },
	<start:@L> "ByStr" <end:@R> => WithMetaData::<NodeMetaIdentifier> {
        node:  NodeMetaIdentifier::ByteString,
        start,
        end
    },
}



// The rule that defines a variable identifier in Scilla.
// A variable identifier is an identifier used to name variables in a Scilla contract.
// A variable identifier consists of the following components:
//
// <variableIdentifier> ::= <identiferRegular>
//                       | <identiferSpecial> 
//                       | (<typeTypeOrEnumLikeIdentifierName> | 'ByStr' <digit>+ | 'Event') '.' <identiferRegular>
// <identiferRegular> ::= <lowerCaseCharacterOrUnderscore><alphaNumericUnderscore>* 
// <identiferSpecial> ::= "_" <alphaNumericUnderscore>*
// <typeTypeOrEnumLikeIdentifierName> ::= <upperCaseCharacter><alphaNumericUnderscore>*
//
// This rule allows for variable identifiers to be defined in a Scilla contract.
//
// @syntax variableIdentifier
// @return A variable identifier as an identifier name with an optional namespace.
pub VariableIdentifier : WithMetaData<NodeVariableIdentifier> = {
	<start:@L> <node:RegularId> <end:@R> => WithMetaData::<NodeVariableIdentifier> { 
        node: NodeVariableIdentifier::VariableName(node),
        start,
        end
    },
	<start:@L> <node:SpecialId> <end:@R> => WithMetaData::<NodeVariableIdentifier> { 
        node:  NodeVariableIdentifier::SpecialIdentifier(node),
        start,
        end
    },

	<start:@L> <n:TypeNameIdentifier> "." <r:RegularId>  <end:@R> => WithMetaData::<NodeVariableIdentifier> { 
        node: NodeVariableIdentifier::VariableInNamespace(n,r),
        start,
        end
    },
}


// The rule that defines the arguments for a built-in function in Scilla.
// Built-in functions in Scilla can have either variable arguments or no arguments at all.
// This rule defines the arguments for a built-in function and consists of the following components:
//
// <builtinArguments> ::= <variableIdentifier>+  
//                    | '(' ')'  
//
// This rule allows for built-in functions to be defined with variable arguments or no arguments at all.
//
// @syntax builtinArguments
// @return The arguments for a built-in function as either variable identifiers or an empty set of parentheses. 
pub BuiltinArguments: WithMetaData<NodeBuiltinArguments> = {
	<start:@L> <prev:BuiltinArguments>
	<n:VariableIdentifier> <end:@R> => 
    WithMetaData::<NodeBuiltinArguments> {
        node: {
    		let mut ret = NodeBuiltinArguments {
    			arguments: prev.node.arguments.clone()
    		};
    		ret.arguments.push(n);
    		ret
    	},
        start,
        end
    },
	<start:@L> <n:VariableIdentifier> <end:@R> =>     WithMetaData::<NodeBuiltinArguments> {
        node: NodeBuiltinArguments {
    		arguments: vec![n]
	    },
        start,
        end
    },
    <start:@L> "(" ")" <end:@R> =>
        WithMetaData::<NodeBuiltinArguments> { 
        node: NodeBuiltinArguments {
     		arguments: vec![]
	    },
        start,
        end
    }
}

pub RemainingTypes: WithMetaData<NodeScillaType> = {
    <start:@L> <meta_identifier: MetaIdentifier> <arguments: TypeArgument*> <end:@R> => WithMetaData::<NodeScillaType> { 
        node:  NodeScillaType::GenericTypeWithArgs(meta_identifier, arguments),
        start,
        end
    },
    <start:@L> "Map" <key_type: TypeMapKey> <value_type: TypeMapValue> <end:@R> => WithMetaData::<NodeScillaType> { 
        node:  NodeScillaType::MapType(key_type, value_type),
        start,
        end
    },
    <start:@L> "(" <type_name: ScillaType> ")" <end:@R> => WithMetaData::<NodeScillaType> { 
        node:  NodeScillaType::EnclosedType(Box::new(type_name)),
        start,
        end
    },
    <start:@L> <address_type: AddressType> <end:@R> => WithMetaData::<NodeScillaType> { 
        node:  NodeScillaType::ScillaAddresseType(Box::new(address_type)),
        start,
        end
    },
    <start:@L> "forall" <template_variable: TemplateTypeId> "." <type_name: RemainingTypes> <end:@R> => WithMetaData::<NodeScillaType> { 
        node:  NodeScillaType::PolyFunctionType(template_variable, Box::new(type_name)),
        start,
        end
    },
    <start:@L> <template_variable: TemplateTypeId> <end:@R> => WithMetaData::<NodeScillaType> { 
        node:  NodeScillaType::TypeVarType(template_variable),
        start,
        end
    }	
}

pub FunctionSignature: WithMetaData<NodeScillaType> = {
	<start:@L> <from_type: RemainingTypes> "->" <to_type: FunctionSignature> <end:@R> => WithMetaData::<NodeScillaType> {
        node: NodeScillaType::FunctionType(Box::new(from_type), Box::new(to_type)),
        start,
        end
    },
	<start:@L> <from_type: RemainingTypes> "->" <to_type: RemainingTypes> <end:@R> => WithMetaData::<NodeScillaType> {
        node:  NodeScillaType::FunctionType(Box::new(from_type), Box::new(to_type)),
        start,
        end
    },
}


// The rule that defines a Scilla type.
// A Scilla type is the data type of a Scilla expression or identifier.
// A Scilla type consists of the following components:
//
// <scillaType> ::= <metaIdentifier> <typeArgument>* 
//                 | 'Map' <typeMapKey> <typeMapValue> 
//                 | <scillaType> '->' <scillaType> 
//                 | '(' <scillaType> ')' 
//                 | <addressType> 
//                 | 'forall' <templateTypeIdentifier> '.' <scillaType> 
//                 | <templateTypeIdentifier>
// <templateTypeIdentifier> ::= "'" <upperCaseCharacter> <alphaNumericUnderscore>*;
//
// This rule allows for Scilla types to be specified as a type identifier or keyword with optional type arguments, key type and value type, source type and target type, enclosed type, address type, or type variable.
//
// @syntax scillaType
// @return A Scilla type as a type identifier or keyword with optional type arguments, key type and value type, source type and target type, enclosed type, address type, or type variable.
pub ScillaType: WithMetaData<NodeScillaType> = {	
	 <f:FunctionSignature> => f,
	 <x:RemainingTypes> => x	 
}



// The rule that defines a Scilla type argument.
// A Scilla type argument is a type that can be passed as an argument to a Scilla function.
// A Scilla type argument consists of the following components:
//
// <typeArgument> ::= '(' <scillaType> ')'
//                  | <metaIdentifier>
//                  | "'" <upperCaseCharacter> <alphaNumericUnderscore>*
//                  | <addressType>
//                  | 'Map' <typeMapKey> <typeMapValue>
// 
//
// This rule allows for Scilla type arguments to be specified as a Scilla type name, meta identifier, template type identifier, address type or map type.
//
// @syntax typeArgument
// @return A Scilla type argument as a Scilla type name, meta identifier, template type identifier, address type or map type.
pub TypeArgument: WithMetaData<NodeTypeArgument> = {
    <start:@L> "(" <t:ScillaType> ")" <end:@R> =>
    WithMetaData::<NodeTypeArgument> {
        node: NodeTypeArgument::EnclosedTypeArgument(Box::new(t)),
        start,
        end
    },
    <start:@L> <i:MetaIdentifier> <end:@R> =>
    WithMetaData::<NodeTypeArgument> {
        node: NodeTypeArgument::GenericTypeArgument(i),
        start,
        end
    },
    <start:@L> <t:TemplateTypeId> <end:@R> =>
    WithMetaData::<NodeTypeArgument> {
        node: NodeTypeArgument::TemplateTypeArgument(t),
        start,
        end
    },
    <start:@L> <a:AddressType> <end:@R> =>
    WithMetaData::<NodeTypeArgument> {
        node: NodeTypeArgument::AddressTypeArgument(a),
        start,
        end
    },
    <start:@L> "Map" <k:TypeMapKey> <v:TypeMapValue> <end:@R> =>
    WithMetaData::<NodeTypeArgument> {
        node: NodeTypeArgument::MapTypeArgument(k, v),
        start,
        end
    },
}



// The rule that defines a Scilla address type.
// A Scilla address type is a type that represents an address on the blockchain.
// A Scilla address type consists of the following components:
//
// <addressType> ::= <baseAddressType> "with" ("end" | "contract" [<addressTypeField> {"," <addressTypeField>}*] "end" | "library" "end" | <specialIdentifier> "end") ["contract" [<addressTypeField> {"," <addressTypeField>}*] | "library" | <specialIdentifier>] "end" 
// <baseAddressType> ::= <upperCaseCharacter> <alphaNumericUnderscore>* | "ByStr" <digit>+ | "Event"
// <specialIdentifier> ::= "_" <alphaNumericUnderscore>*
// <addressTypeField> ::= <identifierRegular> ":" <scillaType>
//
// This rule allows for Scilla address types to be specified with different components and options.
// Scilla address types can be defined as an address with no additional fields, an address with contract fields, an address with library fields, or an address with code fields.
//
// @syntax addressType
// @return A Scilla address type.
pub AddressType: WithMetaData<NodeAddressType> = {
	<start:@L> <type_name: TypeNameIdentifier> "with" "end" <end:@R> => WithMetaData::<NodeAddressType> { 
        node: NodeAddressType {
            identifier: type_name,
            type_name: WithMetaData::<String> {
                node: "".to_string(),
                start: start.clone(),
                end: end.clone(),
            },
            address_fields: vec![]
        },
        start,
        end
    },
	<start:@L> <type_name: TypeNameIdentifier> "with"  "contract" <address_fields: AddressTypeFieldList?> "end" <end:@R> => 
    WithMetaData::<NodeAddressType> { 
        node: NodeAddressType {
            identifier: type_name,
            type_name: WithMetaData::<String> {
                node: "contract".to_string(),
                start: start.clone(),
                end: end.clone()
            },
            address_fields: address_fields.unwrap_or([].to_vec())
        },
        start,
        end
    },
	<start:@L> <type_name: TypeNameIdentifier> "with" "library" "end" <end:@R> => 
    WithMetaData::<NodeAddressType> { 
        node: NodeAddressType {
            identifier: type_name,
            type_name:  WithMetaData::<String> {
                node: "library".to_string(),
                start: start.clone(),
                end: end.clone()
            },
            address_fields: vec![]
        },
        start,
        end
    },
	<start:@L> <type_name: TypeNameIdentifier> "with" <special_identifier:SpecialId> "end" <end:@R> => 
    WithMetaData::<NodeAddressType> { 
        node: NodeAddressType {
            identifier: type_name,
            type_name: special_identifier,
            address_fields: vec![]
        },
        start,
        end
    }
};


// The rule that defines an address type field in Scilla.
// An address type field is a field in a Scilla contract that has an address type and an identifier name.
// An address type field consists of the following components:
//
// <addressTypeField> ::= "field" <identifierRegular> ":" <scillaType>
// <identifierRegular> ::= <lowerCaseCharacterOrUnderscore> <alphaNumericUnderscore>*
//
// This rule allows for address type fields to be defined in a Scilla contract.
//
// @syntax addressTypeField
// @return An address type field as an identifier name with a Scilla address type.
pub AddressTypeFieldList: Vec<WithMetaData<NodeAddressTypeField>> = {
	<first:AddressTypeField> <remaining:NextAddressTypeField*> =>
	{
		let mut ret: Vec<WithMetaData<NodeAddressTypeField>> = [first].to_vec();
		for x in remaining {
			ret.push(x);
		}
		ret
	}
}

pub NextAddressTypeField: WithMetaData<NodeAddressTypeField> = {
	"," <a:AddressTypeField> => a
}

pub AddressTypeField: WithMetaData<NodeAddressTypeField> = {
    <start:@L> "field" <identier_value:VariableIdentifier> ":" <type_name:ScillaType> <end:@R> => {
        WithMetaData::<NodeAddressTypeField> {
            node: NodeAddressTypeField { 
                identifier: identier_value, 
                type_name: type_name
            },
            start,
            end
        }
    }
}



// The rule that defines a Scilla map key type.
// A Scilla map key type is a type that can be used as the key in a Scilla map.
// A Scilla map key type consists of the following components:
//
// <typeMapKey> ::= <metaIdentifier>
//                 | '(' <metaIdentifier> ')'
//                 | '(' <addressType> ')'
//                 | <addressType>
// 
//
// This rule allows for Scilla map key types to be specified as a meta identifier or an address type.
//
// @syntax typeMapKey
// @return A Scilla map key type as a meta identifier or an address type.
pub TypeMapKey: WithMetaData<NodeTypeMapKey> = {
    <start:@L> <identifier_name: MetaIdentifier> <end:@R> =>
    WithMetaData::<NodeTypeMapKey> {
        node: NodeTypeMapKey::GenericMapKey(identifier_name),
        start,
        end
    },
    <start:@L> "(" <identifier_name: MetaIdentifier> ")" <end:@R> =>
    WithMetaData::<NodeTypeMapKey> {
        node: NodeTypeMapKey::EnclosedGenericId(identifier_name),
        start,
        end
    },
    <start:@L> "(" <identifier_name: AddressType> ")" <end:@R> =>
    WithMetaData::<NodeTypeMapKey> {
        node: NodeTypeMapKey::EnclosedAddressMapKeyType(identifier_name),
        start,
        end
    },
    <start:@L> <identifier_name: AddressType> <end:@R> =>
    WithMetaData::<NodeTypeMapKey> {
        node: NodeTypeMapKey::AddressMapKeyType(identifier_name),
        start,
        end
    },
};



// The rule that defines a Scilla map value type.
// A Scilla map value type is a type that can be used as the value in a Scilla map.
// A Scilla map value type consists of the following components:
//
// <typeMapValue> ::= <metaIdentifier>
//                  | "Map" <typeMapKey> <typeMapValue>
//                  | "(" <typeMapValueAllowingTypeArguments> ")"
//                  | <addressType>
//
// This rule allows for Scilla map value types to be specified as a custom type identifier or an address type.
// Additionally, it allows for the specification of a key and value type for the map value type.
// The rule also allows for a type that is allowed as a map value to be used in parentheses.
//
// @syntax typeMapValue
// @return A Scilla map value type as a custom type identifier, an address type, a map key and value type, or a type allowed as a map value and used in parentheses.
pub TypeMapValue:  WithMetaData<NodeTypeMapValue> = {
    <start:@L> <n:MetaIdentifier> <end:@R> =>  WithMetaData::<NodeTypeMapValue> {
        node: NodeTypeMapValue::MapValueTypeOrEnumLikeIdentifier(n),
        start,
        end
    },
    <start:@L> "Map" <k:TypeMapKey> <v:TypeMapValue> <end:@R> =>  WithMetaData::<NodeTypeMapValue> {
        node: NodeTypeMapValue::MapKeyValue(Box::new(
            WithMetaData::<NodeTypeMapEntry> {
                node: NodeTypeMapEntry { key:    k, value: v },
                start: start.clone(),
                end: end.clone()
            }
        )),
        start,
    end
    },
    <start:@L> "(" <t:TypeMapValueAllowingTypeArguments> ")" <end:@R> =>  WithMetaData::<NodeTypeMapValue> {
        node: NodeTypeMapValue::MapValueParenthesizedType(Box::new(t)),
        start,
        end
    },
    <start:@L> <t:AddressType> <end:@R> =>  WithMetaData::<NodeTypeMapValue> {
        node: NodeTypeMapValue::MapValueAddressType(Box::new(t)),
        start,
        end
    },
}



// The rule that defines arguments for a Scilla map value type.
// A Scilla map value type is a type that can be used as the value in a Scilla map.
// A Scilla map value type consists of the following components:
//
// <typeMapValueArguments> ::= '(' <typeMapValueAllowingTypeArguments> ')'  
//                            | <metaIdentifier>
//                            | 'Map' <typeMapKey> <typeMapValue>  
// 
//
// This rule allows for Scilla map value types to be specified with type arguments, as a meta identifier,
// or as a map type with a key type and a value type. The rule returns the specified Scilla map value type.
//
// @syntax typeMapValueArguments
// @return A Scilla map value type with optional type arguments, as a meta identifier, or as a map type.
pub TypeMapValueArguments: WithMetaData<NodeTypeMapValueArguments> = {
    <start:@L> "(" <type_map_value:TypeMapValueAllowingTypeArguments> ")" <end:@R> => 
    WithMetaData::<NodeTypeMapValueArguments> {
        node: NodeTypeMapValueArguments::EnclosedTypeMapValue(Box::new(type_map_value)),
        start,
        end
    },
    <start:@L> <identifier_name:MetaIdentifier> <end:@R> => WithMetaData::<NodeTypeMapValueArguments> { 
        node: NodeTypeMapValueArguments::GenericMapValueArgument(identifier_name),
        start,
        end
    },
    <start:@L> "Map" <key_type:TypeMapKey> <value_type:TypeMapValue> <end:@R> => WithMetaData::<NodeTypeMapValueArguments> {
        node: NodeTypeMapValueArguments::MapKeyValueType(key_type, value_type),
        start,
        end
    }
}





// The top-level rule that defines a Scilla program.
// A Scilla program is defined by following grammar:
//              
// <program> ::= 'scilla_version' <digit>+ [<importDeclarations>] 
//               [<libraryDefinition>] <contractDefinition> EOF
//
// 
// This rule is the starting point for parsing a Scilla program.
//
// @syntax program
// @return A Scilla program consisting of a version number, optional import declarations, optional library definition, and a contract definition.

pub Program: NodeProgram = {
    "scilla_version" <version:SignedInteger>
    <import_declarations:ImportDeclarations?>
    <library_definition:LibraryDefinition?>
    <contract_definition:ContractDefinition> => NodeProgram {
        version, import_declarations, library_definition, contract_definition
    }
}



// The rule that defines a Scilla library definition.
// A library definition allows a Scilla program to define reusable code components that can be shared among multiple contracts.
// A library definition consists of the following components:
//
// <libraryDefinition> ::= 'library' <libraryName> <librarySingleDefinition>*
// <libraryName> ::= <upperCaseCharacter><alphaNumericUnderscore>* | 'ByStr'<digit>+ | 'Event'
//
//
// This rule allows for multiple library definitions to be specified within a single library definition.
//
// @syntax libraryDefinition
// @return A Scilla library definition with a library name and zero or more library definitions. 
pub LibraryDefinition: WithMetaData<NodeLibraryDefinition> = {
    <start:@L> "library" 
    <l:TypeNameIdentifier>
    <d:LibrarySingleDefinition*> <end:@R> => WithMetaData::<NodeLibraryDefinition> {
        node: NodeLibraryDefinition {
            name: l,
            definitions: d
        },
        start,
        end
    },
}



// The rule that defines a single Scilla library definition.
// A library definition allows a Scilla program to define reusable code components that can be shared among multiple contracts.
// A single library definition can be a constant definition, a type definition, or a type variation definition.
// A library definition consists of the following components:
//
// <librarySingleDefinition> ::= 'let' <variableName> [':' <typeName>] '=' <expression>
//                             | 'type' <typeName>
//                             | 'type' <typeName> '=' <typeAlternativeClause>+
//  
// <variableName> ::= [a-z]<alphaNumericUnderscore>*
// <typeName> ::= <identifierRegular>
// 
//
// This rule allows for a single library definition to be specified with optional type annotation, expression, or type variations.
//
// @syntax librarySingleDefinition
// @return A single Scilla library definition with a name, optional type annotation, optional expression, and optional type variations.
pub LibrarySingleDefinition: WithMetaData<NodeLibrarySingleDefinition> = {
	<start:@L> "let" <variable_name: RegularId>
	 <type_annotation: TypeAnnotation?> 
	 "=" <expression: FullExpression> <end:@R> => WithMetaData::<NodeLibrarySingleDefinition> { 
        node:       NodeLibrarySingleDefinition::LetDefinition {
            variable_name: variable_name,
            type_annotation: type_annotation,
            expression: expression.into()
        },
        start,
        end
    },
	<start:@L> "type" <type_name: TypeNameIdentifier> <end:@R> => WithMetaData::<NodeLibrarySingleDefinition> { 
        node: NodeLibrarySingleDefinition::TypeDefinition(type_name, None),
        start,
        end
    },
	<start:@L>  "type" <type_name: TypeNameIdentifier> "=" <variations:TypeAlternativeClause+> <end:@R> => WithMetaData::<NodeLibrarySingleDefinition> { 
        node: NodeLibrarySingleDefinition::TypeDefinition(type_name, Some(variations)),
        start,
        end
    }

    // TODO: Langauge extension for review
    // // Struct
    // "type" <type_name: TypeNameIdentifier> '=' '{' 
    //     <p:ParameterPair?> <next_params:NextParameterPair*>
    // '}' => {
    //        let mut parameters: Vec<NodeParameterPair> = Vec::new();
    //        if let Some(pair) = p {
    //             parameters.push(pair);
    //        }
    //        
    //        for p in next_params {
    //            parameters.push(p);
    //        }
    //        
    //        NodeLibrarySingleDefinition::StructDefinition(type_name, parameters) 
    //     }    
    // }


    // "type" <type_name: TypeNameIdentifier> <template_args:> => NodeLibrarySingleDefinition::TypeDefinition(type_name, None),
    // "type" <type_name: TypeNameIdentifier> "=" <variations:TypeAlternativeClause+> => NodeLibrarySingleDefinition::TypeDefinition(type_name, Some(variations))    
}



// The rule that defines a typed identifier in Scilla.
// A typed identifier is an identifier that has an associated Scilla type annotation.
// A typed identifier consists of the following components:
//
// <typedIdentifier> ::= <identifierRegular> <typeAnnotation>
// <identifierRegular> ::= <lowerCaseCharacterOrUnderscore> <alphaNumericUnderscore>*
//
// This rule allows for typed identifiers to be defined in a Scilla program.
//
// @syntax typedIdentifier
// @return A typed identifier as an identifier name with an associated Scilla type annotation.
pub TypedIdentifier: WithMetaData<NodeTypedIdentifier> = {
    <start:@L> <identifier_name: RegularId>
    <annotation: TypeAnnotation> <end:@R>
    => WithMetaData::<NodeTypedIdentifier> {
        node: NodeTypedIdentifier {identifier_name, annotation },
        start,
        end
    }
};


// The rule that defines a type annotation in Scilla.
// A type annotation is a Scilla type that is assigned to a variable or field to indicate the type of data it holds.
// A type annotation consists of the following components:
//
// <typeAnnotation> ::= ':' <scillaType>
//
// This rule allows for type annotations to be added to variables or fields in a Scilla contract.
//
// @syntax typeAnnotation
// @return A Scilla type as a type annotation for a variable or field.
pub TypeAnnotation: WithMetaData< NodeTypeAnnotation> = {
<start:@L> ":" <type_name:ScillaType> <end:@R> => 
    WithMetaData::<NodeTypeAnnotation> {
        node: NodeTypeAnnotation {type_name: type_name },
        start,
        end
    }
}


// The rule that defines a Scilla type alternative clause.
// A type alternative clause defines an alternative type for a type definition.
// A type alternative clause consists of the following components:
//
// <typeAlternativeClause> ::= 
//       '|' <typeClauseExpression> ['of' <typeArgument>+]
// <typeClauseExpression> ::= <identifierTypeName> | <typeByteStr> | <typeEvent>
//
// This rule allows for a single type alternative clause to be specified with optional type arguments.
//
// @syntax typeAlternativeClause
// @return A Scilla type alternative clause with a type name and optional type arguments.
pub TypeAlternativeClause: WithMetaData<NodeTypeAlternativeClause> = {
	<start:@L> "|" <n:TypeNameIdentifier> <end:@R> => WithMetaData::<NodeTypeAlternativeClause> { 
        node: NodeTypeAlternativeClause::ClauseType(n),
        start,
        end
    },
	<start:@L> "|" <n:TypeNameIdentifier> "of" <t:TypeArgument+> <end:@R>  => WithMetaData::<NodeTypeAlternativeClause> {
		node: NodeTypeAlternativeClause::ClauseTypeWithArgs(n, t),
        start,
        end
	}
}





// The rule that defines a Scilla map value type that allows for type arguments.
// A Scilla map value type is a type that can be used as the value in a Scilla map.
// A Scilla map value type can allow for type arguments to be passed to it.
// A Scilla map value type with type arguments consists of the following components:
//
// <typeMapValueAllowingTypeArguments> ::= <metaIdentifier> <typeMapValueArguments>+
//                                       | <typeMapValue>
//
// This rule allows for Scilla map value types to be specified with or without type arguments.
//
// @syntax typeMapValueAllowingTypeArguments
// @return A Scilla map value type that allows for type arguments or a Scilla map value type without type arguments.
pub TypeMapValueAllowingTypeArguments: WithMetaData<NodeTypeMapValueAllowingTypeArguments> = {
    <start:@L> <n:MetaIdentifier> <args:TypeMapValueArguments+> <end:@R> => 
    WithMetaData::<NodeTypeMapValueAllowingTypeArguments> {
        node: NodeTypeMapValueAllowingTypeArguments::TypeMapValueWithArgs(n, args),
        start,
        end
    },
    <start:@L> <t:TypeMapValue> <end:@R> => 
    WithMetaData::<NodeTypeMapValueAllowingTypeArguments> {
        node: NodeTypeMapValueAllowingTypeArguments::TypeMapValueNoArgs(t),
        start,
        end
    }
}


// The rule that defines type arguments for a Scilla contract.
// Type arguments are used to specify the types of variables, functions, and expressions in a Scilla contract.
// Type arguments consist of a list of types enclosed in braces.
//
// <contractTypeArguments> ::= '{' <typeArgument>* '}'
//
// @syntax contractTypeArguments
// @return A list of type arguments enclosed in braces. 
pub ContractTypeArguments: WithMetaData<NodeContractTypeArguments> = {
    <start:@L> "{" <type_arguments: TypeArgument*> "}" <end:@R> => 
    WithMetaData::<NodeContractTypeArguments> {
        node: NodeContractTypeArguments{ type_arguments: type_arguments },
        start,
        end
    }
}



// The rule that defines a full expression in Scilla.
// A full expression is an expression in Scilla that can be a local variable declaration, function call, apply expression,
// atomic expression, builtin function call, message entry, pattern match, data constructor call, template function, or type application.
//
// <fullExpression> ::= 'let' <identifierRegular> [<typeAnnotation>] '=' <fullExpression> 'in' <fullExpression>
//                    | 'fun' '(' <identifierRegular> <typeAnnotation> ')' '=>' <fullExpression>
//                    | <variableIdentifier> (<variableIdentifier>)+
//                    | <atomicExpression>
//                    | 'builtin' <identifierRegular> [<contractTypeArguments>] <builtinArguments>
//                    | '{' <messageEntry> (';' <messageEntry>)* '}'
//                    | 'match' <variableIdentifier> 'with' <patternMatchExpressionClause>* 'end'
//                    | <metaIdentifier> [<contractTypeArguments>] <variableIdentifier>*
//                    | 'tfun' '[' <templateType> '=>' <fullExpression>
//                    | '@' <variableIdentifier> <typeArgument>+
// <identifierRegular> ::= <lowerCaseCharacterOrUnderscore> <alphaNumericUnderscore>*
// <templateType> ::= "'" <upperCaseCharacter> <alphaNumericUnderscore>*
// 
//
// @syntax fullExpression
// @return A full expression in Scilla.
pub FullExpression : WithMetaData<NodeFullExpression> = {
	<start:@L> "let" <identifier_name:RegularId> <type_annotation:TypeAnnotation?>
	"=" <expression:FullExpression> "in" <containing_expression:FullExpression>
    <end:@R> => 
        WithMetaData::<NodeFullExpression> { 
            node: NodeFullExpression::LocalVariableDeclaration{
                identifier_name,
                type_annotation,
                expression: Box::new(expression),
                containing_expression: Box::new(containing_expression)
            },
            start,
            end
        },
    <start:@L> "fun" "(" <identier_value:RegularId> <t:TypeAnnotation> ")" "=>" <expression:FullExpression> <end:@R> => 
        WithMetaData::<NodeFullExpression> { 
            node: NodeFullExpression::FunctionDeclaration{
        		identier_value:identier_value,
        		type_annotation: t,
        		expression: Box::new(expression)
             },
             start,
             end
         },
     <start:@L> <function_name:VariableIdentifier> <argument_list:VariableIdentifier+> <end:@R> => 
         WithMetaData::<NodeFullExpression> { 
            node: NodeFullExpression::FunctionCall{
             	function_name:function_name,
             	argument_list: argument_list
             },
             start,
             end
         },
     <start:@L> <atomic_expression:AtomicExpression> <end:@R> => 
         WithMetaData::<NodeFullExpression> { 
            node: NodeFullExpression::ExpressionAtomic(
                Box::new(atomic_expression)),
             start,
             end
         },    
    <start:@L> "builtin" <b:RegularId> <targs:ContractTypeArguments?> <xs:BuiltinArguments> <end:@R> => 
        WithMetaData::<NodeFullExpression> { 
            node: NodeFullExpression::ExpressionBuiltin{b:b, targs:targs, xs:xs},
             start,
             end
         },
    <start:@L> "{" <m:MessageEntry> <messages:NextMessageEntry*> "}"<end:@R> => 
        WithMetaData::<NodeFullExpression> { node:  {
                let mut message_entries: Vec<WithMetaData<NodeMessageEntry>> = Vec::new();
                message_entries.push(m);
                for message in messages {
                    message_entries.push(message);
                }
                NodeFullExpression::Message(message_entries)
            },
            start,
            end
        },
    <start:@L> "match" <match_expression:VariableIdentifier> "with" <clauses:PatternMatchExpressionClause+> "end" <end:@R> => 
        WithMetaData::<NodeFullExpression> { 
            node: NodeFullExpression::Match{
        	   match_expression,
        	   clauses
            },
            start,
            end
        },
    <start:@L> <identifier_name:MetaIdentifier> <contract_type_arguments:ContractTypeArguments?>
    <argument_list:VariableIdentifier*> <end:@R> => 
        WithMetaData::<NodeFullExpression> { 
            node: NodeFullExpression::ConstructorCall{ identifier_name, contract_type_arguments, argument_list},
            start,
            end
        },
    <start:@L> "tfun" <identifier_name:TemplateTypeId> "=>" <expression:FullExpression> <end:@R> => 
        WithMetaData::<NodeFullExpression> { 
            node: NodeFullExpression::TemplateFunction{identifier_name, expression: Box::new(expression)},
            start,
            end
        },
    <start:@L> "@" <identifier_name:VariableIdentifier> <type_arguments:TypeArgument+> <end:@R> => 
        WithMetaData::<NodeFullExpression> { 
            node: NodeFullExpression::TApp{identifier_name,type_arguments},
            start,
            end
        }
};



// The rule that defines a pattern match expression clause in Scilla.
// A pattern match expression clause is a clause that allows for pattern matching in a Scilla contract.
// A pattern match expression clause consists of the following components:
//
// <patternMatchExpressionClause> ::= '|' <pattern> '=>' <fullExpression>
//
// This rule allows for pattern match expression clauses to be defined in a Scilla contract.
//
// @syntax patternMatchExpressionClause
// @return A pattern match expression clause as a pattern expression with a corresponding full expression.
pub PatternMatchExpressionClause: WithMetaData<NodePatternMatchExpressionClause> = {
	<start:@L> "|" <p:Pattern> "=>" <e:FullExpression> <end:@R> => WithMetaData::<NodePatternMatchExpressionClause> {
        node: NodePatternMatchExpressionClause { pattern: p, expression: e },
        start,
        end
    }
}


// The rule that defines a pattern in Scilla.
// A pattern is a value or a structure that can be matched against a given expression in Scilla.
// A pattern consists of one of the following:
//
// <pattern> ::= '_' 
//              | <identifierRegular> { <argumentPattern> }*
//              | <metaIdentifier> { <argumentPattern> }*
// <identifierRegular> ::= <lowerCaseCharacterOrUnderscore> <alphaNumericUnderscore>*
// <metaIdentifier> ::= [A-Z_] <alphaNumericUnderscore>*
//
// This rule allows for patterns to be defined in a Scilla contract.
//
// @syntax pattern
// @return A pattern that can be matched against a given expression in Scilla.
pub Pattern: WithMetaData<NodePattern> = {
	<start:@L> "_" <end:@R> => 
    WithMetaData::<NodePattern> {
        node: NodePattern::Wildcard,
        start,
        end
    },
	<start:@L> <identifier_name: RegularId> <end:@R> => 
    WithMetaData::<NodePattern> {
        node: NodePattern::Binder(identifier_name),
        start,
        end
    },
	<start:@L> <meta: MetaIdentifier> <constructor_arguments: ArgumentPattern*> <end:@R> =>
    WithMetaData::<NodePattern> {
        node: 		NodePattern::Constructor(meta, constructor_arguments),
        start,
        end
    },
}



// The rule that defines an argument pattern in Scilla.
// An argument pattern is a pattern used to match arguments in a Scilla function or procedure.
// An argument pattern can consist of a wildcard, a binding identifier, a meta-identifier, or a pattern expression.
// A pattern expression can be used to match more complex argument patterns.
//
// <argumentPattern> ::= '_'                                    
//                     | <lowerCaseCharacterOrUnderscore><alphaNumericUnderscore>*          
//                     | <metaIdentifier>                                        
//                     | '(' <pattern> ')'  
//
// @syntax argumentPattern
// @return An argument pattern as a wildcard, a binding identifier, a meta-identifier, or a pattern expression.
pub ArgumentPattern: WithMetaData<NodeArgumentPattern> = {
    <start:@L> "_" <end:@R> => 
        WithMetaData::<NodeArgumentPattern> {
            node: NodeArgumentPattern::WildcardArgument,
            start,
            end
        },
    <start:@L> <binding_identifier: RegularId> <end:@R> => 
        WithMetaData::<NodeArgumentPattern> {
            node: NodeArgumentPattern::BinderArgument(binding_identifier),
            start,
            end
        },
    <start:@L> <identifier_name: MetaIdentifier> <end:@R> => 
        WithMetaData::<NodeArgumentPattern> {
            node: NodeArgumentPattern::ConstructorArgument(identifier_name),
            start,
            end
        },
    <start:@L> "(" <pattern_expression:Pattern> ")" 
        <end:@R> => 
            WithMetaData::<NodeArgumentPattern> {
                node: NodeArgumentPattern::PatternArgument(Box::new(pattern_expression)),
                start,
                end
            },
}


// The rule that defines a message entry in Scilla.
// A message entry is a key-value pair in a Scilla message that consists of an identifier name and a value.
// A message entry consists of the following components:
//
// <messageEntry> ::= <variableIdentifier> ':' <valueLiteral>
//                  | <variableIdentifier> ':' <variableIdentifier>
//
// This rule allows for message entries to be defined in a Scilla message.
//
// @syntax messageEntry
// @return A message entry as a key-value pair in a Scilla message that consists of an identifier name and a value.
pub NextMessageEntry: WithMetaData<NodeMessageEntry> = {
	 ";" <message:MessageEntry> => message
}

pub MessageEntry: WithMetaData<NodeMessageEntry> = {
    <start:@L> <i:VariableIdentifier> ":" <v:ValueLiteral> <end:@R> => 
    WithMetaData::<NodeMessageEntry> {
        node: NodeMessageEntry::MessageLiteral(i, v),
        start,
        end
    },
    <start:@L> <i:VariableIdentifier> ":" <v:VariableIdentifier> <end:@R> => WithMetaData::<NodeMessageEntry> {
        node: NodeMessageEntry::MessageVariable(i, v),
        start,
        end
    }        
}


// The rule that defines an atomic expression in Scilla.
// An atomic expression is a Scilla expression that is not composed of any other sub-expressions.
// An atomic expression can be a variable identifier or a value literal.
//
// <atomicExpression> ::= <variableIdentifier> | <valueLiteral>
//
// @syntax atomicExpression
// @return A Scilla atomic expression, which can be a variable identifier or a value literal.
pub AtomicExpression: WithMetaData<NodeAtomicExpression> = {
	<start:@L> <variable_identifier:VariableIdentifier> <end:@R> => 
    WithMetaData::<NodeAtomicExpression> {
        node: NodeAtomicExpression::AtomicSid(variable_identifier),
        start,
        end
    },
    <start:@L> <value_literal:ValueLiteral> <end:@R> => 
    WithMetaData::<NodeAtomicExpression> {
        node: NodeAtomicExpression::AtomicLit(value_literal),
        start,
        end
    },
};



// The rule that defines a value literal in Scilla.
// A value literal is a literal representation of a value in Scilla.
// A value literal can be one of the following types:
//
// <valueLiteral> ::=  <identifierToken> <digit>+
//                   | <hex>
//                   | 'True' | 'False'
//                   | <string>
//                   | 'Emp' <typeMapKey> <typeMapValue>
// TODO: Transalate regex
// <hex> ::= [0][x]([a-fA-F0-9] [a-fA-F0-9])*
// <string> ::= '"' ~[\r\n"]* '"'
//
// This rule allows for value literals to be defined in Scilla.
//
// @syntax valueLiteral
// @return A value literal as a signed or unsigned integer, a hexadecimal value, a string, or an empty map.
pub ValueLiteral: WithMetaData<NodeValueLiteral> = {
	<start:@L> <n: TypeNameIdentifier> <v: SignedInteger> <end:@L> => 
    WithMetaData::<NodeValueLiteral> { 
        node: NodeValueLiteral::LiteralInt(n, v),
        start,
        end,
    },
     <start:@L> <node: HexNumber> <end:@R> => 
     WithMetaData::<NodeValueLiteral> { 
        node: NodeValueLiteral::LiteralHex(node),
        start,
        end,
    },
     <start:@L> <s: StringLiteral> <end:@R> => 
     WithMetaData::<NodeValueLiteral> { 
        node: NodeValueLiteral::LiteralString(s),
        start,
        end,
    },
     <start:@L> "Emp" <key_type: TypeMapKey>  <value_type: TypeMapValue> <end:@R> => 
     WithMetaData::<NodeValueLiteral> { 
        node: {
    		NodeValueLiteral::LiteralEmptyMap(key_type, value_type)
    	},
        start,
        end,
    },        
}; 



// The rule that defines a statement in Scilla.
// A statement is an expression that is executed in a Scilla contract.
// A statement consists of one or more components, depending on its type.
// The following are the types of statements in Scilla:
//
// <statement>
//    ::= <identifierRegular> '<-' <variableIdentifier>                                                     
//     | <remoteFetchStatement>
//     | <identifierRegular> ':=' <variableIdentifier>                                                    
//     | <identifierRegular> '=' <fullExpression>
//     | <identifierRegular> '<-' '&' (<typeTypeOrEnumLikeIdentifierName> | <typeByteStr> | <typeEvent>) [<blockchainFetchArguments>]    
//     | <identifierRegular> '<-' <identifierRegular> mapAccess+                    
//     | <identifierRegular> '<-' 'exists' <identifierRegular> mapAccess+     
//     | <identifierRegular> mapAccess+ ':=' <variableIdentifier>                                 
//     | 'delete' <identifierRegular> mapAccess+                                        
//     | 'accept'                                                                                       
//     | 'send' <variableIdentifier>                                                                                   
//     | 'event' <variableIdentifier>                                                                                  
//     | 'throw' [<variableIdentifier>]
//     | 'match' <variableIdentifier> 'with' patternMatchClause+ 'end'                   
//     | <componentId> <variableIdentifier>*                                                           
//     | 'forall' <variableIdentifier> componentId                                                           
// <identifierRegular> ::= <lowerCaseCharacterOrUnderscore><alphaNumericUnderscore>*
//         
// This rule allows for statements to be defined in a Scilla contract.
//
// @syntax statement
// @return A statement as an expression to be executed in a Scilla contract.
pub Statement: NodeStatement = {
	<identifier_name:RegularId> "<-" <right_hand_side:VariableIdentifier> => 
                NodeStatement::Load {
                    left_hand_side: identifier_name,
                    right_hand_side
                },
    <r:RemoteFetchStatement> => NodeStatement::RemoteFetch(Box::new(r)),
   <identifier_name:RegularId> ":=" <right_hand_side:VariableIdentifier> => 
        NodeStatement::Store {
            left_hand_side: identifier_name,
            right_hand_side
        },
    <identifier_name:RegularId> "=" <right_hand_side:FullExpression> => 
        NodeStatement::Bind {
            left_hand_side: identifier_name,
            right_hand_side: Box::new(right_hand_side)
        },

    <identifier_name:RegularId> "<-" "&" <type_name:TypeNameIdentifier> <arguments:BlockchainFetchArguments?> => 
        NodeStatement::ReadFromBC {
            left_hand_side: identifier_name, 
            type_name,
            arguments
        },
    <identifier_name:RegularId> "<-" <right_hand_side:RegularId> <keys:MapAccess+> => 
        NodeStatement::MapGet {
            left_hand_side: identifier_name,
            right_hand_side,
            keys
        },
    <identifier_name:RegularId> "<-" "exists" <right_hand_side:RegularId> <keys:MapAccess+> => 
       NodeStatement::MapGetExists {
           left_hand_side: identifier_name,
           right_hand_side,
           keys
       },
    <identifier_name:RegularId> <keys:MapAccess+> ":=" <right_hand_side:VariableIdentifier> => 
        NodeStatement::MapUpdate {
            left_hand_side: identifier_name,
            keys,
            right_hand_side
        },
   "delete" <identifier_name:RegularId> <keys:MapAccess+> => 
       NodeStatement::MapUpdateDelete {
           left_hand_side: identifier_name,
           keys
       },
   "accept" => NodeStatement::Accept,
   "send" <identifier_name:VariableIdentifier> => NodeStatement::Send {
       identifier_name
   },
    "event" <identifier_name:VariableIdentifier> => NodeStatement::CreateEvnt {
        identifier_name
    },
    "throw" <error_variable:VariableIdentifier?> => NodeStatement::Throw {
        error_variable
    },
    "match" <variable:VariableIdentifier> "with" <clauses:PatternMatchClause+> "end" => NodeStatement::MatchStmt {
        variable,
        clauses
    },
    <component_id:ComponentId> <arguments:VariableIdentifier*> => 
        NodeStatement::CallProc {
            component_id,
            arguments: arguments.to_vec()
        },
    "forall" <identifier_name:VariableIdentifier> <component_id:ComponentId> => 
        NodeStatement::Iterate {
            identifier_name,
            component_id
        }
}

pub NextStatement :  NodeStatement = {
	 ";" <statement:Statement>  => statement
}



// The rule that defines a Scilla statement block.
// A Scilla statement block is a sequence of one or more Scilla statements separated by semicolons.
// A Scilla statement block consists of the following components:
//
// <statementBlock> ::= <statement> ';' <statementBlock>
//                    | <statement>
//
// This rule allows for a Scilla statement block to be specified as a sequence of one or more Scilla statements separated by semicolons.
//
// @syntax statementBlock
// @return A Scilla statement block as a sequence of one or more Scilla statements separated by semicolons.
pub StatementBlock: WithMetaData<NodeStatementBlock> = { 
	<start:@L> <first_statement: Statement> <statement_list:NextStatement*> <end:@R> => 
    WithMetaData::<NodeStatementBlock> {
        node: {
    		let mut statements: Vec<NodeStatement> = [].to_vec();
            statements.push(first_statement);
            for stmt in statement_list {
                statements.push(stmt);
            }
    		NodeStatementBlock {
    			statements
    		}
    	},
        start,
        end
    }
}


// The rule that defines Scilla blockchain fetch arguments.
// Scilla blockchain fetch arguments are the list of variable identifiers that can be passed to a blockchain fetch function.
// Scilla blockchain fetch arguments consists of the following components:
//
// <blockchainFetchArguments> ::= '(' <variableIdentifier>+ ')'
//
// This rule allows for Scilla blockchain fetch arguments to be specified as a list of variable identifiers.
//
// @syntax blockchainFetchArguments
// @return Scilla blockchain fetch arguments as a list of variable identifiers.
pub BlockchainFetchArguments: NodeBlockchainFetchArguments = {
    "(" <arguments:VariableIdentifier+> ")" => NodeBlockchainFetchArguments{ arguments }
}



// The rule that defines a Scilla component ID.
// A Scilla component ID specifies an identifier for a Scilla component.
// A Scilla component ID consists of the following components:
//
// <componentId> ::= <typeName> | <specialId> | <regularId>
// <typeName>    ::= <upperCaseCharacter><alphaNumericUnderscore>*
// <specialId>   ::= 'ByStr'<digit>+ | 'Event'
// <regularId>   ::= <lowerCaseCharacterOrUnderscore><alphaNumericUnderscore>*
//
// This rule allows for a Scilla component ID to be specified with either a type name identifier or a regular identifier.
//
// @syntax componentId
// @return A Scilla component ID with either an identifier with a type name or an identifier with a regular name.
pub ComponentId:  WithMetaData<NodeComponentId> = {
    <start:@L> <identifier:TypeNameIdentifier> <end:@R> => 
    WithMetaData::<NodeComponentId> {
        node: NodeComponentId::WithTypeLikeName(identifier),
        start,
        end
    },
    <start:@L> <identifier:RegularId> <end:@R>  => 
    WithMetaData::<NodeComponentId> {
        node: NodeComponentId::WithRegularId(identifier), 
        start,
        end
    }

}




// The rule that defines a Scilla pattern match clause.
// A Scilla pattern match clause is used to match the patterns of certain values and execute a set of statements accordingly.
// A Scilla pattern match clause consists of the following components:
//
// <patternMatchClause> ::= '|' <pattern> '=>' [<statement> (';' <statement>)*]
//
// This rule allows for a Scilla pattern match clause to be specified with a pattern expression and a set of one or more Scilla statements to be executed if the pattern matches.
//
// @syntax patternMatchClause
// @return A Scilla pattern match clause with a pattern expression and a set of one or more Scilla statements to be executed if the pattern matches.
pub PatternMatchClause: WithMetaData<NodePatternMatchClause> = {
   <start:@L> "|" <pattern_expression:Pattern> "=>" <statement_block:StatementBlock?> <end:@R>
   => 
   WithMetaData::<NodePatternMatchClause> {
        node: NodePatternMatchClause {
           pattern_expression: Box::new(pattern_expression),
           statement_block: statement_block
       },
       start,
       end
   }
}




// The rule that defines a Scilla remote fetch statement.
// A Scilla remote fetch statement is used to fetch data from a remote contract and assign it to a variable.
// A Scilla remote fetch statement consists of the following components:
//
// <remoteFetchStatement> ::= 
//     <identifierRegular> '<-' '&' <identifierRegular> '.' <variableIdentifier> 
//   | <identifierRegular> '<-' '&' <identifierSpecial> '.' <identifierSpecial> 
//   | <identifierRegular> '<-' '&' <identifierRegular> '.' <identifierRegular> <mapAccess>+ 
//   | <identifierRegular> '<-' '&' 'exists' <identifierRegular> '.' <identifierRegular> <mapAccess>+
//   | <identifierRegular> '<-' '&' <variableIdentifier> 'as' <addressType> 
// <identifierRegular> ::= <lowerCaseCharacterOrUnderscore><alphaNumericUnderscore>*
// <identifierSpecial> ::= "_" <alphaNumericUnderscore>*
//
//
// This rule allows for a Scilla remote fetch statement to be specified with different combinations of the above components.
//
// @syntax remoteFetchStatement
// @return A Scilla remote fetch statement with a left-hand side identifier, an address identifier, and optional member or map key access clauses and address type casting.
pub RemoteFetchStatement: NodeRemoteFetchStatement = {
    <left_hand_side:RegularId> "<-" "&"
    <address_id:RegularId> "." <right_hand_side:VariableIdentifier>
    => NodeRemoteFetchStatement::ReadStateMutable(
        left_hand_side,
        address_id,
        right_hand_side
    ),
    <left_hand_side:RegularId> "<-" "&"
    <address_id:SpecialId> "." <right_hand_side:SpecialId>
    => NodeRemoteFetchStatement::ReadStateMutableSpecialId(
        left_hand_side,
        address_id,
        right_hand_side
    ),    
    <left_hand_side:RegularId> "<-" "&"
    <address_id:RegularId> "." <member_id:RegularId>
    <map_accesses:MapAccess+>
    => 
        NodeRemoteFetchStatement::ReadStateMutableMapAccess(
            left_hand_side,
            address_id,
            member_id,
            map_accesses
        )
    ,
    <left_hand_side:RegularId> "<-" "&" "exists"
    <address_id:RegularId> "." <member_id:RegularId>
    <map_accesses:MapAccess+>
    => {
        NodeRemoteFetchStatement::ReadStateMutableMapAccessExists(
            left_hand_side,
            address_id,
            member_id,
            map_accesses
        )
    },
    <left_hand_side:RegularId> "<-" "&"
    <address_id:VariableIdentifier> "as" <address_type:AddressType>
    => NodeRemoteFetchStatement::ReadStateMutableCastAddress(
        left_hand_side,
        address_id,
        address_type
    ),
}


// The rule that defines a map access in Scilla.
// A map access is a way to access a value in a Scilla map using a variable identifier.
// A map access consists of the following components:
//
// <mapAccess> ::= "[" <variableIdentifier> "]"
//
// This rule allows for map access to be performed in a Scilla program.
//
// @syntax mapAccess
// @return A map access as a variable identifier name in a Scilla map.
pub MapAccess: WithMetaData<NodeMapAccess> = {
    <start:@L> "[" <identifier_name:VariableIdentifier> "]" <end:@R> => WithMetaData::<NodeMapAccess> {
        node:NodeMapAccess {identifier_name},
        start,
        end
    } 
};


// The rule that defines a Scilla parameter pair.
// A Scilla parameter pair specifies a parameter of a Scilla contract.
// A Scilla parameter pair consists of the following components:
//
// <parameterPair> ::= <typedIdentifier>
//
// This rule allows for a Scilla parameter pair to be specified with an identifier with type.
//
// @syntax parameterPair
// @return A Scilla parameter pair with an identifier with type.
pub ParameterPair: WithMetaData<NodeParameterPair> = {
    <start:@L> <identifier_with_type: TypedIdentifier> <end:@R>
    => 
    WithMetaData::<NodeParameterPair> {
        node:  NodeParameterPair { identifier_with_type },
        start,
        end
    }

}


pub NextParameterPair: WithMetaData<NodeParameterPair> = {
    "," <p: ParameterPair>  => p
}


// The rule that defines Scilla component parameters.
// A Scilla component parameter specifies a parameter of a Scilla component.
// A Scilla component parameter consists of the following components:
//
// <componentParameters> ::= '(' [<parameterPair> (',' <parameterPair>)*]? ')' 
//
// This rule allows for Scilla component parameters to be specified with zero or more parameter pairs.
//
// @syntax componentParameters
// @return Scilla component parameters with zero or more parameter pairs.
pub ComponentParameters : WithMetaData<NodeComponentParameters> = {
   <start:@L> "(" 
   <p:ParameterPair?> <next_params:NextParameterPair*>
   ")" <end:@R>
   => WithMetaData::<NodeComponentParameters> {
       node: {
           let mut parameters: Vec<WithMetaData<NodeParameterPair>> = Vec::new();
           if let Some(pair) = p {
    	        parameters.push(pair);
           }

           for p in next_params {
               parameters.push(p);
           }

           NodeComponentParameters { parameters }
       },
       start,
       end
    }
};



// The rule that defines a Scilla component definition.
// A Scilla component definition specifies a component of a Scilla contract, which can either be a transition or a procedure.
// A Scilla component definition consists of the following components:
//
// <componentDefinition> ::= <transitionDefinition> | <procedureDefinition>
//
// This rule allows for a Scilla component definition to be specified with either a transition definition or a procedure definition.
//
// @syntax componentDefinition
// @return A Scilla component definition with either a transition definition or a procedure definition.
pub ComponentDefinition: WithMetaData<NodeComponentDefinition> = {
    <start:@L> <definition:TransitionDefinition> <end:@R> => 
    WithMetaData::<NodeComponentDefinition> { 
        node: NodeComponentDefinition::TransitionComponent(Box::new(definition)),
        start,
        end
    },
    <start:@L> <definition:ProcedureDefinition> <end:@R> => WithMetaData::<NodeComponentDefinition> {
        node: NodeComponentDefinition::ProcedureComponent(Box::new(definition)),
        start,
        end
    }
}    



// The rule that defines a Scilla transition definition.
// A Scilla transition definition specifies a transition of a Scilla contract.
// A Scilla transition definition consists of the following components:
//
// <transitionDefinition> ::= 'transition' <componentId> <componentParameters> <componentBody>
//
// This rule allows for a Scilla transition definition to be specified with a name, parameters, and body.
//
// @syntax transitionDefinition
// @return A Scilla transition definition with a name, parameters, and body.
pub TransitionDefinition : WithMetaData<NodeTransitionDefinition> = 
<start:@L> "transition" <name:ComponentId> <parameters:ComponentParameters> <body:ComponentBody> <end:@R> => 
    WithMetaData::<NodeTransitionDefinition> {
        node: NodeTransitionDefinition{name, parameters, body },
        start,
        end
    };



// The rule that defines a Scilla procedure definition.
// A Scilla procedure definition specifies a procedure of a Scilla contract.
// A Scilla procedure definition consists of the following components:
//
// <procedureDefinition> ::= "procedure" <componentId> <componentParameters> <componentBody>
// 
// This rule allows for a Scilla procedure definition to be specified with a name, parameters, and body.
//
// @syntax procedureDefinition
// @return A Scilla procedure definition with a name, parameters, and body.
pub ProcedureDefinition: WithMetaData<NodeProcedureDefinition> = {
    <start:@L> "procedure" 
    <name: ComponentId>
    <parameters:ComponentParameters>
    <body: ComponentBody> <end:@R>
    => WithMetaData::<NodeProcedureDefinition> {
        node: NodeProcedureDefinition{name,parameters,body } ,
        start,
        end
    }
};


// The rule that defines a Scilla component body.
// A component body specifies the body of a Scilla component.
// A component body consists of the following components:
//
// <componentBody> ::= [<statementBlock>] "end"
//
// This rule allows for a component body to be specified with an optional statement block.
//
// @syntax componentBody
// @return A Scilla component body with an optional statement block.
pub ComponentBody: WithMetaData<NodeComponentBody> = {
        <start:@L> <statement_block:StatementBlock?> "end" <end:@R> => WithMetaData::<NodeComponentBody>{ 
            node: NodeComponentBody{ statement_block },
            start,
            end
        }
    }
;



// The rule that defines a Scilla contract definition.
// A contract definition specifies the main contract of a Scilla program.
// A contract definition consists of the following components:
//
//
// <contractDefinition> ::= 'contract' <contractName> '(' <contractParameters> ')' [<withConstraint>] [<field>*] [<componentDefinition>*]
// <contractName> ::= <upperCaseCharacter><alphaNumericUnderscore>* | 'ByStr' <digit>+ | 'Event'
// <contractParameters> ::= [<parameterPair> (',' <parameterPair>)*] 
//
// This rule allows for a contract definition to be specified with optional parameters, constraint, fields, and components.
//
// @syntax contract
// @return A Scilla contract definition with a name, optional parameters, optional constraint, zero or more fields, and zero or more components.

pub ContractDefinition: WithMetaData<NodeContractDefinition> = {
    <start:@L> "contract" <contract_name:TypeNameIdentifier>
        <parameters:ComponentParameters>
        <constraint:WithConstraint?>
        <fields:ContractField*>
        <components:ComponentDefinition*> <end:@R>
    => WithMetaData::<NodeContractDefinition> {
        node: NodeContractDefinition {
            contract_name,
            parameters,
            constraint,
            fields,
            components
        },
        start,
        end
    }
};





// The rule that defines a Scilla contract field.
// A contract field specifies a variable that belongs to the contract state.
// A contract field consists of the following components:
//
// <contractField> ::= "field" <typedIdentifier> "=" <fullExpression>
//
// This rule allows for a contract field to be specified with a typed identifier and a right-hand side expression.
//
// @syntax contractField
// @return A Scilla contract field with a typed identifier and a right-hand side expression.

pub ContractField : WithMetaData<NodeContractField> = 
    <start:@L> "field" <typed_identifier:TypedIdentifier> "=" <right_hand_side:FullExpression> <end:@R>
    => WithMetaData::<NodeContractField> {
        node: NodeContractField{ typed_identifier, right_hand_side },
        start,
        end
    };


// The rule that defines a Scilla contract constraint.
// A contract constraint specifies a condition that must be satisfied for the contract to be valid.
// A contract constraint consists of the following components:
//
// <withConstraint> ::= "with" <fullExpression> "=>"
//
// This rule allows for a contract constraint to be specified with a boolean expression.
//
// @syntax withConstraint
// @return A Scilla contract constraint with a boolean expression.
pub WithConstraint: WithMetaData<NodeWithConstraint> = 
    <start:@L> "with" <expression:FullExpression> "=>" <end:@R> => 
    WithMetaData::<NodeWithConstraint> {
        node: NodeWithConstraint { expression: Box::new(expression) },
        start,
        end
    };    




HexNumber: WithMetaData<String> = {
   <start:@L> <node:r"0(x|X)([a-fA-F0-9][a-fA-F0-9])*"> <end:@R>  => WithMetaData::<String> {
        node: node.to_string(),
        start,
        end
    } 
}


// The rule that defines a Scilla integer.
// A Scilla integer is a numeric value that can be positive or negative.
// A Scilla integer consists of the following components:
//
// <integer> ::= ['-'] <digit>+
//
// This rule allows for Scilla integers to be specified as a numeric value that can be positive or negative.
//
// @syntax integer
// @return A Scilla integer as a numeric value that can be positive or negative. 

SignedInteger: WithMetaData<String> = {
    <start:@L> <node:r"[+-]?[0-9]+"> <end:@R> => WithMetaData::<String> {
        node: node.to_string(),
        start,
        end
    } 
}


// The rule that defines a regular identifier in Scilla.
// A regular identifier is a name that can be used to identify a variable or a function in a Scilla program.
// A regular identifier consists of one or more characters from the following set:
//
// <identiferRegular> ::= <lowerCaseCharacterOrUnderscore> <alphaNumericUnderscore>* 
//
// This rule allows for regular identifiers to be defined in a Scilla program.
//
// @syntax identifierRegular
// @return A regular identifier as a name that can be used to identify a variable or a function in a Scilla program.
RegularId: WithMetaData<String> = {
	<start:@L> <node:r"[a-z][a-zA-Z0-9_]*"> <end:@R> => WithMetaData::<String> {
        node: node.to_string(),
        start,
        end
    } 
}


// The rule that defines a special identifier in Scilla.
// A special identifier is an identifier in a Scilla contract that starts with an underscore followed by alphanumeric characters.
// 
// <identiferSpecial> ::= "_" <alphaNumericUnderscore>*
//
// @syntax identifierSpecial
// @return A special identifier as an identifier that starts with an underscore followed by alphanumeric characters.
SpecialId: WithMetaData<String>  = {
	<start:@L> <node:r"[_][a-zA-Z0-9_]*"> <end:@R> => WithMetaData::<String> {
        node: node.to_string(),
        start,
        end
    } 
}


// The rule that defines a custom type name in Scilla.
// A custom type name is a user-defined type name in a Scilla contract.
// A custom type name consists of a custom type identifier.
//
// <typeTypeOrEnumLikeIdentifierName> ::= <upperCaseCharacter> <alphaNumericUnderscore>* ;
//
// This rule allows for custom type names to be defined in a Scilla contract.
//
// @syntax typeTypeOrEnumLikeIdentifierName
// @return A custom type name as a user-defined type name in a Scilla contract.
TypeOrEnumLikeIdentifierId: WithMetaData<String> = {
	<start:@L> <node:r"[A-Z][a-zA-Z0-9_]*"> <end:@R> => WithMetaData::<String> {
        node: node.to_string(),
        start,
        end
    } 
}

TemplateTypeId: WithMetaData<String>  = {
	<start:@L> <node:r"['][A-Z][a-zA-Z0-9_]*"> <end:@R> => WithMetaData::<String> {
        node: node.to_string(),
        start,
        end
    }
}

StringLiteral: WithMetaData<String> = {
	<start:@L> <node:r#""(?:\\.|[^"])*""#> <end:@R> => WithMetaData::<String> {
        node: node.to_string(),
        start,
        end
    }
}