// Lark Grammar for Colang 2.x ?start: _statements | suite // General sequences of statements _statements: stmt* ?stmt: (def_stmt | flow_stmt | comment _NEWLINE | _NEWLINE) suite: _NEWLINE _INDENT (stmt+) _DEDENT // Flow definition and calling ?def_stmt: flow_def decorators: (decorator _NEWLINE)* decorator: "@" decorator_name ["(" decorator_parameters ")"] decorator_parameters: _argvalues* flow_def: decorators _FLOW spec_name [flow_params_def] ["->" return_members_def] suite ?flow_params_def: flow_params_def_classic | flow_params_def_simple flow_params_def_classic: "(" (flow_param_def ("," flow_param_def)*) ")" flow_params_def_simple: (flow_param_def)+ flow_param_def: var_name ("=" test)? ?flow_stmt: simple_stmt | spec_op_stmt | compound_stmt | doc_string_stmt return_members_def: return_member_def ("," return_member_def)* return_member_def: var_name ("=" test)? // Simple statements ?simple_stmt: set_stmt | return_stmt | abort_stmt | break_stmt | continue_stmt | pass_stmt | log_stmt | print_stmt | priority_stmt | label_stmt | global_stmt | expr_stmt | import_stmt set_stmt: var_name set_op set_right_side _NEWLINE ?set_right_side: test | spec_op doc_string_stmt: doc_string _NEWLINE // TODO: support more assignment operators? set_op: "=" -> set | "+=" -> increment | "-=" -> decrement return_stmt: "return" [test] _NEWLINE abort_stmt: "abort" _NEWLINE break_stmt: "break" _NEWLINE continue_stmt: "continue" _NEWLINE pass_stmt: "pass" _NEWLINE log_stmt: "log" (expr | "(" expr ")") _NEWLINE print_stmt: "print" (expr | "(" expr ")") _NEWLINE priority_stmt: "priority" expr _NEWLINE label_stmt: NAME":" _NEWLINE global_stmt: "global" var_name _NEWLINE import_stmt: "import" (package_name | string) _NEWLINE expr_stmt: "(" test ")" // -------------------------------- // A "spec" is a unifying concept for flows, actions, events spec_operator: "match" -> match_spec | "await" -> await_spec | "start" -> start_spec | "stop" -> stop_spec | "activate" -> activate_spec | "deactivate" -> deactivate_spec | "send" -> send_spec spec_op: spec_operator spec_expr | non_var_spec_expr ?spec_op_stmt: spec_op _NEWLINE capture_ref: "as" var_name // TODO: find a more elegant solution. // NON-VAR branch ?non_var_spec_expr: non_var_spec_or ?non_var_spec_or: non_var_spec_and (_OR non_var_spec_and)+ | non_var_spec_and ?non_var_spec_and: non_var_spec_atom (_AND non_var_spec_atom)+ | non_var_spec_atom ?non_var_spec_atom: "(" non_var_spec_expr ")" | non_var_spec ?non_var_spec: spec_name [classic_arguments | simple_arguments] (spec_member)* [capture_ref] -> spec // Arbitrary expressions with specs including "and" and "or" as operators ?spec_expr: spec_or ?spec_or: spec_and (_OR spec_and)+ | spec_and ?spec_and: spec_atom (_AND spec_atom)+ | spec_atom ?spec_atom: "(" spec_expr ")" | spec // A spec includes name, arguments and potentially members access. // Example members: .Finished(), .action spec: spec_name [classic_arguments | simple_arguments] (spec_member)* [capture_ref] | "(" spec_name [classic_arguments | simple_arguments] ")" (spec_member)* [capture_ref] | var_name (spec_member)* [capture_ref] spec_member: "." name [classic_arguments] // Classic arguments use the syntax from python classic_arguments: "(" [_argvalues] ")" _argvalues: argvalue ("," argvalue)* argvalue: expr | name "=" expr // A simplified version of the arguments without parenthesis and "," simple_arguments: simple_argvalue+ ?simple_argvalue: expr | var_name "=" expr // Compound statements ?compound_stmt: if_stmt | while_stmt | when_stmt while_stmt: "while" test [":"] suite if_stmt: _IF test [":"] suite elifs ["else" [":"] suite] elifs: elif_* elif_: _ELSE_IF test [":"] suite when_stmt: "when" spec_expr [":"] suite orwhens ["else" [":"] suite] orwhens: orwhen_* orwhen_: _OR_WHEN spec_expr [":"] suite // -------------------------------- // Test expression (used both for conditions and assignment) test: or_test ?or_test: and_test (_OR and_test)* ?and_test: not_test_ (_AND not_test_)* ?not_test_: _NOT not_test_ -> not_test | comparison ?comparison: expr (comp_op expr)* star_expr: "*" expr expr: or_expr ?or_expr: xor_expr ("|" xor_expr)* ?xor_expr: and_expr ("^" and_expr)* ?and_expr: shift_expr ("&" shift_expr)* ?shift_expr: arith_expr (_shift_op arith_expr)* ?arith_expr: term (_add_op term)* ?term: factor (_mul_op factor)* ?factor: _unary_op factor | power !_unary_op: "+"|"-"|"~" !_add_op: "+"|"-" !_shift_op: "<<"|">>" !_mul_op: "*"|"@"|"/"|"%"|"//" !comp_op: "<"|">"|"=="|">="|"<="|"<>"|"!="|_IN|_NOT _IN|_IS|_IS _NOT ?power: atom_expr ("**" factor)? ?atom_expr: name "(" [arguments] ")" -> funccall | atom_expr "[" subscriptlist "]" -> getitem | atom_expr "." attr_name -> getattr | atom_expr "." method_name "(" [arguments] ")" -> method | "[" _exprlist? "]" -> list | "{" _dict_exprlist? "}" -> dict | "{" _exprlist "}" -> set | atom _exprlist: atom_expr ("," atom_expr)* [","] _dict_exprlist: (key_value | "**" expr) ("," (key_value | "**" expr))* [","] key_value: test ":" test arguments: argvalue ("," argvalue)* ("," [ starargs | kwargs])? | starargs | kwargs starargs: stararg ("," stararg)* ("," argvalue)* ["," kwargs] stararg: "*" test kwargs: "**" test ("," argvalue)* ?subscriptlist: subscript | subscript (("," subscript)+ [","] | ",") -> subscript_tuple ?subscript: test | ([test] ":" [test] [sliceop]) -> slice sliceop: ":" [test] // Setting the priority for this rule is important! // When using a variable in the right side of an assignment, it will be considered an expression // rather than a spec (both expressions and specs can be just a variable). ?atom: var_name -> var | number | string | doc_string | "None" -> const_none | "True" -> const_true | "False" -> const_false spec_name: name+ | "(" name+ ")" // -------------------------------- name: NAME attr_name: NAME decorator_name: NAME method_name: NAME var_name: VAR_NAME package_name: NAME ("." NAME)* comment: COMMENT // Primitive types // TODO: add more primitive types number: DEC_NUMBER | FLOAT_NUMBER string: STRING doc_string: LONG_STRING // -------------------------------- // LEXER rules below // High priority keywords // TODO: Create a positive lookbehind for whitespace characters: e.g. with /(?<=\s) _FLOW.1: /(?