126 lines
No EOL
5.6 KiB
Text
126 lines
No EOL
5.6 KiB
Text
/**
|
|
* ZoKrates Grammar
|
|
* Author: Jacob Eberhardt, Thibaut Schaeffer
|
|
*/
|
|
|
|
file = { SOI ~ NEWLINE* ~ import_directive* ~ NEWLINE* ~ ty_struct_definition* ~ NEWLINE* ~ function_definition* ~ EOI }
|
|
|
|
import_directive = { main_import_directive | from_import_directive }
|
|
from_import_directive = { "from" ~ "\"" ~ import_source ~ "\"" ~ "import" ~ identifier ~ ("as" ~ identifier)? ~ NEWLINE*}
|
|
main_import_directive = {"import" ~ "\"" ~ import_source ~ "\"" ~ ("as" ~ identifier)? ~ NEWLINE+}
|
|
import_source = @{(!"\"" ~ ANY)*}
|
|
function_definition = {"def" ~ identifier ~ "(" ~ parameter_list ~ ")" ~ "->" ~ "(" ~ type_list ~ ")" ~ ":" ~ NEWLINE* ~ statement* }
|
|
|
|
parameter_list = _{(parameter ~ ("," ~ parameter)*)?}
|
|
parameter = {vis? ~ ty ~ identifier}
|
|
|
|
// basic types
|
|
ty_field = {"field"}
|
|
ty_bool = {"bool"}
|
|
ty_basic = { ty_field | ty_bool }
|
|
ty_basic_or_struct = { ty_basic | ty_struct }
|
|
ty_array = { ty_basic_or_struct ~ ("[" ~ expression ~ "]")+ }
|
|
ty = { ty_array | ty_basic | ty_struct }
|
|
type_list = _{(ty ~ ("," ~ ty)*)?}
|
|
// structs
|
|
ty_struct = { identifier }
|
|
// type definitions
|
|
ty_struct_definition = { "struct" ~ identifier ~ "{" ~ NEWLINE* ~ struct_field_list ~ NEWLINE* ~ "}" ~ NEWLINE* }
|
|
struct_field_list = _{(struct_field ~ (NEWLINE+ ~ struct_field)*)? }
|
|
struct_field = { ty ~ identifier }
|
|
|
|
vis_private = {"private"}
|
|
vis_public = {"public"}
|
|
vis = { vis_private | vis_public }
|
|
|
|
// Statements
|
|
statement = { (return_statement // does not require subsequent newline
|
|
| (iteration_statement
|
|
| multi_assignment_statement // try this first as we want all assignments based on return of function calls match here and not later
|
|
| definition_statement
|
|
| assignment_statement
|
|
| expression_statement
|
|
) ~ NEWLINE
|
|
) ~ NEWLINE* }
|
|
|
|
iteration_statement = { "for" ~ ty ~ identifier ~ "in" ~ expression ~ ".." ~ expression ~ "do" ~ NEWLINE* ~ statement* ~ "endfor"}
|
|
return_statement = { "return" ~ expression_list}
|
|
multi_assignment_statement = { optionally_typed_identifier_list ~ "=" ~ identifier ~ "(" ~ expression_list ~ ")"} // This is very specific with regards to parsing. However, I think more generality is not needed here.
|
|
definition_statement = {ty ~ identifier ~ "=" ~ expression} // declare and assign, so only identifiers are allowed, unlike `assignment_statement`
|
|
assignment_statement = {assignee ~ "=" ~ expression } // TODO: Is this optimal? Can the left side be written more elegantly?
|
|
expression_statement = {expression}
|
|
|
|
optionally_typed_identifier_list = _{ optionally_typed_identifier ~ ("," ~ optionally_typed_identifier)* }
|
|
optionally_typed_identifier = { (identifier) | (ty ~ identifier) } // we don't use { ty? ~ identifier } as with a single token, it gets parsed as `ty` but we want `identifier`
|
|
|
|
// Expressions
|
|
expression_list = _{(expression ~ ("," ~ expression)*)?}
|
|
|
|
expression = { term ~ (op_binary ~ term)* }
|
|
term = { ("(" ~ expression ~ ")") | inline_struct_expression | conditional_expression | postfix_expression | primary_expression | inline_array_expression | array_initializer_expression | unary_expression }
|
|
spread = { "..." ~ expression }
|
|
range = { from_expression? ~ ".." ~ to_expression? }
|
|
from_expression = { expression }
|
|
to_expression = { expression }
|
|
|
|
conditional_expression = { "if" ~ expression ~ "then" ~ expression ~ "else" ~ expression ~ "fi"}
|
|
|
|
postfix_expression = { identifier ~ access+ } // we force there to be at least one access, otherwise this matches single identifiers. Not sure that's what we want.
|
|
access = { array_access | call_access | member_access }
|
|
array_access = { "[" ~ range_or_expression ~ "]" }
|
|
call_access = { "(" ~ expression_list ~ ")" }
|
|
member_access = { "." ~ identifier }
|
|
|
|
primary_expression = { identifier
|
|
| constant
|
|
}
|
|
|
|
inline_struct_expression = { identifier ~ "{" ~ NEWLINE* ~ inline_struct_member_list ~ NEWLINE* ~ "}" }
|
|
inline_struct_member_list = _{(inline_struct_member ~ ("," ~ NEWLINE* ~ inline_struct_member)*)? ~ ","? }
|
|
inline_struct_member = { identifier ~ ":" ~ expression }
|
|
|
|
inline_array_expression = { "[" ~ NEWLINE* ~ inline_array_inner ~ NEWLINE* ~ "]" }
|
|
inline_array_inner = _{(spread_or_expression ~ ("," ~ NEWLINE* ~ spread_or_expression)*)?}
|
|
spread_or_expression = { spread | expression }
|
|
range_or_expression = { range | expression }
|
|
array_initializer_expression = { "[" ~ expression ~ ";" ~ constant ~ "]" }
|
|
|
|
unary_expression = { op_unary ~ term }
|
|
|
|
// End Expressions
|
|
|
|
assignee = { identifier ~ assignee_access* }
|
|
assignee_access = { array_access | member_access }
|
|
identifier = @{ ((!keyword ~ ASCII_ALPHA) | (keyword ~ (ASCII_ALPHANUMERIC | "_"))) ~ (ASCII_ALPHANUMERIC | "_")* }
|
|
constant = { decimal_number | boolean_literal }
|
|
decimal_number = @{ "0" | ASCII_NONZERO_DIGIT ~ ASCII_DIGIT* }
|
|
boolean_literal = { "true" | "false" }
|
|
|
|
op_inclusive_or = {"||"}
|
|
op_exclusive_or = {"^"}
|
|
op_and = {"&&"}
|
|
op_equal = {"=="}
|
|
op_not_equal = {"!="}
|
|
op_lt = {"<"}
|
|
op_lte = {"<="}
|
|
op_gt = {">"}
|
|
op_gte = {">="}
|
|
op_add = {"+"}
|
|
op_sub = {"-"}
|
|
op_mul = {"*"}
|
|
op_div = {"/"}
|
|
op_pow = {"**"}
|
|
op_not = {"!"}
|
|
op_binary = _ { op_pow | op_inclusive_or | op_exclusive_or | op_and | op_equal | op_not_equal | op_lte | op_lt | op_gte | op_gt | op_add | op_sub | op_mul | op_div }
|
|
op_unary = { op_not }
|
|
|
|
|
|
WHITESPACE = _{ " " | "\t" | "\\" ~ NEWLINE}
|
|
COMMENT = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!NEWLINE ~ ANY)*) }
|
|
|
|
// TODO: Order by alphabet
|
|
keyword = @{"for" | "endfor" | "as" | "in" | "return" | "byte" | "field" | "bool" | "if" | "do" | "else" | "export" | "false" |
|
|
"def" | "for" | "import" | "uint" |
|
|
"in" | "public" | "private" | "return" |
|
|
"struct" | "true"
|
|
} |