Jac Language Reference#
Welcome to the official reference guide for the Jac programming language. This document is designed to serve as a comprehensive reference manual as well as a formal specification of the language. The mission of this guide is to be a resource for developers seeking to answer the question, "How do I code X in Jac?"
This document is organized around the formal grammar for the language code examples and corresponding grammar snippets being directly generated from the actual grammar and test cases maintained in the official repository. We expect the descriptions may occasionally lag behind the rapid evolution of Jac in the early days. If you notice something, make a pull request and join our contributor community.
Whitespace
Jac uses curly braces to delimit code blocks rather than relying on indentation. As a result, varying indentation has no effect on execution order. Developers are free to format code as they see fit while still retaining Python-style readability:
Consistent formatting is still recommended, but the compiler treats whitespace as insignificant when determining program structure.
Comments
Single-line comments begin with #
and extend to the end of the line. Jac also
supports multiline comments delimited by #*
and *#
:
Complete Language
Full Jac Language Grammar
// [Heading]: Base Module structure.
start: module
module: (toplevel_stmt (tl_stmt_with_doc | toplevel_stmt)*)?
| STRING (tl_stmt_with_doc | toplevel_stmt)*
tl_stmt_with_doc: STRING toplevel_stmt
toplevel_stmt: KW_CLIENT? onelang_stmt
| KW_CLIENT LBRACE onelang_stmt* RBRACE
| py_code_block
onelang_stmt: import_stmt
| archetype
| ability
| global_var
| free_code
| test
| impl_def
| sem_def
// [Heading]: Import/Include Statements.
import_stmt: KW_IMPORT KW_FROM from_path LBRACE import_items RBRACE
| KW_IMPORT import_path (COMMA import_path)* SEMI
| KW_INCLUDE import_path SEMI
from_path: (DOT | ELLIPSIS)* import_path
| (DOT | ELLIPSIS)+
import_path: dotted_name (KW_AS NAME)?
import_items: (import_item COMMA)* import_item COMMA?
import_item: named_ref (KW_AS NAME)?
dotted_name: named_ref (DOT named_ref)*
// [Heading]: Class Archetypes.
archetype: decorators? KW_ASYNC? archetype_decl
| enum
archetype_decl: arch_type access_tag? NAME inherited_archs? (member_block | SEMI)
decorators: (DECOR_OP atomic_chain)+
access_tag: COLON ( KW_PROT | KW_PUB | KW_PRIV )
inherited_archs: LPAREN (atomic_chain COMMA)* atomic_chain RPAREN
arch_type: KW_WALKER
| KW_OBJECT
| KW_EDGE
| KW_NODE
| KW_CLASS
// [Heading]: Class Archetype bodies.
member_block: LBRACE member_stmt* RBRACE
member_stmt: STRING? (py_code_block | ability | archetype | impl_def | has_stmt | free_code)
has_stmt: KW_STATIC? (KW_LET | KW_HAS) access_tag? has_assign_list SEMI
has_assign_list: (has_assign_list COMMA)? typed_has_clause
typed_has_clause: named_ref type_tag (EQ expression | KW_BY KW_POST_INIT)?
type_tag: COLON expression
// [Heading]: Enumerations.
enum: decorators? enum_decl
enum_decl: KW_ENUM access_tag? NAME inherited_archs? (enum_block | SEMI)
enum_block: LBRACE assignment_list (py_code_block | free_code)* RBRACE
// [Heading]: Functions and Abilities.
ability: decorators? KW_ASYNC? (ability_decl | function_decl)
function_decl: KW_OVERRIDE? KW_STATIC? KW_DEF access_tag? named_ref func_decl? (block_tail | KW_ABSTRACT? SEMI)
ability_decl: KW_OVERRIDE? KW_STATIC? KW_CAN access_tag? named_ref event_clause (block_tail | KW_ABSTRACT? SEMI)
block_tail: code_block | KW_BY expression SEMI
event_clause: KW_WITH expression? (KW_EXIT | KW_ENTRY)
func_decl: (LPAREN func_decl_params? RPAREN) (RETURN_HINT expression)?
| (RETURN_HINT expression)
func_decl_params: (param_var COMMA)* param_var COMMA?
param_var: (STAR_POW | STAR_MUL)? named_ref type_tag (EQ expression)?
| DIV
| STAR_MUL
// [Heading]: Implementations.
impl_def: decorators? KW_IMPL dotted_name impl_spec? impl_tail
impl_spec: inherited_archs | func_decl | event_clause
impl_tail: enum_block | block_tail
// [Heading]: Semstrings.
sem_def: KW_SEM dotted_name (EQ | KW_IS) STRING SEMI
// [Heading]: Global variables.
global_var: (KW_LET | KW_GLOBAL) access_tag? assignment_list SEMI
assignment_list: (assignment | named_ref) (COMMA (assignment | named_ref))* COMMA?
// [Heading]: With entry blocks.
free_code: KW_WITH KW_ENTRY (COLON NAME)? code_block
// [Heading]: Inline python.
py_code_block: PYNLINE
// [Heading]: Tests.
test: KW_TEST NAME? code_block
// [Heading]: Codeblocks and Statements.
code_block: LBRACE statement* RBRACE
statement: import_stmt
| ability
| has_stmt
| archetype
| impl_def
| if_stmt
| while_stmt
| for_stmt
| try_stmt
| match_stmt
| with_stmt
| global_ref SEMI
| nonlocal_ref SEMI
| typed_ctx_block
| return_stmt SEMI
| (yield_expr | KW_YIELD) SEMI
| raise_stmt SEMI
| assert_stmt SEMI
| assignment SEMI
| delete_stmt SEMI
| report_stmt SEMI
| expression SEMI
| ctrl_stmt SEMI
| py_code_block
| spatial_stmt
| SEMI
// [Heading]: If statements.
if_stmt: KW_IF expression code_block (elif_stmt | else_stmt)?
elif_stmt: KW_ELIF expression code_block (elif_stmt | else_stmt)?
else_stmt: KW_ELSE code_block
// [Heading]: While statements.
while_stmt: KW_WHILE expression code_block else_stmt?
// [Heading]: For statements.
for_stmt: KW_ASYNC? KW_FOR assignment KW_TO expression KW_BY assignment code_block else_stmt?
| KW_ASYNC? KW_FOR atomic_chain KW_IN expression code_block else_stmt?
// [Heading]: Try statements.
try_stmt: KW_TRY code_block except_list? else_stmt? finally_stmt?
except_list: except_def+
except_def: KW_EXCEPT expression (KW_AS NAME)? code_block
finally_stmt: KW_FINALLY code_block
// [Heading]: Match statements.
match_stmt: KW_MATCH expression LBRACE match_case_block+ RBRACE
match_case_block: KW_CASE pattern_seq (KW_IF expression)? COLON statement+
pattern_seq: (or_pattern | as_pattern)
or_pattern: (pattern BW_OR)* pattern
as_pattern: or_pattern KW_AS NAME
pattern: literal_pattern
| singleton_pattern
| capture_pattern
| sequence_pattern
| mapping_pattern
| attr_pattern
| class_pattern
literal_pattern: (INT | FLOAT | multistring)
singleton_pattern: (NULL | BOOL)
capture_pattern: NAME
sequence_pattern: LSQUARE list_inner_pattern (COMMA list_inner_pattern)* RSQUARE
| LPAREN list_inner_pattern (COMMA list_inner_pattern)* RPAREN
mapping_pattern: LBRACE (dict_inner_pattern (COMMA dict_inner_pattern)*)? RBRACE
list_inner_pattern: (pattern_seq | STAR_MUL NAME)
dict_inner_pattern: (literal_pattern COLON pattern_seq | STAR_POW NAME)
attr_pattern: NAME (DOT NAME)+
class_pattern: NAME (DOT NAME)* LPAREN kw_pattern_list? RPAREN
| NAME (DOT NAME)* LPAREN pattern_list (COMMA kw_pattern_list)? RPAREN
pattern_list: (pattern_list COMMA)? pattern_seq
kw_pattern_list: (kw_pattern_list COMMA)? named_ref EQ pattern_seq
// [Heading]: Context managers.
with_stmt: KW_ASYNC? KW_WITH expr_as_list code_block
expr_as_list: (expr_as COMMA)* expr_as
expr_as: expression (KW_AS expression)?
// [Heading]: Global and nonlocal statements.
global_ref: GLOBAL_OP name_list
nonlocal_ref: NONLOCAL_OP name_list
name_list: (named_ref COMMA)* named_ref
// [Heading]: Typed context blocks (OSP).
typed_ctx_block: RETURN_HINT expression code_block
// [Heading]: Return statements.
return_stmt: KW_RETURN expression?
// [Heading]: Yield statements.
yield_expr: KW_YIELD KW_FROM? expression
// [Heading]: Raise statements.
raise_stmt: KW_RAISE (expression (KW_FROM expression)?)?
// [Heading]: Assert statements.
assert_stmt: KW_ASSERT expression (COMMA expression)?
// [Heading]: Delete statements.
delete_stmt: KW_DELETE expression
// [Heading]: Report statements.
report_stmt: KW_REPORT expression
// [Heading]: Control statements.
ctrl_stmt: KW_SKIP | KW_BREAK | KW_CONTINUE
// [Heading]: Walker visit and disengage (OSP).
spatial_stmt: visit_stmt | disenage_stmt
visit_stmt: KW_VISIT (COLON expression COLON)? expression (else_stmt | SEMI)
disenage_stmt: KW_DISENGAGE SEMI
// [Heading]: Assignments.
assignment: KW_LET? (atomic_chain EQ)+ (yield_expr | expression)
| atomic_chain type_tag (EQ (yield_expr | expression))?
| atomic_chain aug_op (yield_expr | expression)
aug_op: RSHIFT_EQ
| LSHIFT_EQ
| BW_XOR_EQ
| BW_OR_EQ
| BW_AND_EQ
| MOD_EQ
| DIV_EQ
| FLOOR_DIV_EQ
| MUL_EQ
| SUB_EQ
| ADD_EQ
| MATMUL_EQ
| STAR_POW_EQ
// [Heading]: Expressions.
expression: concurrent_expr (KW_IF expression KW_ELSE expression)?
| lambda_expr
// [Heading]: Concurrent expressions.
concurrent_expr: (KW_FLOW | KW_WAIT)? walrus_assign
// [Heading]: Walrus assignments.
walrus_assign: (named_ref WALRUS_EQ)? pipe
// [Heading]: Lambda expressions.
lambda_expr: KW_LAMBDA func_decl_params (RETURN_HINT expression)? ( COLON expression | code_block )
| KW_LAMBDA func_decl? ( COLON expression | code_block )
// [Heading]: Pipe expressions.
pipe: (pipe PIPE_FWD)? pipe_back
// [Heading]: Pipe back expressions.
pipe_back: (pipe_back PIPE_BKWD)? bitwise_or
// [Heading]: Bitwise expressions.
bitwise_or: (bitwise_or BW_OR)? bitwise_xor
bitwise_xor: (bitwise_xor BW_XOR)? bitwise_and
bitwise_and: (bitwise_and BW_AND)? shift
shift: (shift (RSHIFT | LSHIFT))? logical_or
// [Heading]: Logical and compare expressions.
logical_or: logical_and (KW_OR logical_and)*
logical_and: logical_not (KW_AND logical_not)*
logical_not: NOT logical_not | compare
compare: (arithmetic cmp_op)* arithmetic
cmp_op: KW_ISN
| KW_IS
| KW_NIN
| KW_IN
| NE
| GTE
| LTE
| GT
| LT
| EE
// [Heading]: Arithmetic expressions.
arithmetic: (arithmetic (MINUS | PLUS))? term
term: (term (MOD | DIV | FLOOR_DIV | STAR_MUL | DECOR_OP))? power
power: (power STAR_POW)? factor
factor: (BW_NOT | MINUS | PLUS) factor | connect
// [Heading]: Connect expressions (OSP).
connect: (connect (connect_op | disconnect_op))? atomic_pipe
// [Heading]: Pipe atomic expressions.
atomic_pipe: (atomic_pipe A_PIPE_FWD)? atomic_pipe_back
// [Heading]: Pipe back atomic expressions.
atomic_pipe_back: (atomic_pipe_back A_PIPE_BKWD)? os_spawn
// [Heading]: Spawn expressions (OSP).
os_spawn: (os_spawn KW_SPAWN)? unpack
// [Heading]: Unpack expressions.
unpack: STAR_MUL? ref
// [Heading]: References (OSP).
ref: BW_AND? await_expr
// [Heading]: Pipe-style function call.
await_expr: KW_AWAIT? pipe_call
pipe_call: (PIPE_FWD | A_PIPE_FWD | KW_SPAWN)? atomic_chain
// [Heading]: Attributes and Subscript expressions.
atomic_chain: atomic_chain NULL_OK? (filter_compr | assign_compr | index_slice)
| atomic_chain NULL_OK? (DOT_BKWD | DOT_FWD | DOT) named_ref
| (atomic_call | atom | edge_ref_chain)
index_slice: LSQUARE \
expression? COLON expression? (COLON expression?)? \
(COMMA expression? COLON expression? (COLON expression?)?)* \
RSQUARE
| list_val
// [Heading]: Function calls.
atomic_call: atomic_chain (gen_compr | LPAREN param_list? by_llm? RPAREN)
by_llm: KW_BY expression
param_list: expr_list COMMA kw_expr_list COMMA?
| kw_expr_list COMMA?
| expr_list COMMA?
// [Heading]: Atomic expressions.
atom: named_ref
| LPAREN (expression | yield_expr | function_decl) RPAREN
| atom_collection
| atom_literal
| type_ref
| jsx_element
atom_literal: builtin_type
| NULL
| BOOL
| multistring
| ELLIPSIS
| FLOAT
| OCT
| BIN
| HEX
| INT
type_ref: TYPE_OP (named_ref | builtin_type)
multistring: (fstring | STRING)+
// [Heading]: Formatted string literals.
fstring: F_DQ_START fstr_dq_part* F_DQ_END
| F_SQ_START fstr_sq_part* F_SQ_END
| F_TDQ_START fstr_tdq_part* F_TDQ_END
| F_TSQ_START fstr_tsq_part* F_TSQ_END
| RF_DQ_START rfstr_dq_part* F_DQ_END
| RF_SQ_START rfstr_sq_part* F_SQ_END
| RF_TDQ_START rfstr_tdq_part* F_TDQ_END
| RF_TSQ_START rfstr_tsq_part* F_TSQ_END
fstr_dq_part: F_TEXT_DQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE
fstr_sq_part: F_TEXT_SQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE
fstr_tdq_part: F_TEXT_TDQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE
fstr_tsq_part: F_TEXT_TSQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE
// Add separate rules for raw f-strings
rfstr_dq_part: RF_TEXT_DQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE
rfstr_sq_part: RF_TEXT_SQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE
rfstr_tdq_part: RF_TEXT_TDQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE
rfstr_tsq_part: RF_TEXT_TSQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE
fformat: F_FORMAT_TEXT | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE
// [Heading]: Collection values.
atom_collection: dict_compr
| set_compr
| gen_compr
| list_compr
| dict_val
| set_val
| tuple_val
| list_val
list_compr: LSQUARE expression inner_compr+ RSQUARE
gen_compr: LPAREN expression inner_compr+ RPAREN
set_compr: LBRACE expression inner_compr+ RBRACE
dict_compr: LBRACE kv_pair inner_compr+ RBRACE
inner_compr: KW_ASYNC? KW_FOR atomic_chain KW_IN pipe_call (KW_IF walrus_assign)*
dict_val: LBRACE ((kv_pair COMMA)* kv_pair COMMA?)? RBRACE
list_val: LSQUARE (expr_list COMMA?)? RSQUARE
tuple_val: LPAREN tuple_list? RPAREN
set_val: LBRACE expr_list COMMA? RBRACE
kv_pair: expression COLON expression | STAR_POW expression
expr_list: (expr_list COMMA)? expression
tuple_list: expression COMMA expr_list COMMA kw_expr_list COMMA?
| expression COMMA kw_expr_list COMMA?
| expression COMMA expr_list COMMA?
| expression COMMA
| kw_expr_list COMMA?
kw_expr_list: (kw_expr_list COMMA)? kw_expr
kw_expr: named_ref EQ expression | STAR_POW expression
// [Heading]: Edge references (OSP).
edge_ref_chain: LSQUARE KW_ASYNC? (KW_NODE| KW_EDGE)? expression? (edge_op_ref (filter_compr | expression)?)+ RSQUARE
edge_op_ref: edge_any | edge_from | edge_to
edge_to: ARROW_R | ARROW_R_P1 typed_filter_compare_list ARROW_R_P2
edge_from: ARROW_L | ARROW_L_P1 typed_filter_compare_list ARROW_L_P2
edge_any: ARROW_BI | ARROW_L_P1 typed_filter_compare_list ARROW_R_P2
connect_op: connect_from | connect_to | connect_any
disconnect_op: KW_DELETE edge_op_ref
connect_to: CARROW_R | CARROW_R_P1 expression (COLON kw_expr_list)? CARROW_R_P2
connect_from: CARROW_L | CARROW_L_P1 expression (COLON kw_expr_list)? CARROW_L_P2
connect_any: CARROW_BI | CARROW_L_P1 expression (COLON kw_expr_list)? CARROW_R_P2
// [Heading]: Filter and assign comprehensions.
filter_compr: LPAREN NULL_OK filter_compare_list RPAREN
| LPAREN TYPE_OP NULL_OK typed_filter_compare_list RPAREN
assign_compr: LPAREN EQ kw_expr_list RPAREN
filter_compare_list: (filter_compare_list COMMA)? filter_compare_item
typed_filter_compare_list: expression (COLON filter_compare_list)?
filter_compare_item: named_ref cmp_op expression
// [Heading]: Names and references.
named_ref: special_ref
| KWESC_NAME
| NAME
special_ref: KW_INIT
| KW_POST_INIT
| KW_ROOT
| KW_SUPER
| KW_SELF
| KW_HERE
| KW_VISITOR
// [Heading]: JSX Elements.
jsx_element: jsx_self_closing
| jsx_fragment
| jsx_opening_closing
jsx_self_closing: JSX_OPEN_START jsx_element_name jsx_attributes? JSX_SELF_CLOSE
jsx_opening_closing: jsx_opening_element jsx_children? jsx_closing_element
jsx_fragment: JSX_FRAG_OPEN jsx_children? JSX_FRAG_CLOSE
jsx_opening_element: JSX_OPEN_START jsx_element_name jsx_attributes? JSX_TAG_END
jsx_closing_element: JSX_CLOSE_START jsx_element_name JSX_TAG_END
jsx_element_name: JSX_NAME (DOT JSX_NAME)*
jsx_attributes: jsx_attribute+
jsx_attribute: jsx_spread_attribute | jsx_normal_attribute
jsx_spread_attribute: LBRACE ELLIPSIS expression RBRACE
jsx_normal_attribute: JSX_NAME (EQ jsx_attr_value)?
jsx_attr_value: STRING
| LBRACE expression RBRACE
jsx_children: jsx_child+
jsx_child: jsx_element
| jsx_expression
| jsx_text
jsx_expression: LBRACE expression RBRACE
jsx_text: JSX_TEXT
// [Heading]: Builtin types.
builtin_type: TYP_TYPE
| TYP_ANY
| TYP_BOOL
| TYP_DICT
| TYP_SET
| TYP_TUPLE
| TYP_LIST
| TYP_FLOAT
| TYP_INT
| TYP_BYTES
| TYP_STRING
// ************************************************************************* //
// Terminals //
// ************************************************************************* //
PYNLINE: /::py::(.|\n|\r)*?::py::/
TYPE_OP: /`/
GLOBAL_OP: "global"
NONLOCAL_OP: "nonlocal"
RETURN_HINT: "->"
NULL_OK: "?"
COLON: ":"
SEMI: ";"
ELLIPSIS: "..."
DOT: "."
COMMA: ","
LBRACE: "{"
RBRACE: "}"
LPAREN: "("
RPAREN: ")"
LSQUARE: "["
RSQUARE: "]"
// TODO:AST: These should be just NAME for tokenizer and the parser (or even higher)
// Should treat them as type names.
// [Heading]: Lexer Tokens.
TYP_STRING: "str"
TYP_INT: "int"
TYP_FLOAT: "float"
TYP_LIST: "list"
TYP_TUPLE: "tuple"
TYP_SET: "set"
TYP_DICT: "dict"
TYP_BOOL: "bool"
TYP_BYTES: "bytes"
TYP_ANY: "any"
TYP_TYPE: "type"
// Keywords ---------------------------------------------------------------- //
KW_LET: "let"
KW_ABSTRACT: "abs"
KW_CLASS: "class"
KW_OBJECT: "obj"
KW_ENUM: "enum"
KW_NODE: "node"
KW_VISIT: "visit"
KW_SPAWN: "spawn"
KW_WITH: "with"
KW_LAMBDA: "lambda"
KW_ENTRY: "entry"
KW_EXIT: "exit"
KW_IMPORT: "import"
KW_INCLUDE: "include"
KW_FROM: "from"
KW_AS: "as"
KW_EDGE: "edge"
KW_WALKER: "walker"
KW_ASYNC: "async"
KW_AWAIT: "await"
KW_FLOW: "flow"
KW_WAIT: "wait"
KW_TEST: "test"
KW_IMPL: "impl"
KW_SEM: "sem"
KW_ASSERT: "assert"
KW_IF: "if"
KW_ELIF: "elif"
KW_ELSE: "else"
KW_FOR: "for"
KW_TO: "to"
KW_BY: "by"
KW_WHILE: "while"
KW_CONTINUE: "continue"
KW_BREAK: "break"
KW_DISENGAGE: "disengage"
KW_YIELD: "yield"
KW_SKIP: "skip"
KW_REPORT: "report"
KW_RETURN: "return"
KW_DELETE: "del"
KW_TRY: "try"
KW_EXCEPT: "except"
KW_FINALLY: "finally"
KW_RAISE: "raise"
KW_IN: "in"
KW_IS: "is"
KW_PRIV: "priv"
KW_PUB: "pub"
KW_PROT: "protect"
KW_HAS: "has"
KW_GLOBAL: "glob"
KW_CAN: "can"
KW_DEF: "def"
KW_STATIC: "static"
KW_OVERRIDE: "override"
KW_MATCH: "match"
KW_CASE: "case"
KW_CLIENT: "cl"
KW_INIT: "init"
KW_POST_INIT: "postinit"
KW_HERE: "here"
KW_VISITOR: "visitor"
KW_SELF: "self"
KW_SUPER: "super"
KW_ROOT: "root"
KW_NIN.1: /\bnot\s+in\b/
KW_ISN.1: /\bis\s+not\b/
KW_AND.1: /&&|and/
KW_OR.1: /\|\||or/
NOT: "not" // TODO:AST: Rename to KW_NOT
// Literals ---------------------------------------------------------------- //
STRING: /(r?b?|b?r?)("[^"\r\n]*"|'[^'\r\n]*')/
| /(r?b?|b?r?)("""(.|\r|\n)*?"""|'''(.|\r|\n)*?''')/
RF_DQ_START.3: /[rR][fF]"|[fF][rR]"/
RF_SQ_START.3: /[rR][fF]'|[fF][rR]'/
RF_TDQ_START.3: /[rR][fF]"""|[fF][rR]"""/
RF_TSQ_START.3: /[rR][fF]'''|[fF][rR]'''/
F_DQ_START.2: /[fF]"/
F_SQ_START.2: /[fF]'/
F_TDQ_START.2: /[fF]"""/
F_TSQ_START.2: /[fF]'''/
F_DQ_END: "\""
F_SQ_END: "'"
F_TDQ_END: "\"\"\""
F_TSQ_END: "'''"
D_RBRACE: "}}"
D_LBRACE: "{{"
F_TEXT_DQ.-1: /[^"{}\n\\]+|\\./
F_TEXT_SQ.-1: /[^'{}\n\\]+|\\./
F_TEXT_TDQ.-1: /(?:[^"{}\\]|"(?!""))+|\\./s
F_TEXT_TSQ.-1: /(?:[^'{}\\]|'(?!''))+|\\./s
RF_TEXT_DQ.-1: /[^"{}]+/
RF_TEXT_SQ.-1: /[^'{}]+/
RF_TEXT_TDQ.-1: /(?:[^"{}]|"(?!""))+/s
RF_TEXT_TSQ.-1: /(?:[^'{}]|'(?!''))+/s
F_FORMAT_TEXT.-1: /[^{}]+/
CONV: /![rRsSaA]/
NULL.1: "None"
BOOL.1: /True|False/
FLOAT: /(\d+(\.\d*)|\.\d+)([eE][+-]?\d+)?|\d+([eE][-+]?\d+)/
HEX.1: /0[xX][0-9a-fA-F_]+/
BIN.1: /0[bB][01_]+/
OCT.1: /0[oO][0-7_]+/
INT: /[0-9][0-9_]*/
// Identifier -------------------------------------------------------------- //
KWESC_NAME: /<>[a-zA-Z_][a-zA-Z0-9_]*/
NAME: /[a-zA-Z_][a-zA-Z0-9_]*/
// Object-Spatial Operators -------------------------------------------------- //
ARROW_BI: "<-->"
ARROW_L: "<--"
ARROW_R: "-->"
ARROW_L_P1: "<-:"
ARROW_R_P2: ":->"
ARROW_L_P2: ":<-"
ARROW_R_P1: "->:"
CARROW_BI: "<++>"
CARROW_L: "<++"
CARROW_R: "++>"
CARROW_L_P1: "<+:"
CARROW_R_P2: ":+>"
CARROW_L_P2: ":<+"
CARROW_R_P1: "+>:"
// Assignment Operator ----------------------------------------------------- //
EQ: "="
WALRUS_EQ: ":="
ADD_EQ: "+="
SUB_EQ: "-="
MUL_EQ: "*="
DIV_EQ: "/="
MOD_EQ: "%="
MATMUL_EQ: "@="
STAR_POW_EQ: "**="
FLOOR_DIV_EQ: "//="
BW_AND_EQ: "&="
BW_OR_EQ: "|="
BW_XOR_EQ: "^="
LSHIFT_EQ: "<<="
RSHIFT_EQ: ">>="
// Arithmatic -------------------------------------------------------------- //
EE: "=="
LT: "<"
GT: ">"
LTE: "<="
GTE: ">="
NE: "!="
PLUS: "+"
MINUS: "-"
STAR_MUL: "*"
DIV: "/"
MOD: "%"
STAR_POW: "**"
FLOOR_DIV: "//"
DECOR_OP: "@"
BW_AND: "&"
BW_OR: "|"
BW_XOR: "^"
BW_NOT: "~"
LSHIFT: "<<"
RSHIFT: ">>"
// Other Operator ---------------------------------------------------------- //
A_PIPE_FWD: ":>"
A_PIPE_BKWD: "<:"
PIPE_FWD: "|>"
PIPE_BKWD: "<|"
DOT_FWD: ".>"
DOT_BKWD: "<."
// JSX Contextual Tokens --------------------------------------------------- //
// JSX opening tag start: < followed by identifier or uppercase
// Using lower priority so it doesn't interfere with LT operator
JSX_OPEN_START.2: /<(?=[A-Z_a-z])/
// JSX self-closing end: />
JSX_SELF_CLOSE: /\/>/
// JSX tag end: > (used for both opening and closing)
JSX_TAG_END: />/
// JSX closing tag start: </
JSX_CLOSE_START: /<\//
// JSX fragment open: <>
JSX_FRAG_OPEN: /<>/
// JSX fragment close: </>
JSX_FRAG_CLOSE: /<\/>/
// JSX identifier (NAME in JSX context) - allows hyphens for attributes like data-age, aria-label
JSX_NAME: /[A-Z_a-z][A-Z_a-z0-9\-]*/
// JSX text content (anything except < > { } and must not start/end with whitespace-only)
// Using negative priority so it's only matched as last resort within JSX
JSX_TEXT.-1: /[^<>{}\n]+/
// ************************************************************************* //
// Comments and Whitespace //
// ************************************************************************* //
COMMENT.4: /#\*(.|\n|\r)*?\*#|#.*/
WS.-2: /[ \t\f\r\n]/+
%ignore COMMENT
%ignore WS