KCL Spec
词法规则
关键字和保留字
下面是 KCL 语言的关键字:
    True       False      None        Undefined   import
    and        or         in          is          not
    as         if         else        elif        for
    schema     mixin      protocol    check       assert
    all        any        map         filter      lambda
    rule
下面是 KCL 语言的保留字:
    pass       return     validate   rule        flow
    def        del        raise      except      try
    finally    while      from       with        yield
    global     nonlocal   struct     class       final
行注释
# a comment
运算符
    +       -       *       **      /       //      %
    <<      >>      &       |       ^       <       >
    ~       <=      >=      ==      !=      =
    +=      -=      *=      **=     /=      //=     %=
    <<=     >>=     &=      ^=
分隔符
    (       )       [       ]       {       }
    ,       :       .       ;       @
运算符的优先级
以下的运算符列表根据优先级从 高到底 排列:
| Operator | Description | 
|---|---|
** | Exponentiation (highest priority) | 
+x -x ~x | Positive, negative, bitwise NOT | 
* / % // | Multiplication, division, floor division and remainder | 
+ - | Addition and subtraction | 
<< >> | Left and right shifts | 
& | Bitwise AND | 
^ | Bitwise XOR | 
| ` | ` | 
in, not in, is, is not, <, <=, >, >=, !=, == | Comparisons, including membership and identity operators | 
not | Boolean NOT | 
and | Boolean AND | 
or | Boolean OR | 
if – else | Conditional expression = | 
=, +=, -=, *=, /=, %=, &=, ` | =, ^=, **=, //=, <<=, >>=` | 
EBNF 语法
KCL 采用 Python 的 LarkParser 工具描述语法,规范规则如下:
// Copyright 2021 The KCL Authors. All rights reserved.
//////////// KCL grammar ////////////
start: (NEWLINE | preamble_statement)*
//////////// statement ////////////
preamble_statement: preamble_small_stmt | preamble_compound_stmt
preamble_small_stmt: (small_stmt | import_stmt) NEWLINE
preamble_compound_stmt: compound_stmt | schema_stmt
statement: small_stmt NEWLINE | compound_stmt
compound_stmt: if_stmt
small_stmt: assign_stmt | expr_stmt | assert_stmt
//////////// import_stmt ////////////
import_stmt: IMPORT dot_name (AS NAME)?
dot_name: [leading_dots] identifier (DOT identifier)*
leading_dots: DOT+
/////////// assert_stmt ////////////
assert_stmt: ASSERT test (COMMA test)?
//////////// if_stmt ////////////
if_stmt: IF test COLON suite (ELIF test COLON suite)* (ELSE COLON suite)?
suite: small_stmt NEWLINE | NEWLINE _INDENT statement+ _DEDENT
//////////// assign_stmt ////////////
assign_stmt: primary_expr (ASSIGN primary_expr)* ASSIGN test
    | primary_expr augassign test
augassign: COMP_PLUS | COMP_MINUS | COMP_MULTIPLY | COMP_DOUBLE_STAR | COMP_DIVIDE
    | COMP_DOUBLE_DIVIDE | COMP_MOD | COMP_AND | COMP_OR | COMP_XOR | COMP_SHIFT_LEFT
    | COMP_SHIFT_RIGHT
