Signed-off-by: erick-alcachofa <erick@artichoke.dev> This commit lays the foundational groundwork for the artichoke language parser by introducing the formal language grammar specification. The tokenizer was updated to include new operators and keywords, also added the posibility to handle comments. Key Additions: - Implemented support for C-style block comments (`/* ... */`), including error handling for unclosed comments. - Added all necessary tokens for missing keywords (e.g., `module`, `export`, `using`, `match`, `loop`) and operators (e.g., `+=`, `:=`, `.#`, `.*`, `.@`). - The `Token` enum has been expanded to reflect the full language feature set. Documentation: - Added `docs/grammar.ebnf` which contains the official, well-structured EBNF grammar for the language. - Added `docs/readme.md` providing a detailed technical overview of the language's features, syntax, and semantics. BREAKING CHANGE: The `kwVariant` and `kwMut` tokens have been removed to align with the updated language design defined in the new grammar.
349 lines
8.3 KiB
EBNF
349 lines
8.3 KiB
EBNF
/*
|
|
================================================================================
|
|
| |
|
|
| The Artichoke Programming Language |
|
|
| Official EBNF Grammar |
|
|
| |
|
|
================================================================================
|
|
*/
|
|
|
|
|
|
/* --- Program Structure --- */
|
|
/* A program is a sequence of top-level declarations and statements. */
|
|
|
|
<program> =
|
|
( <import_statement>
|
|
| <module_statement>
|
|
| <alias_statement>
|
|
| <struct_declaration>
|
|
| <enum_declaration>
|
|
| <function_declaration> )*
|
|
|
|
<module_statement> =
|
|
"export"? "module" <namespaced_identifier> "{"
|
|
( <module_statement>
|
|
| <alias_statement>
|
|
| <struct_declaration>
|
|
| <enum_declaration>
|
|
| <function_declaration> )*
|
|
"}"
|
|
|
|
<import_statement> =
|
|
"import" <import_target> ";"
|
|
|
|
<import_target> =
|
|
<namespaced_identifier>
|
|
| <namespaced_identifier> "::" "*"
|
|
|
|
<alias_statement> =
|
|
"using" <identifier> "=" <namespaced_identifier> ";"
|
|
|
|
|
|
/* --- Declarations --- */
|
|
/* Rules for defining functions, structs, enums, and their components. */
|
|
|
|
<function_declaration> =
|
|
"export"? "fn" <identifier> <generic_params> "(" <fn_params> ")" ( "->" <type> )? <code_block>
|
|
|
|
<fn_params> =
|
|
<fn_params_list>?
|
|
|
|
<fn_params_list> =
|
|
"this" <type> ("," <fn_param> ( "," <fn_param> )* )?
|
|
| <fn_param> ( "," <fn_param> )*
|
|
|
|
<fn_param> =
|
|
<identifier> ":" <type>
|
|
|
|
<struct_declaration> =
|
|
"export"? "struct" <identifier> <generic_params> "{" <struct_members> "}"
|
|
|
|
<struct_members> =
|
|
<struct_member> ( "," <struct_member> )*
|
|
|
|
<struct_member> =
|
|
<identifier> ":" <type>
|
|
|
|
<enum_declaration> =
|
|
"export"? "enum" <identifier> <generic_params> "{" <enum_members> "}"
|
|
|
|
<enum_members> =
|
|
<enum_member> ( "," <enum_member> )*
|
|
|
|
<enum_member> =
|
|
<identifier> ( "(" <type> ")" )?
|
|
|
|
<generic_params> =
|
|
( "<" <generic_params_list> ">" )?
|
|
|
|
<generic_params_list> =
|
|
<generic_param> ( "," <generic_param> )*
|
|
|
|
<generic_param> =
|
|
"typename" <identifier>
|
|
|
|
|
|
/* --- Statements & Control Flow --- */
|
|
/* Rules for code blocks, variable declarations, and control structures. */
|
|
|
|
<code_block> =
|
|
"{" <statements>? "}"
|
|
|
|
<statements> =
|
|
<statement> ( <statement> )*
|
|
|
|
<statement> =
|
|
<variable_declaration> ";"
|
|
| <if_statement>
|
|
| <loop_statement>
|
|
| <defer_statement> ";"
|
|
| <errdefer_statement> ";"
|
|
| <return_statement> ";"
|
|
| <break_statement> ";"
|
|
| <continue_statement> ";"
|
|
| <expression_statement>
|
|
| <alias_statement>
|
|
| <match_statement>
|
|
| <switch_statement>
|
|
|
|
<variable_declaration> =
|
|
<variable_declarator> <identifier> ( ":" <type> )? "=" <expression>
|
|
| <variable_declarator> <identifier> ":" <type> ( "=" <expression> )?
|
|
|
|
<variable_declarator> =
|
|
"let"
|
|
| "def"
|
|
|
|
<if_statement> =
|
|
"if" "(" <expression> ")" <variable_unwrapper>? <code_block>
|
|
<else_statement>?
|
|
|
|
<else_statement> =
|
|
"else" <variable_unwrapper>? <code_block>
|
|
| "else" <if_statement>
|
|
|
|
<variable_unwrapper> =
|
|
"|" <identifier> "|"
|
|
|
|
<loop_statement> =
|
|
(<identifier> ":=")? (
|
|
<c_for_statement>
|
|
| <range_for_statement>
|
|
| <while_statement>
|
|
| <do_while_statement>
|
|
| <inf_loop_statement>
|
|
)
|
|
|
|
<c_for_statement> =
|
|
"for" "(" <variable_declaration>? ";" <expression> ";" <expression> ")"
|
|
<code_block>
|
|
|
|
<range_for_statement> =
|
|
"for" "(" <variable_declarator> <identifier> ":=" <expression> ")"
|
|
<code_block>
|
|
|
|
<while_statement> =
|
|
"while" "(" <expression> ")" <variable_unwrapper>? <code_block>
|
|
<else_statement>?
|
|
|
|
<do_while_statement> =
|
|
"do" <code_block> "while" "(" <expression> ")"
|
|
|
|
<inf_loop_statement> =
|
|
"loop" <code_block>
|
|
|
|
<match_statement> =
|
|
"match" "(" <expression> ")" "{" <match_case>* <default_case>? "}"
|
|
|
|
<switch_statement> =
|
|
"switch" "(" <expression> ")" "{" <switch_case>* <default_case>? "}"
|
|
|
|
<match_case> =
|
|
( <type_name> | <scoped_access_expression> ) ( "(" <identifier> ")" )? "->" <code_block>
|
|
|
|
<switch_case> =
|
|
<expression> "->" <code_block>
|
|
|
|
<default_case> =
|
|
"_" "->" <code_block>
|
|
|
|
<break_statement> =
|
|
"break" <identifier>?
|
|
|
|
<continue_statement> =
|
|
"continue" <identifier>?
|
|
|
|
<defer_statement> =
|
|
"defer" ( <expression> | <code_block> )
|
|
|
|
<errdefer_statement> =
|
|
"errdefer" ( <expression> | <code_block> )
|
|
|
|
<return_statement> =
|
|
"return" <expression>?
|
|
|
|
<expression_statement> =
|
|
<expression> ";"
|
|
|
|
|
|
/* --- Expressions & Operator Precedence --- */
|
|
/* The full expression hierarchy, from lowest to highest precedence. */
|
|
|
|
<expression> =
|
|
<assign_expression>
|
|
|
|
<assign_expression> =
|
|
<bool_or_expression> ( ( <assign_op> | <compound_assign_op> ) <expression> )?
|
|
|
|
<bool_or_expression> =
|
|
<bool_and_expression> ( ( "||" | "or" ) <bool_and_expression> )*
|
|
|
|
<bool_and_expression> =
|
|
<compare_expression> ( ( "&&" | "and" ) <compare_expression> )*
|
|
|
|
<compare_expression> =
|
|
<bitwise_expression> ( <compare_op> <bitwise_expression> )?
|
|
|
|
<bitwise_expression> =
|
|
<bitwise_shift_expression> ( <bitwise_op> <bitwise_shift_expression> )*
|
|
|
|
<bitwise_shift_expression> =
|
|
<addition_expression> ( <bitshift_op> <addition_expression> )*
|
|
|
|
<addition_expression> =
|
|
<multiply_expression> ( <addition_op> <multiply_expression> )*
|
|
|
|
<multiply_expression> =
|
|
<prefix_expression> ( <multiply_op> <prefix_expression> )*
|
|
|
|
<prefix_expression> =
|
|
<prefix_op>* <primary_expression>
|
|
|
|
<primary_expression> =
|
|
<primary_type_expression> ( <suffix_op> | <fn_call_arguments> )*
|
|
|
|
|
|
/* --- Primary Expressions & Literals --- */
|
|
/* The highest-precedence expressions, including literals and grouped expressions. */
|
|
|
|
<primary_type_expression> =
|
|
<char_literal>
|
|
| <null_literal>
|
|
| <string_literal>
|
|
| <number_literal>
|
|
| <boolean_literal>
|
|
| <grouped_expression>
|
|
| <identifier>
|
|
| <struct_literal>
|
|
| <scoped_access_expression>
|
|
| <reflection_expression>
|
|
|
|
<grouped_expression> =
|
|
"(" <expression> ")"
|
|
|
|
<scoped_access_expression> =
|
|
<type_name> "::" <identifier>
|
|
|
|
<reflection_expression> =
|
|
( <primary_expression> | <type_name> | <scoped_access_expression> ) ".@" <identifier>?
|
|
|
|
<fn_call_arguments> =
|
|
"(" <expression_list> ")"
|
|
|
|
<expression_list> =
|
|
(<expression> ",")* <expression>?
|
|
|
|
<struct_literal> =
|
|
<type> "{" ( <named_field_list> | <positional_field_list> )? ","? "}"
|
|
|
|
<named_field_list> =
|
|
<named_field_init> ( "," <named_field_init> )*
|
|
|
|
<named_field_init> =
|
|
<identifier> ":" <expression>
|
|
|
|
<positional_field_list> =
|
|
<expression> ( "," <expression> )*
|
|
|
|
<null_literal> =
|
|
"null"
|
|
|
|
<boolean_literal> =
|
|
"true"
|
|
| "false"
|
|
|
|
<number_literal> = /* Assumed to be defined by the tokenizer */
|
|
<string_literal> = /* Assumed to be defined by the tokenizer */
|
|
<char_literal> = /* Assumed to be defined by the tokenizer */
|
|
|
|
|
|
/* --- Operators --- */
|
|
/* Definitions for all operator token sets. */
|
|
|
|
<assign_op> = "="
|
|
<compound_assign_op> = "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "<<=" | ">>=" | "||=" | "&&="
|
|
<compare_op> = "==" | "!=" | ">" | "<" | ">=" | "<="
|
|
<bitwise_op> = "&" | "^" | "|"
|
|
<bitshift_op> = "<<" | ">>"
|
|
<addition_op> = "+" | "-"
|
|
<multiply_op> = "*" | "/" | "%"
|
|
<prefix_op> = "!" | "-" | "~" | "&" | "*"
|
|
|
|
<suffix_op> =
|
|
"[" <expression>? ":" <expression>? "]"
|
|
| "[" <expression> "]"
|
|
| ".[" <expression> "]"
|
|
| "." <identifier>
|
|
| "->" <identifier>
|
|
| ".#"
|
|
| ".*"
|
|
|
|
/* --- Type System --- */
|
|
/* Rules for defining types, type names, and type qualifiers. */
|
|
|
|
<type> =
|
|
<type_qualifier_chain> <type_name>
|
|
|
|
<type_qualifier_chain> =
|
|
( "*" | "[]" ) <type_qualifier_chain>?
|
|
| "$" <type_qualifier_chain_after_mutable>?
|
|
| "?" <type_qualifier_chain_after_optional>?
|
|
|
|
<type_qualifier_chain_after_optional> =
|
|
( "*" | "[]" ) <type_qualifier_chain>?
|
|
| "$" <type_qualifier_chain_after_mutable>?
|
|
|
|
<type_qualifier_chain_after_mutable> =
|
|
( "*" | "[]" ) <type_qualifier_chain>?
|
|
| "?" <type_qualifier_chain_after_optional>?
|
|
|
|
<type_name> =
|
|
<namespaced_identifier> ( "<" <types_list> ">" )?
|
|
|
|
<namespaced_identifier> =
|
|
<identifier>
|
|
| <identifier> "::" <namespaced_identifier>
|
|
|
|
<types_list> =
|
|
<type> ( "," <types_list> )*
|
|
|
|
|
|
/* --- Lexical Tokens & Base Definitions --- */
|
|
/* The lowest-level building blocks of the language. */
|
|
|
|
<identifier> =
|
|
<nondigit> <identifier_tail>
|
|
|
|
<identifier_tail> =
|
|
<empty>
|
|
| <nondigit> <identifier_tail>
|
|
| <digit> <identifier_tail>
|
|
|
|
<nondigit> = "_" | [a-z] | [A-Z]
|
|
<digit> = <zero> | <nonzero_digit>
|
|
<zero> = "0"
|
|
<nonzero_digit> = [1-9]
|
|
|
|
<empty> = E /* Represents an empty terminal string */
|
|
|