@@ -46,6 +46,9 @@ const ALL_KEYWORDS = [
4646 'let' ,
4747 'const' ,
4848 'constant' ,
49+ 'export' ,
50+ 'dyn' ,
51+ 'identifier' ,
4952 'final' ,
5053 'view' ,
5154 'fn' ,
@@ -108,6 +111,7 @@ module.exports = grammar({
108111 [ $ . path_locator_expression , $ . program_ref_expression ] ,
109112 [ $ . path_locator_expression , $ . locator_type ] ,
110113 [ $ . path_locator_expression , $ . program_ref_expression , $ . locator_type ] ,
114+ [ $ . path_locator_expression ] ,
111115 [ $ . return_type , $ . tuple_type ] ,
112116 [ $ . return_type_item , $ . tuple_type ] ,
113117 [ $ . optional_type , $ . mapping_type ] ,
@@ -141,6 +145,7 @@ module.exports = grammar({
141145 $ . struct_definition ,
142146 $ . function_definition ,
143147 $ . final_function_definition ,
148+ $ . view_function_definition ,
144149 $ . const_declaration ,
145150 ) ,
146151
@@ -184,6 +189,7 @@ module.exports = grammar({
184189 ) ,
185190
186191 interface_declaration : $ => seq (
192+ optional ( 'export' ) ,
187193 'interface' ,
188194 field ( 'name' , $ . identifier ) ,
189195 optional ( seq ( ':' , field ( 'parents' , $ . parent_list ) ) ) ,
@@ -212,10 +218,16 @@ module.exports = grammar({
212218 record_prototype : $ => seq (
213219 'record' ,
214220 field ( 'name' , $ . identifier ) ,
215- ';' ,
221+ choice (
222+ ';' ,
223+ // Partially-constrained record body in an interface: fields must end
224+ // with a trailing `..` (fully constraining fields is not yet supported).
225+ seq ( '{' , optional ( commaSep1 ( $ . struct_field ) ) , '..' , '}' ) ,
226+ ) ,
216227 ) ,
217228
218229 struct_definition : $ => seq (
230+ optional ( 'export' ) ,
219231 'struct' ,
220232 field ( 'name' , $ . identifier ) ,
221233 optional ( field ( 'const_parameters' , $ . const_param_list ) ) ,
@@ -267,6 +279,7 @@ module.exports = grammar({
267279 ) ,
268280
269281 const_declaration : $ => seq (
282+ optional ( 'export' ) ,
270283 'const' ,
271284 field ( 'name' , $ . identifier ) ,
272285 ':' ,
@@ -278,6 +291,7 @@ module.exports = grammar({
278291
279292 function_definition : $ => seq (
280293 repeat ( $ . annotation ) ,
294+ optional ( 'export' ) ,
281295 'fn' ,
282296 field ( 'name' , $ . identifier ) ,
283297 optional ( field ( 'const_parameters' , $ . const_param_list ) ) ,
@@ -288,6 +302,7 @@ module.exports = grammar({
288302
289303 final_function_definition : $ => seq (
290304 repeat ( $ . annotation ) ,
305+ optional ( 'export' ) ,
291306 'final' ,
292307 'fn' ,
293308 field ( 'name' , $ . identifier ) ,
@@ -299,6 +314,7 @@ module.exports = grammar({
299314
300315 view_function_definition : $ => seq (
301316 repeat ( $ . annotation ) ,
317+ optional ( 'export' ) ,
302318 'view' ,
303319 'fn' ,
304320 field ( 'name' , $ . identifier ) ,
@@ -318,7 +334,7 @@ module.exports = grammar({
318334 const_param_list : $ => seq (
319335 token ( prec ( 1 , '::' ) ) ,
320336 '[' ,
321- commaSep1 ( $ . const_param ) ,
337+ optional ( commaSep1 ( $ . const_param ) ) ,
322338 ']' ,
323339 ) ,
324340
@@ -354,7 +370,7 @@ module.exports = grammar({
354370 annotation : $ => seq (
355371 '@' ,
356372 field ( 'name' , $ . _annotation_name ) ,
357- optional ( seq ( '(' , commaSep1 ( $ . annotation_pair ) , ')' ) ) ,
373+ optional ( seq ( '(' , optional ( commaSep1 ( $ . annotation_pair ) ) , ')' ) ) ,
358374 ) ,
359375
360376 annotation_pair : $ => seq (
@@ -529,6 +545,7 @@ module.exports = grammar({
529545 $ . field_expression ,
530546 $ . tuple_access_expression ,
531547 $ . index_expression ,
548+ $ . dynamic_op_expression ,
532549 $ . path_expression ,
533550 $ . struct_expression ,
534551 $ . struct_locator_expression ,
@@ -555,6 +572,7 @@ module.exports = grammar({
555572 $ . field_expression ,
556573 $ . tuple_access_expression ,
557574 $ . index_expression ,
575+ $ . dynamic_op_expression ,
558576 $ . path_expression ,
559577 $ . path_locator_expression ,
560578 $ . program_ref_expression ,
@@ -613,7 +631,7 @@ module.exports = grammar({
613631 cast_expression : $ => prec . left ( PREC . cast , seq (
614632 field ( 'value' , $ . _expression ) ,
615633 'as' ,
616- field ( 'type' , $ . primitive_type ) ,
634+ field ( 'type' , choice ( $ . primitive_type , $ . dyn_record_type ) ) ,
617635 ) ) ,
618636
619637 ternary_expression : $ => prec . right ( PREC . ternary , seq (
@@ -661,6 +679,26 @@ module.exports = grammar({
661679 ']' ,
662680 ) ) ,
663681
682+ // Dynamic interface/storage access, in three forms:
683+ // iface@(target)::func(args) — dynamic function call
684+ // iface@(target)::storage.op(args) — dynamic mapping/vector access
685+ // iface@(target)::storage — dynamic singleton storage read
686+ // The target may be followed by an optional network argument: `@(target, network)`.
687+ dynamic_op_expression : $ => prec . left ( PREC . call , seq (
688+ field ( 'interface' , $ . _expression ) ,
689+ '@' ,
690+ '(' ,
691+ field ( 'target' , $ . _expression ) ,
692+ optional ( seq ( ',' , field ( 'network' , $ . _expression ) ) ) ,
693+ ')' ,
694+ token ( prec ( 1 , '::' ) ) ,
695+ field ( 'member' , $ . identifier ) ,
696+ optional ( choice (
697+ field ( 'arguments' , $ . argument_list ) ,
698+ seq ( '.' , field ( 'operation' , $ . identifier ) , field ( 'arguments' , $ . argument_list ) ) ,
699+ ) ) ,
700+ ) ) ,
701+
664702 path_expression : $ => choice (
665703 $ . special_path ,
666704 seq (
@@ -684,6 +722,7 @@ module.exports = grammar({
684722 field ( 'program' , $ . program_id ) ,
685723 token ( prec ( 1 , '::' ) ) ,
686724 field ( 'member' , $ . identifier ) ,
725+ repeat ( seq ( token ( prec ( 1 , '::' ) ) , $ . identifier ) ) ,
687726 optional ( $ . const_arg_list ) ,
688727 ) ,
689728
@@ -722,15 +761,19 @@ module.exports = grammar({
722761 const_arg_list_bracket : $ => seq (
723762 token ( prec ( 1 , '::' ) ) ,
724763 '[' ,
725- commaSep1 ( $ . const_arg ) ,
764+ optional ( commaSep1 ( $ . const_arg ) ) ,
726765 ']' ,
727766 ) ,
728767
729768 const_arg : $ => choice (
769+ $ . dynamic_call_return_type ,
730770 $ . _type ,
731771 $ . _expression ,
732772 ) ,
733773
774+ // A visibility-prefixed type argument, e.g. `public u64` in `foo::[public u64]`.
775+ dynamic_call_return_type : $ => seq ( $ . visibility , $ . _type ) ,
776+
734777 const_arg_list_angle : $ => seq (
735778 token ( prec ( 1 , '::' ) ) ,
736779 '<' ,
@@ -798,11 +841,13 @@ module.exports = grammar({
798841 / 0 b [ 0 - 9 A - Z a - z _ ] + ( u 8 | u 1 6 | u 3 2 | u 6 4 | u 1 2 8 | i 8 | i 1 6 | i 3 2 | i 6 4 | i 1 2 8 ) ? / ,
799842 ) ) ,
800843
801- field_literal : _ => token ( prec ( 2 , / [ 0 - 9 ] [ 0 - 9 _ ] * f i e l d / ) ) ,
844+ // Suffix literals accept the same bases as integer literals (decimal, `0x`, `0o`, `0b`);
845+ // the compiler classifies purely by the trailing type suffix.
846+ field_literal : _ => token ( prec ( 2 , / [ 0 - 9 ] [ 0 - 9 A - Z a - z _ ] * f i e l d / ) ) ,
802847
803- group_literal : _ => token ( prec ( 2 , / [ 0 - 9 ] [ 0 - 9 _ ] * g r o u p / ) ) ,
848+ group_literal : _ => token ( prec ( 2 , / [ 0 - 9 ] [ 0 - 9 A - Z a - z _ ] * g r o u p / ) ) ,
804849
805- scalar_literal : _ => token ( prec ( 2 , / [ 0 - 9 ] [ 0 - 9 _ ] * s c a l a r / ) ) ,
850+ scalar_literal : _ => token ( prec ( 2 , / [ 0 - 9 ] [ 0 - 9 A - Z a - z _ ] * s c a l a r / ) ) ,
806851
807852 string_literal : _ => token ( / " [ ^ " ] * " / ) ,
808853
@@ -817,6 +862,7 @@ module.exports = grammar({
817862
818863 _type : $ => choice (
819864 $ . primitive_type ,
865+ $ . dyn_record_type ,
820866 $ . path_type ,
821867 $ . locator_type ,
822868 $ . array_type ,
@@ -827,6 +873,9 @@ module.exports = grammar({
827873 $ . mapping_type ,
828874 ) ,
829875
876+ // A dynamic record type: `dyn record`.
877+ dyn_record_type : _ => seq ( 'dyn' , 'record' ) ,
878+
830879 primitive_type : _ => choice (
831880 'address' ,
832881 'bool' ,
@@ -856,7 +905,7 @@ module.exports = grammar({
856905
857906 locator_type : $ => seq (
858907 $ . program_id ,
859- optional ( seq ( token ( prec ( 1 , '::' ) ) , $ . identifier ) ) ,
908+ repeat ( seq ( token ( prec ( 1 , '::' ) ) , $ . identifier ) ) ,
860909 optional ( $ . const_arg_list ) ,
861910 ) ,
862911
0 commit comments