//////////// schema_stmt ////////////
schema_stmt: [decorators] SCHEMA [RELAXED] identifier [LEFT_BRACKETS [arguments] RIGHT_BRACKETS] [LEFT_PARENTHESES operand_name RIGHT_PARENTHESES] COLON NEWLINE [schema_body]
schema_body: _INDENT (string NEWLINE)* [mixin_stmt] (schema_attribute_stmt | statement)* [check_block] _DEDENT
schema_attribute_stmt: [decorators] (FINAL)? identifier COLON type [(ASSIGN | augassign) test] NEWLINE
/////////// decorators ////////////
decorators: (AT primary_expr NEWLINE)+
//////////// type ////////////
type: type_element (OR type_element)*
type_element: schema_type | basic_type | compound_type
schema_type: operand_name
basic_type: STRING_TYPE | INT_TYPE | FLOAT_TYPE | BOOL_TYPE
compound_type: list_type | dict_type
list_type: LEFT_BRACKETS (type)? RIGHT_BRACKETS
dict_type: LEFT_BRACE (type)? COLON (type)? RIGHT_BRACE
//////////// check_block ////////////
check_block: CHECK COLON NEWLINE _INDENT check_expr+ _DEDENT
check_expr: check_test [COMMA primary_expr] NEWLINE
check_test: or_test [IF or_test]
//////////// mixin_stmt ////////////
mixin_stmt: MIXIN LEFT_BRACKETS [mixins | multiline_mixins] RIGHT_BRACKETS NEWLINE
multiline_mixins: NEWLINE _INDENT mixins NEWLINE _DEDENT
mixins: operand_name (COMMA (NEWLINE mixins | operand_name))*
//////////// expression_stmt ////////////
expr_stmt: expression
expression: test (COMMA test)*
test: if_expr | primary_expr | unary_expr | binary_expr
if_expr: test IF test ELSE test
unary_expr: (PLUS | MINUS | NOT) primary_expr | L_NOT test
binary_expr: test bin_op test
bin_op: L_OR
      | L_AND
      | EQUAL_TO | NOT_EQUAL_TO | LESS_THAN | GREATER_THAN | LESS_THAN_OR_EQUAL_TO | GREATER_THAN_OR_EQUAL_TO 
      | IN | L_NOT IN | IS | IS L_NOT
      | OR
      | XOR
      | AND
      | MINUS | PLUS
      | MULTIPLY | MOD | DIVIDE | DOUBLE_DIVIDE
      | SHIFT_LEFT | SHIFT_RIGHT
primary_expr: operand | primary_expr select_suffix | primary_expr call_suffix | primary_expr subscript_suffix | primary_expr schema_expr
operand: operand_name | number | string
    | TRUE | FALSE | NONE | list_expr | list_comp | dict_expr
    | dict_comp | LEFT_PARENTHESES test RIGHT_PARENTHESES
