2018-08-09 01:54:43 +02:00
|
|
|
/*
|
2018-09-15 16:21:05 +02:00
|
|
|
Prog8 combined lexer and parser grammar
|
2018-08-10 23:56:30 +02:00
|
|
|
|
|
|
|
NOTES:
|
|
|
|
|
|
|
|
- whitespace is ignored. (tabs/spaces)
|
2018-09-13 22:31:59 +02:00
|
|
|
- every position can be empty, be a comment, or contain ONE statement.
|
2018-08-10 23:56:30 +02:00
|
|
|
|
2018-08-09 01:54:43 +02:00
|
|
|
*/
|
|
|
|
|
2021-10-09 16:56:39 +02:00
|
|
|
// -> java classes Prog8ANTLRParser and Prog8ANTLRLexer,
|
|
|
|
// both NOT to be used from Kotlin code, but ONLY through Kotlin class Prog8Parser
|
|
|
|
grammar Prog8ANTLR;
|
2018-08-09 01:54:43 +02:00
|
|
|
|
2019-01-29 12:06:33 +01:00
|
|
|
@header {
|
|
|
|
package prog8.parser;
|
|
|
|
}
|
2018-08-11 14:06:43 +02:00
|
|
|
|
2023-06-27 23:30:37 +02:00
|
|
|
EOL : ('\r'? '\n' | '\r' | '\n')+ ;
|
|
|
|
LINECOMMENT : EOL [ \t]* COMMENT -> channel(HIDDEN);
|
2021-06-14 22:04:22 +02:00
|
|
|
COMMENT : ';' ~[\r\n]* -> channel(HIDDEN) ;
|
2023-07-04 00:18:58 +02:00
|
|
|
BLOCK_COMMENT : '/*' ( BLOCK_COMMENT | . )*? '*/' -> skip ;
|
2021-06-13 22:49:54 +02:00
|
|
|
|
|
|
|
WS : [ \t] -> skip ;
|
2019-01-26 17:32:26 +01:00
|
|
|
// WS2 : '\\' EOL -> skip;
|
2020-02-09 01:21:23 +01:00
|
|
|
VOID: 'void';
|
2023-12-05 17:38:23 +01:00
|
|
|
NAME : [\p{Letter}][\p{Letter}\p{Mark}\p{Digit}_]* ; // match unicode properties
|
2024-03-31 00:20:37 +01:00
|
|
|
UNDERSCORENAME : '_' NAME ; // match unicode properties
|
2023-12-09 13:13:34 +01:00
|
|
|
DEC_INTEGER : DEC_DIGIT (DEC_DIGIT | '_')* ;
|
|
|
|
HEX_INTEGER : '$' HEX_DIGIT (HEX_DIGIT | '_')* ;
|
|
|
|
BIN_INTEGER : '%' BIN_DIGIT (BIN_DIGIT | '_')* ;
|
2022-04-02 02:08:01 +02:00
|
|
|
ADDRESS_OF: '&' ;
|
|
|
|
INVALID_AND_COMPOSITE: '&&' ;
|
2018-08-09 01:54:43 +02:00
|
|
|
|
2023-12-09 13:13:34 +01:00
|
|
|
fragment HEX_DIGIT: ('a'..'f') | ('A'..'F') | ('0'..'9') ;
|
|
|
|
fragment BIN_DIGIT: ('0' | '1') ;
|
|
|
|
fragment DEC_DIGIT: ('0'..'9') ;
|
|
|
|
|
2023-03-26 21:09:15 +02:00
|
|
|
FLOAT_NUMBER : FNUMBER (('E'|'e') ('+' | '-')? DEC_INTEGER)? ; // sign comes later from unary expression
|
2023-07-04 00:18:58 +02:00
|
|
|
FNUMBER : FDOTNUMBER | FNUMDOTNUMBER ;
|
2023-12-09 13:13:34 +01:00
|
|
|
FDOTNUMBER : '.' (DEC_DIGIT | '_')+ ;
|
|
|
|
FNUMDOTNUMBER : DEC_DIGIT (DEC_DIGIT | '_')* FDOTNUMBER? ;
|
2018-08-09 01:54:43 +02:00
|
|
|
|
2023-07-04 00:18:58 +02:00
|
|
|
STRING_ESCAPE_SEQ : '\\' . | '\\x' . . | '\\u' . . . .;
|
2018-08-10 00:26:41 +02:00
|
|
|
STRING :
|
|
|
|
'"' ( STRING_ESCAPE_SEQ | ~[\\\r\n\f"] )* '"'
|
2018-08-09 01:54:43 +02:00
|
|
|
;
|
2018-08-10 23:56:30 +02:00
|
|
|
INLINEASMBLOCK :
|
|
|
|
'{{' .+? '}}'
|
|
|
|
;
|
2018-08-09 01:54:43 +02:00
|
|
|
|
2018-09-30 23:07:26 +02:00
|
|
|
SINGLECHAR :
|
2021-12-05 18:11:40 +01:00
|
|
|
'\'' ( STRING_ESCAPE_SEQ | ~[\\\r\n\f'] ) '\''
|
2018-09-30 23:07:26 +02:00
|
|
|
;
|
|
|
|
|
2022-01-14 23:16:05 +01:00
|
|
|
ZEROPAGE : '@zp' ;
|
2019-01-26 22:46:01 +01:00
|
|
|
|
2022-01-14 23:16:05 +01:00
|
|
|
ZEROPAGEREQUIRE : '@requirezp' ;
|
|
|
|
|
2024-05-21 21:53:58 +02:00
|
|
|
ZEROPAGENOT: '@nozp' ;
|
|
|
|
|
2022-01-14 23:16:05 +01:00
|
|
|
SHARED : '@shared' ;
|
2021-05-19 01:19:25 +02:00
|
|
|
|
2023-05-22 20:31:28 +02:00
|
|
|
SPLIT: '@split' ;
|
|
|
|
|
2019-04-16 01:19:51 +02:00
|
|
|
ARRAYSIG :
|
|
|
|
'[]'
|
|
|
|
;
|
|
|
|
|
2020-12-21 19:19:53 +01:00
|
|
|
|
2021-06-14 22:17:30 +02:00
|
|
|
// A module (file) consists of zero or more directives or blocks, in any order.
|
|
|
|
// If there are more than one, then they must be separated by EOL (one or more newlines).
|
|
|
|
// However, trailing EOL is NOT required.
|
2021-06-18 21:55:03 +02:00
|
|
|
// Note: the parser may see *several* consecutive EOLs - this happens when EOL and comments are interleaved (see #47)
|
|
|
|
module: EOL* ((directive | block) (EOL+ (directive | block))*)? EOL* EOF;
|
2018-08-10 23:56:30 +02:00
|
|
|
|
2023-06-27 01:59:22 +02:00
|
|
|
block: identifier integerliteral? EOL? '{' EOL? (block_statement | EOL)* '}';
|
2020-03-14 14:20:55 +01:00
|
|
|
|
|
|
|
block_statement:
|
|
|
|
directive
|
|
|
|
| variabledeclaration
|
|
|
|
| subroutinedeclaration
|
|
|
|
| inlineasm
|
2022-09-30 14:05:11 +02:00
|
|
|
| inlineir
|
2021-04-18 23:03:18 +02:00
|
|
|
| labeldef
|
2020-03-14 14:20:55 +01:00
|
|
|
;
|
|
|
|
|
2018-08-10 00:26:41 +02:00
|
|
|
|
|
|
|
statement :
|
2018-08-09 01:54:43 +02:00
|
|
|
directive
|
2020-03-14 13:23:13 +01:00
|
|
|
| variabledeclaration
|
2018-08-09 01:54:43 +02:00
|
|
|
| assignment
|
|
|
|
| augassignment
|
2018-08-10 23:56:30 +02:00
|
|
|
| unconditionaljump
|
|
|
|
| postincrdecr
|
2018-08-14 02:22:59 +02:00
|
|
|
| functioncall_stmt
|
2018-08-14 14:33:36 +02:00
|
|
|
| if_stmt
|
2018-09-02 18:32:48 +02:00
|
|
|
| branch_stmt
|
2020-03-14 13:23:13 +01:00
|
|
|
| subroutinedeclaration
|
2018-08-10 23:56:30 +02:00
|
|
|
| inlineasm
|
2022-09-30 14:05:11 +02:00
|
|
|
| inlineir
|
2018-08-12 17:16:36 +02:00
|
|
|
| returnstmt
|
2018-09-16 03:00:32 +02:00
|
|
|
| forloop
|
2018-09-23 02:04:45 +02:00
|
|
|
| whileloop
|
2020-07-25 16:25:02 +02:00
|
|
|
| untilloop
|
2018-09-23 02:04:45 +02:00
|
|
|
| repeatloop
|
2023-03-14 23:37:49 +01:00
|
|
|
| unrollloop
|
2019-07-09 00:02:38 +02:00
|
|
|
| whenstmt
|
2018-09-18 23:14:32 +02:00
|
|
|
| breakstmt
|
2023-11-19 17:52:43 +01:00
|
|
|
| continuestmt
|
2018-09-19 02:41:35 +02:00
|
|
|
| labeldef
|
2018-08-09 01:54:43 +02:00
|
|
|
;
|
|
|
|
|
2018-09-16 03:00:32 +02:00
|
|
|
|
2020-03-14 13:23:13 +01:00
|
|
|
variabledeclaration :
|
|
|
|
varinitializer
|
|
|
|
| vardecl
|
|
|
|
| constdecl
|
|
|
|
| memoryvardecl
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
subroutinedeclaration :
|
|
|
|
subroutine
|
|
|
|
| asmsubroutine
|
|
|
|
| romsubroutine
|
|
|
|
;
|
|
|
|
|
|
|
|
|
2018-08-12 17:16:36 +02:00
|
|
|
labeldef : identifier ':' ;
|
2018-08-10 23:56:30 +02:00
|
|
|
|
2019-01-02 23:32:41 +01:00
|
|
|
unconditionaljump : 'goto' (integerliteral | scoped_identifier) ;
|
2018-08-09 01:54:43 +02:00
|
|
|
|
2023-12-29 03:39:12 +01:00
|
|
|
directive :
|
|
|
|
directivename=('%output' | '%launcher' | '%zeropage' | '%zpreserved' | '%zpallowed' | '%address' | '%import' |
|
|
|
|
'%breakpoint' | '%asminclude' | '%asmbinary' | '%option' | '%encoding' )
|
|
|
|
(directivearg? | directivearg (',' directivearg)*)
|
|
|
|
;
|
2018-08-09 01:54:43 +02:00
|
|
|
|
2018-08-10 23:56:30 +02:00
|
|
|
directivearg : stringliteral | identifier | integerliteral ;
|
2018-08-09 01:54:43 +02:00
|
|
|
|
2023-12-08 22:08:17 +01:00
|
|
|
vardecl: datatype (arrayindex | ARRAYSIG)? decloptions identifier (',' identifier)* ;
|
2022-01-14 23:16:05 +01:00
|
|
|
|
2024-05-21 21:53:58 +02:00
|
|
|
decloptions: (SHARED | ZEROPAGE | ZEROPAGEREQUIRE | ZEROPAGENOT | SPLIT)* ;
|
2019-07-15 22:28:05 +02:00
|
|
|
|
2019-01-26 22:46:01 +01:00
|
|
|
varinitializer : vardecl '=' expression ;
|
2018-08-09 01:54:43 +02:00
|
|
|
|
2018-08-10 00:26:41 +02:00
|
|
|
constdecl: 'const' varinitializer ;
|
|
|
|
|
2019-04-12 22:00:32 +02:00
|
|
|
memoryvardecl: ADDRESS_OF varinitializer;
|
2018-08-10 00:26:41 +02:00
|
|
|
|
2022-07-04 23:42:49 +02:00
|
|
|
datatype: 'ubyte' | 'byte' | 'uword' | 'word' | 'float' | 'str' | 'bool' ;
|
2018-08-10 00:26:41 +02:00
|
|
|
|
2019-04-16 01:19:51 +02:00
|
|
|
arrayindex: '[' expression ']' ;
|
2018-08-10 00:26:41 +02:00
|
|
|
|
2024-01-13 02:05:52 +01:00
|
|
|
assignment : (assign_target '=' expression) | (assign_target '=' assignment) | (multi_assign_target '=' expression);
|
2018-08-09 01:54:43 +02:00
|
|
|
|
|
|
|
augassignment :
|
2022-03-27 12:12:57 +02:00
|
|
|
assign_target operator=('+=' | '-=' | '/=' | '*=' | '&=' | '|=' | '^=' | '%=' | '<<=' | '>>=' ) expression
|
2018-08-09 01:54:43 +02:00
|
|
|
;
|
|
|
|
|
2018-08-10 00:26:41 +02:00
|
|
|
assign_target:
|
2023-08-15 12:54:30 +02:00
|
|
|
scoped_identifier #IdentifierTarget
|
2023-09-03 19:06:47 +02:00
|
|
|
| arrayindexed #ArrayindexedTarget
|
2023-08-15 12:54:30 +02:00
|
|
|
| directmemory #MemoryTarget
|
2018-08-10 00:26:41 +02:00
|
|
|
;
|
2018-08-09 01:54:43 +02:00
|
|
|
|
2024-01-13 02:05:52 +01:00
|
|
|
multi_assign_target:
|
|
|
|
assign_target (',' assign_target)+ ;
|
|
|
|
|
2018-08-10 23:56:30 +02:00
|
|
|
postincrdecr : assign_target operator = ('++' | '--') ;
|
|
|
|
|
2018-08-09 01:54:43 +02:00
|
|
|
expression :
|
2022-01-08 13:45:00 +01:00
|
|
|
'(' expression ')'
|
|
|
|
| functioncall
|
2018-12-31 04:48:26 +01:00
|
|
|
| <assoc=right> prefix = ('+'|'-'|'~') expression
|
2019-01-26 17:32:26 +01:00
|
|
|
| left = expression EOL? bop = ('*' | '/' | '%' ) EOL? right = expression
|
|
|
|
| left = expression EOL? bop = ('+' | '-' ) EOL? right = expression
|
|
|
|
| left = expression EOL? bop = ('<<' | '>>' ) EOL? right = expression
|
|
|
|
| left = expression EOL? bop = '&' EOL? right = expression
|
|
|
|
| left = expression EOL? bop = '^' EOL? right = expression
|
|
|
|
| left = expression EOL? bop = '|' EOL? right = expression
|
2022-08-14 12:34:00 +02:00
|
|
|
| left = expression EOL? bop = ('<' | '>' | '<=' | '>=') EOL? right = expression
|
2020-10-11 19:02:53 +02:00
|
|
|
| left = expression EOL? bop = ('==' | '!=') EOL? right = expression
|
2020-03-11 20:47:42 +01:00
|
|
|
| rangefrom = expression rto = ('to'|'downto') rangeto = expression ('step' rangestep = expression)? // can't create separate rule due to mutual left-recursion
|
2021-12-29 16:21:37 +01:00
|
|
|
| left = expression EOL? bop = 'in' EOL? right = expression
|
2023-12-19 19:49:25 +01:00
|
|
|
| left = expression EOL? bop = ('not in ' | 'not in\t' | 'not in\n' | 'not in\r') EOL? right = expression
|
2021-11-08 18:38:04 +01:00
|
|
|
| prefix = 'not' expression
|
2019-01-26 17:32:26 +01:00
|
|
|
| left = expression EOL? bop = 'and' EOL? right = expression
|
|
|
|
| left = expression EOL? bop = 'or' EOL? right = expression
|
|
|
|
| left = expression EOL? bop = 'xor' EOL? right = expression
|
2018-08-09 01:54:43 +02:00
|
|
|
| literalvalue
|
2018-08-10 02:58:41 +02:00
|
|
|
| scoped_identifier
|
2023-09-03 19:06:47 +02:00
|
|
|
| arrayindexed
|
2018-12-30 21:40:27 +01:00
|
|
|
| directmemory
|
2019-04-11 20:55:20 +02:00
|
|
|
| addressof
|
2018-12-19 03:51:22 +01:00
|
|
|
| expression typecast
|
2018-08-09 01:54:43 +02:00
|
|
|
;
|
|
|
|
|
2023-09-03 19:06:47 +02:00
|
|
|
arrayindexed:
|
|
|
|
scoped_identifier arrayindex
|
|
|
|
;
|
|
|
|
|
|
|
|
|
2018-12-19 03:51:22 +01:00
|
|
|
typecast : 'as' datatype;
|
|
|
|
|
2018-12-31 04:48:26 +01:00
|
|
|
directmemory : '@' '(' expression ')';
|
2018-12-30 21:40:27 +01:00
|
|
|
|
2023-09-17 18:30:57 +02:00
|
|
|
addressof : <assoc=right> ADDRESS_OF (scoped_identifier | arrayindexed) ;
|
2019-04-04 21:02:24 +02:00
|
|
|
|
2018-10-01 22:23:16 +02:00
|
|
|
|
2020-02-09 01:21:23 +01:00
|
|
|
functioncall : scoped_identifier '(' expression_list? ')' ;
|
2018-08-14 02:22:59 +02:00
|
|
|
|
2020-02-09 01:21:23 +01:00
|
|
|
functioncall_stmt : VOID? scoped_identifier '(' expression_list? ')' ;
|
2018-08-14 02:22:59 +02:00
|
|
|
|
2018-08-12 17:16:36 +02:00
|
|
|
expression_list :
|
2018-12-31 01:52:18 +01:00
|
|
|
expression (',' EOL? expression)* // you can split the expression list over several lines
|
2018-08-09 01:54:43 +02:00
|
|
|
;
|
|
|
|
|
2019-07-10 19:14:41 +02:00
|
|
|
returnstmt : 'return' expression? ;
|
2018-08-12 17:16:36 +02:00
|
|
|
|
2018-09-16 03:00:32 +02:00
|
|
|
breakstmt : 'break';
|
|
|
|
|
2023-11-19 17:52:43 +01:00
|
|
|
continuestmt: 'continue';
|
|
|
|
|
2024-03-31 23:43:26 +02:00
|
|
|
identifier : NAME | UNDERSCORENAME | VOID;
|
2018-08-09 01:54:43 +02:00
|
|
|
|
2024-03-31 00:20:37 +01:00
|
|
|
scoped_identifier : identifier ('.' identifier)* ;
|
2018-08-09 01:54:43 +02:00
|
|
|
|
2020-09-19 23:23:32 +02:00
|
|
|
integerliteral : intpart=(DEC_INTEGER | HEX_INTEGER | BIN_INTEGER) ;
|
2018-08-09 01:54:43 +02:00
|
|
|
|
2018-08-10 00:26:41 +02:00
|
|
|
booleanliteral : 'true' | 'false' ;
|
2018-08-09 01:54:43 +02:00
|
|
|
|
2019-07-16 00:08:28 +02:00
|
|
|
arrayliteral : '[' EOL? expression (',' EOL? expression)* EOL? ']' ; // you can split the values over several lines
|
|
|
|
|
2022-02-11 21:56:33 +01:00
|
|
|
stringliteral : (encoding=NAME ':')? STRING ;
|
2018-08-09 01:54:43 +02:00
|
|
|
|
2022-02-11 21:56:33 +01:00
|
|
|
charliteral : (encoding=NAME ':')? SINGLECHAR ;
|
2018-09-30 23:07:26 +02:00
|
|
|
|
2018-08-10 00:26:41 +02:00
|
|
|
floatliteral : FLOAT_NUMBER ;
|
2018-08-09 01:54:43 +02:00
|
|
|
|
2019-07-16 00:08:28 +02:00
|
|
|
|
2018-08-10 00:26:41 +02:00
|
|
|
literalvalue :
|
|
|
|
integerliteral
|
|
|
|
| booleanliteral
|
|
|
|
| arrayliteral
|
|
|
|
| stringliteral
|
2018-09-30 23:07:26 +02:00
|
|
|
| charliteral
|
2018-08-10 00:26:41 +02:00
|
|
|
| floatliteral
|
2018-08-09 01:54:43 +02:00
|
|
|
;
|
2018-08-10 23:56:30 +02:00
|
|
|
|
2023-08-09 20:01:12 +02:00
|
|
|
inlineasm : '%asm' EOL? INLINEASMBLOCK;
|
2018-08-13 01:30:33 +02:00
|
|
|
|
2023-08-09 20:01:12 +02:00
|
|
|
inlineir: '%ir' EOL? INLINEASMBLOCK;
|
2022-09-30 14:05:11 +02:00
|
|
|
|
2020-12-26 05:33:00 +01:00
|
|
|
inline: 'inline';
|
2018-08-13 01:30:33 +02:00
|
|
|
|
|
|
|
subroutine :
|
2024-08-26 21:25:23 +02:00
|
|
|
'sub' identifier '(' sub_params? ')' sub_return_part? EOL? (statement_block EOL?)
|
2018-08-13 04:12:42 +02:00
|
|
|
;
|
|
|
|
|
2022-03-12 14:12:06 +01:00
|
|
|
sub_return_part : '->' datatype ;
|
2018-09-30 18:49:58 +02:00
|
|
|
|
2018-08-14 14:33:36 +02:00
|
|
|
statement_block :
|
2023-06-27 01:59:22 +02:00
|
|
|
'{' EOL?
|
2018-08-13 01:30:33 +02:00
|
|
|
(statement | EOL) *
|
2018-08-14 14:33:36 +02:00
|
|
|
'}'
|
2018-08-13 01:30:33 +02:00
|
|
|
;
|
|
|
|
|
2018-08-13 04:12:42 +02:00
|
|
|
|
2018-12-19 02:51:22 +01:00
|
|
|
sub_params : vardecl (',' EOL? vardecl)* ;
|
2018-10-01 20:05:32 +02:00
|
|
|
|
|
|
|
asmsubroutine :
|
2024-08-26 21:25:23 +02:00
|
|
|
inline? 'asmsub' asmsub_decl EOL? (statement_block EOL?)
|
2018-10-01 20:05:32 +02:00
|
|
|
;
|
|
|
|
|
2020-03-10 23:09:31 +01:00
|
|
|
romsubroutine :
|
|
|
|
'romsub' integerliteral '=' asmsub_decl
|
|
|
|
;
|
|
|
|
|
|
|
|
asmsub_decl : identifier '(' asmsub_params? ')' asmsub_clobbers? asmsub_returns? ;
|
2018-10-01 20:05:32 +02:00
|
|
|
|
2018-10-02 22:52:05 +02:00
|
|
|
asmsub_params : asmsub_param (',' EOL? asmsub_param)* ;
|
2018-10-01 20:05:32 +02:00
|
|
|
|
2023-03-08 22:57:19 +01:00
|
|
|
asmsub_param : vardecl '@' register=NAME ; // A,X,Y,AX,AY,XY,Pc,Pz,Pn,Pv allowed.
|
2019-07-08 23:00:18 +02:00
|
|
|
|
|
|
|
asmsub_clobbers : 'clobbers' '(' clobber? ')' ;
|
2018-10-01 20:05:32 +02:00
|
|
|
|
2023-03-08 22:57:19 +01:00
|
|
|
clobber : NAME (',' NAME)* ; // A,X,Y allowed
|
2018-08-13 01:30:33 +02:00
|
|
|
|
2019-07-08 23:00:18 +02:00
|
|
|
asmsub_returns : '->' asmsub_return (',' EOL? asmsub_return)* ;
|
2018-08-13 01:30:33 +02:00
|
|
|
|
2023-03-08 22:57:19 +01:00
|
|
|
asmsub_return : datatype '@' register=NAME ; // A,X,Y,AX,AY,XY,Pc,Pz,Pn,Pv allowed
|
2018-08-14 14:33:36 +02:00
|
|
|
|
|
|
|
|
2019-01-01 18:45:21 +01:00
|
|
|
if_stmt : 'if' expression EOL? (statement | statement_block) EOL? else_part? ; // statement is constrained later
|
2018-08-14 14:33:36 +02:00
|
|
|
|
|
|
|
else_part : 'else' EOL? (statement | statement_block) ; // statement is constrained later
|
2018-09-02 18:32:48 +02:00
|
|
|
|
|
|
|
|
2024-04-09 22:35:30 +02:00
|
|
|
branch_stmt : branchcondition EOL? (statement | statement_block) EOL? else_part? ;
|
2018-09-02 18:32:48 +02:00
|
|
|
|
2018-09-22 00:33:25 +02:00
|
|
|
branchcondition: 'if_cs' | 'if_cc' | 'if_eq' | 'if_z' | 'if_ne' | 'if_nz' | 'if_pl' | 'if_pos' | 'if_mi' | 'if_neg' | 'if_vs' | 'if_vc' ;
|
2018-09-16 03:00:32 +02:00
|
|
|
|
|
|
|
|
2021-12-10 14:59:04 +01:00
|
|
|
forloop : 'for' scoped_identifier 'in' expression EOL? (statement | statement_block) ;
|
2018-09-23 02:04:45 +02:00
|
|
|
|
|
|
|
whileloop: 'while' expression EOL? (statement | statement_block) ;
|
|
|
|
|
2020-07-25 16:25:02 +02:00
|
|
|
untilloop: 'do' (statement | statement_block) EOL? 'until' expression ;
|
2019-07-09 00:02:38 +02:00
|
|
|
|
2020-07-25 16:25:02 +02:00
|
|
|
repeatloop: 'repeat' expression? EOL? (statement | statement_block) ;
|
2020-03-14 18:11:04 +01:00
|
|
|
|
2023-09-05 00:53:58 +02:00
|
|
|
unrollloop: 'unroll' expression EOL? (statement | statement_block) ; // note: expression must evaluate to a constant
|
2023-03-14 23:37:49 +01:00
|
|
|
|
2023-06-27 01:59:22 +02:00
|
|
|
whenstmt: 'when' expression EOL? '{' EOL? (when_choice | EOL) * '}' EOL? ;
|
2019-07-09 00:02:38 +02:00
|
|
|
|
2019-07-10 00:25:21 +02:00
|
|
|
when_choice: (expression_list | 'else' ) '->' (statement | statement_block ) ;
|