operand_name: identifier | qualified_identifier
select_suffix: DOT (identifier | dict_identifier_selector | list_identifier_selector)
dict_identifier_selector: MULTIPLY | LEFT_BRACE identifier (COMMA identifier)* RIGHT_BRACE
list_identifier_selector: subscript_suffix
//////////// call_suffix ////////////
call_suffix: LEFT_PARENTHESES [arguments [COMMA]] RIGHT_PARENTHESES
//////////// subscript_suffix ////////////
subscript_suffix: LEFT_BRACKETS (test | [test] COLON [test] [COLON [test]]) RIGHT_BRACKETS
//////////// arguments ////////////
arguments: argument (COMMA argument)*
argument: test | NAME ASSIGN test | MULTIPLY test | DOUBLE_STAR test
//////////// operand ////////////
identifier: NAME
qualified_identifier: identifier DOT identifier
//////////// list_expr ////////////
list_expr: LEFT_BRACKETS [list_items | NEWLINE _INDENT list_items _DEDENT] RIGHT_BRACKETS
list_items: list_item ((COMMA [NEWLINE] | NEWLINE) list_item)* [COMMA] [NEWLINE]
list_item: test | star_expr
list_comp: LEFT_BRACKETS (list_item comp_clause+ | NEWLINE _INDENT list_item comp_clause+ _DEDENT) RIGHT_BRACKETS
//////////// dict_expr ////////////
dict_expr: LEFT_BRACE [entries | NEWLINE _INDENT entries _DEDENT] RIGHT_BRACE
dict_comp: LEFT_BRACE (entry comp_clause+ | NEWLINE _INDENT entry comp_clause+ _DEDENT) RIGHT_BRACE
entries: entry ((COMMA [NEWLINE] | NEWLINE) entry)* [COMMA] [NEWLINE]
entry: test COLON test | double_star_expr
comp_clause: FOR loop_variables [COMMA] IN or_test [NEWLINE] [IF test [NEWLINE]]
star_expr: MULTIPLY primary_expr
double_star_expr: DOUBLE_STAR primary_expr
loop_variables: primary_expr (COMMA primary_expr)*
//////////// schema_expr ////////////
schema_expr: (LEFT_PARENTHESES [arguments] RIGHT_PARENTHESES)? dict_expr
//////////// misc ////////////
number: DEC_NUMBER | HEX_NUMBER | BIN_NUMBER | OCT_NUMBER | FLOAT_NUMBER | IMAG_NUMBER
string: STRING | LONG_STRING
// Tokens
ASSIGN: "="
COLON: ":"
SEMI_COLON: ";"
COMMA: ","
LEFT_PARENTHESES: "("
RIGHT_PARENTHESES: ")"
LEFT_BRACKETS: "["
RIGHT_BRACKETS: "]"
LEFT_BRACE: "{"
RIGHT_BRACE: "}"
PLUS: "+"
MINUS: "-"
MULTIPLY: "*"
DIVIDE: "/"
MOD: "%"
DOT: "."
AND: "&"
OR: "|"
XOR: "^"
NOT: "~"
LESS_THAN: "<"
GREATER_THAN: ">"
EQUAL_TO: "=="
NOT_EQUAL_TO: "!="
GREATER_THAN_OR_EQUAL_TO: ">="
LESS_THAN_OR_EQUAL_TO: "<="
DOUBLE_STAR: "**"
DOUBLE_DIVIDE: "//"
SHIFT_LEFT: "<<"
SHIFT_RIGHT: ">>"
AT: "@"
COMP_PLUS: "+="
COMP_MINUS: "-="
COMP_MULTIPLY: "*="
COMP_DIVIDE: "/="
COMP_MOD: "%="
COMP_AND: "&="
COMP_OR: "|="
COMP_XOR: "^="
COMP_DOUBLE_STAR: "**="
COMP_DOUBLE_DIVIDE: "//="
COMP_SHIFT_LEFT: "<<="
COMP_SHIFT_RIGHT: ">>="
// Special tokens
IMPORT: "import"
AS: "as"
SCHEMA: "schema"
MIXIN: "mixin"
RELAXED: "relaxed"
CHECK: "check"
FOR: "for"
ASSERT: "assert"
IF: "if"
ELIF: "elif"
ELSE: "else"
L_OR: "or"
L_AND: "and"
L_NOT: "not"
IN: "in"
IS: "is"
FINAL: "final"
LAMBDA: "lambda"
STRING_TYPE: "str"
INT_TYPE: "int"
FLOAT_TYPE: "float"
BOOL_TYPE: "bool"
// Constant tokens
TRUE: "True"
FALSE: "False"
NONE: "None"
NAME: /[a-zA-Z_]\w*/
COMMENT: /#[^\n]*/
NEWLINE: ( /\r?\n[\t ]*/ | COMMENT )+
STRING: /[ubf]?r?("(?!"").*?(?<!\\)(\\\\)*?"|'(?!'').*?(?<!\\)(\\\\)*?')/i
LONG_STRING: /[ubf]?r?(""".*?(?<!\\)(\\\\)*?"""|'''.*?(?<!\\)(\\\\)*?''')/is
DEC_NUMBER: /\-?0|\-?[1-9]\d*/i
HEX_NUMBER.2: /\-?0[xX][0-9a-fA-F]+/i
OCT_NUMBER.2: /\-?0[oO][0-7]+/i
BIN_NUMBER.2 : /\-?0[bB][0-1]+/i
FLOAT_NUMBER.2: /(([-+]?\d+\.\d*|\.\d+)(e[-+]?\d+)?|\d+(e[-+]?\d+))/i
IMAG_NUMBER.2: /\d+j/i | FLOAT_NUMBER "j"i
%ignore /[\t \f]+/  // WS
%ignore /\\[\t \f]*\r?\n/   // LINE_CONT
%declare _INDENT _DEDENT