Files
langkit/lkt/parser.lkt
Pierre-Marie de Rodat a0f8539c0c Lkt: allow multiple modules for each import ... clause
It was not allowed so far because of an oversight in the recent revamp
of the module system.
2026-02-12 11:48:42 +00:00

524 lines
15 KiB
Plaintext

from nodes import *
import tokens
@with_lexer(tokens.lkt_lexer)
@with_unparsers
grammar lkt_grammar {
@main_rule
main_rule <- LangkitRoot(/ module_doc imports decls @Termination)
id <- Id(@Identifier)
ref_id <- RefId(@Identifier)
type_ref_id <- ref_id |> when(Id.is_type_name)
module_id <- ModuleId(@Identifier) |> when(Id.is_not_type_name)
def_id <- DefId(@Identifier)
doc <- ?string_lit
module_doc <- ?ModuleDocStringLit(
list+(ModuleDocStringLine(@ModuleDocStringLine))
)
imported_names <- list+(
ImportedName(
ImportedId(@Identifier)
/
?pick(@Identifier("as") / def_id)
),
","
)
import_clause <- or(
| Import("import" / imported_names)
| ImportFrom("from" module_id "import" imported_names)
| ImportAllFrom("from" / module_id "import" "*")
)
imports <- list*(import_clause)
lexer_decl <- LexerDecl(
"lexer"
/
def_id
"{"
list*(or(lexer_case_rule | decl)).dont_skip("}")
"}"
)
grammar_decl <- GrammarDecl("grammar" / def_id "{" decls "}")
grammar_rule <- GrammarRuleDecl(def_id "<-" grammar_expr)
lexer_case_rule <- LexerCaseRule(
"match" / grammar_primary "{" list*(lexer_case_alt).dont_skip("}") "}"
)
lexer_case_alt <- or(
| LexerCaseRuleCondAlt(
"if"
/
@Identifier("previous_token")
"is"
list+(ref_id, "|")
"then"
lexer_case_send
)
| LexerCaseRuleDefaultAlt("else" / lexer_case_send)
| skip(ErrorLexerCaseRuleAlt)
)
lexer_case_send <- LexerCaseRuleSend(
@Identifier("send") "(" ref_id "," num_lit ")"
)
grammar_primary <- or(
| grammar_pick
| grammar_list_expr
| token_literal
| token_no_case_literal
| token_pattern
| grammar_cut
| grammar_skip
| grammar_null
| grammar_token
| grammar_stopcut
| parse_node_expr
| grammar_opt
| grammar_opt_error
| grammar_or_expr
| grammar_rule_ref
| grammar_discard_expr
| skip(ErrorGrammarExpr)
)
grammar_expr <- or(
| GrammarDontSkip(
grammar_expr "." @Identifier("dont_skip") "(" grammar_expr ")"
)
| GrammarPredicate(
grammar_expr "|>" "when" "(" basic_name ")"
)
| grammar_primary
)
grammar_pick <- GrammarPick(
@Identifier("pick") "(" list+(grammar_expr).dont_skip(")") ")"
)
grammar_implicit_pick <- GrammarImplicitPick(list+(grammar_expr))
grammar_opt <- or(
| GrammarOptGroup("?" "(" / list*(grammar_expr).dont_skip(")") ")")
| GrammarOpt("?" / grammar_expr)
)
grammar_opt_error <- or(
| GrammarOptErrorGroup(
"!" "(" / list*(grammar_expr).dont_skip(")") ")"
)
| GrammarOptError("!" / grammar_expr)
)
grammar_cut <- GrammarCut("/")
grammar_stopcut <- GrammarStopCut(
@Identifier("stop_cut") "(" grammar_expr ")"
)
grammar_or_expr <- GrammarOrExpr(
"or"
"("
list+(
list+(grammar_expr).dont_skip("|"), "|", allow_leading
).dont_skip(")")
")"
)
grammar_discard_expr <- GrammarDiscard("discard" "(" grammar_expr ")")
token_literal <- TokenLit(@String)
token_no_case_literal <- TokenNoCaseLit(
@Identifier("no_case") "(" token_literal ")"
)
token_pattern <- or(
| TokenPatternConcat(token_pattern "&" token_pattern_literal)
| token_pattern_literal
)
token_pattern_literal <- TokenPatternLit(@PString)
parse_node_expr <- ParseNodeExpr(
type_ref
"("
/
list*(grammar_expr).dont_skip(")")
")"
)
grammar_rule_ref <- GrammarRuleRef(ref_id)
grammar_list_expr <- GrammarList(
# Match either "list" (type inference will determine the list type) or
# a specific list type.
or(DefaultListTypeRef(@Identifier("list")) | type_ref)
or(ListKind.One("+") | ListKind.Zero("*"))
"("
# Main list expr
or(grammar_implicit_pick | grammar_expr).dont_skip(")").dont_skip(",")
# Separator
?pick("," grammar_list_sep)
")"
)
grammar_list_sep <- GrammarListSep(grammar_expr ?pick("," id))
grammar_skip <- GrammarSkip(@Identifier("skip") "(" type_ref ")")
grammar_null <- GrammarNull("null" ?pick("(" type_ref ")"))
grammar_token <- TokenRef("@" ref_id ?pick("(" token_literal ")"))
type_decl <- or(
| StructDecl(
"struct"
/
def_id
?pick("implements" / type_list)
"{"
decl_block.dont_skip("}")
"}"
)
| EnumClassDecl(
"enum"
"class"
/
def_id
?pick(":" type_ref)
?pick("implements" type_list)
"{"
list*(
EnumClassCase(
"case"
list+(EnumClassAltDecl(def_id null(ASTList[TypeRef])), ",")
)
)
decl_block.dont_skip("}")
"}"
)
| ClassDecl(
"class"
/
def_id
?pick(":" / type_ref)
?pick("implements" / type_list)
"{"
decl_block.dont_skip("}")
"}"
)
| EnumTypeDecl(
"enum"
/
def_id
?pick("implements" type_list)
"{"
"case"
list+(enum_lit_decl, ",")
decl_block.dont_skip("}")
"}"
)
| TraitDecl(
"trait"
/
def_id
null(ASTList[TypeRef])
"{"
decl_block.dont_skip("}")
"}"
)
)
generic_decl <- GenericDecl(
"generic"
/
"["
GenericParamDeclList+(generic_param_type, ",")
"]"
bare_decl
)
generic_param_type <- FullDecl(
doc
list*(decl_annotation)
GenericParamTypeDecl(
ClassQualifier("class") def_id null(ASTList[TypeRef])
)
)
enum_lit_decl <- EnumLitDecl(def_id)
fun_decl <- FunDecl(
"fun"
/
def_id
"("
fun_param_list
")"
":"
type_ref
?pick("implements" type_member_ref)
?pick("=" expr)
)
lambda_param_decl <- LambdaParamDecl(
def_id ?pick(":" type_ref) ?pick("=" expr)
)
fun_param_decl <- FunParamDecl(
list*(decl_annotation) def_id ":" type_ref ?pick("=" expr)
)
fun_param_list <- list*(fun_param_decl, ",")
lambda_param_list <- list*(lambda_param_decl, ",")
field_decl <- FieldDecl(
def_id
":"
type_ref
?pick("implements" type_member_ref)
?pick("=" expr)
)
lexer_family_decl <- LexerFamilyDecl(
@Identifier("family") / def_id "{" list*(decl).dont_skip("}") "}"
)
bare_decl <- or(
| generic_decl
| type_decl
| fun_decl
| lexer_decl
| grammar_decl
| field_decl
| val_decl
| env_spec_decl
| lexer_family_decl
| grammar_rule
| dynvar_decl
| skip(ErrorDecl)
)
decl <- FullDecl(doc list*(decl_annotation) bare_decl)
type_member_ref <- DotExpr(type_ref_id null(NullCondQualifier)"." / ref_id)
type_expr <- or(
| DotExpr(module_id null(NullCondQualifier)"." / type_ref_id)
| DotExpr(type_expr null(NullCondQualifier)"." / type_ref_id)
| type_ref_id
)
type_ref <- or(
| GenericTypeRef(type_expr "[" type_list "]")
| SimpleTypeRef(type_expr)
| FunctionTypeRef("(" list*(type_ref, ",") ")" "->" type_ref)
)
type_list <- list+(type_ref, ",")
decls <- list*(decl).dont_skip("}")
decl_block <- DeclBlock*(decl)
val_decl <- ValDecl("val" / def_id ?pick(":" type_ref) "=" expr)
dynvar_decl <- DynVarDecl("dynvar" def_id ":" type_ref)
var_bind <- VarBind("bind" / ref_id "=" expr)
env_spec_action <- CallExpr(RefId(@Identifier) "(" args ")")
env_spec_decl <- EnvSpecDecl(
DefId(@Identifier("env_spec")) "{" list*(env_spec_action) "}"
)
block <- BlockExpr(
"{"
/
list+(
or(
| BlockExprClause(or(var_bind | decl) ";")
| expr
| skip(ErrorDecl)
)
).dont_skip("}")
"}"
)
pattern <- or(OrPattern(neg_pattern "|" pattern) | neg_pattern)
neg_pattern <- or(
| NotPattern("not" neg_pattern)
| complex_pattern
)
pattern_binding <- BindingValDecl(def_id)
complex_pattern <- or(
| ComplexPattern(
null(BindingValDecl)
value_pattern
?pick("(" / list+(pattern_arg, ",") ")")
?pick("when" expr)
)
| ComplexPattern(
?pick(pattern_binding "@")
value_pattern
?pick("(" / list+(pattern_arg, ",") ")")
?pick("when" expr)
)
| ComplexPattern(
?pick(pattern_binding "@")
AnyTypePattern("*")
"(" / list+(pattern_arg, ",") ")"
?pick("when" expr)
)
| RenamingComplexPattern(
pattern_binding
null(Pattern)
null(ASTList[PatternDetail])
?pick("when" expr)
)
)
value_pattern <- or(
| TypePattern(type_ref)
| NullPattern("null")
| regex_pattern
| bool_pattern
| integer_pattern
| list_pattern
| ParenPattern("(" pattern ")")
)
regex_pattern <- RegexPattern(@String)
# Boolean patterns use hard-coded "true" & "false" identifiers, even though
# booleans literals are not built-in in Langkit but just a regular enum.
bool_pattern <- or(
| BoolPattern.True(@Identifier("true"))
| BoolPattern.False(@Identifier("false"))
)
ellipsis_pattern <- EllipsisPattern(?pick(id "@") "...")
integer_pattern <- IntegerPattern(@Number)
list_pattern <- ListPattern(
"[" list+(or(ellipsis_pattern | neg_pattern), ",") "]"
)
pattern_arg <- or(
| FieldPatternDetail(id ":" / pattern)
| PropertyPatternDetail(
CallExpr(ref_id "(" / args ")") ":" / pattern
)
)
expr <- or(
| BinOp(stream_concat Op.StreamConcat(":::") expr)
| stream_concat
)
stream_concat <- or(
| BinOp(logic Op.StreamCons("::") stream_concat)
| logic
)
logic <- or(
| BinOp(
logic
or(
| Op.OrInt("or" "?")
| Op.Or("or")
| Op.And("and")
| Op.LogicAnd("%" "and")
| Op.LogicOr("%" "or")
)
rel
)
| rel
)
rel <- or(NotExpr("not" eq) | eq)
eq <- or(
| BinOp(
eq
or(
| Op.Lte("<=")
| Op.Lt("<")
| Op.Gte(">=")
| Op.Gt(">")
| Op.Eq("==")
| Op.Ne("!=")
)
arith_1
)
| arith_1
)
arith_1 <- or(
| BinOp(arith_1 or(Op.Plus("+") | Op.Minus("-") | Op.Amp("&")) arith_2)
| arith_2
)
arith_2 <- or(
| BinOp(arith_2 or(Op.Mult("*") | Op.Div("/")) arith_3)
| arith_3
)
arith_3 <- or(
| UnOp(or(Op.Plus("+") | Op.Minus("-")) isa_or_primary)
| isa_or_primary
)
isa_or_primary <- or(
| Isa(primary "is" / pattern)
| AnyOf(primary "in" / AnyOfList+(primary, "|"))
| LogicUnify(isa_or_primary "<->" / primary)
| LogicPropagate(isa_or_primary "<-" logic_propagate_call)
| LogicAssign(isa_or_primary "<-" / primary)
| primary
)
logic_propagate_call <- LogicPropagateCall(callable_ref "%" "(" args ")")
primary <- or(| lambda_expr | if_expr | raise_expr | try_expr | basic_expr)
match_expr <- MatchExpr(
"match"
/
expr
"{"
list+(or(
| PatternMatchBranch("case" pattern "=>" / expr)
| MatchBranch(
"case" MatchValDecl(def_id ?pick(":" / type_ref)) "=>" / expr
)
))
"}"
)
num_lit <- NumLit(@Number)
big_num_lit <- BigNumLit(@BigNumber)
string_lit <- or(
| SingleLineStringLit(@String)
| PatternSingleLineStringLit(@PString)
| block_string_lit
)
block_string_lit <- BlockStringLit(
list+(BlockStringLine(@BlockStringLine))
)
char_lit <- CharLit(@Char)
if_expr <- IfExpr(
"if"
/
expr
"then"
expr
list*(ElsifBranch("elif" / expr "then" expr))
"else"
expr
)
raise_expr <- RaiseExpr("raise" / ?pick("[" / type_ref "]") expr)
try_expr <- TryExpr("try" / expr ?pick("else" / expr))
array_literal <- ArrayLiteral(
"[" / list*(expr, ",") "]" ?pick(":" / type_ref)
)
callable_ref <- or(
DotExpr(callable_ref null(NullCondQualifier) "." ref_id) | ref_id
)
null_cond_qual <- NullCondQualifier("?")
basic_expr <- or(
| CallExpr(basic_expr "(" / args ")")
| GenericInstantiation(basic_expr "[" type_list "]")
| SubscriptExpr(basic_expr null_cond_qual "[" / expr "]")
| ErrorOnNull(basic_expr "!")
| KeepExpr(
basic_expr null_cond_qual "." @Identifier("keep") "[" type_ref "]"
)
| CastExpr(
basic_expr
null_cond_qual
"."
@Identifier("as")
/
ExcludesNull("!")
"["
type_ref
"]"
)
| LogicPredicate(basic_expr "%" "(" / args ")")
| DotExpr(basic_expr null_cond_qual "." / ref_id)
| LogicExpr("%" CallExpr(ref_id "(" / args ")"))
| LogicExpr("%" / ref_id)
| term
)
term <- or(
| ParenExpr("(" / expr ")")
| match_expr
| null_lit
| ref_id
| block
| num_lit
| big_num_lit
| string_lit
| char_lit
| query_comprehension
| array_literal
)
basic_name <- or(
DotExpr(basic_name null(NullCondQualifier) "." / ref_id) | ref_id
)
lambda_expr <- LambdaExpr(
"(" lambda_param_list ")" ?pick(":" type_ref) "=>" / expr
)
null_lit <- NullLit("null" / ?pick("[" / type_ref "]"))
argument <- Argument(?pick(ref_id "=") expr)
args <- list*(argument, ",")
decl_annotation_args <- ?DeclAnnotationArgs("(" args ")")
decl_annotation <- DeclAnnotation("@" / id decl_annotation_args)
query_comprehension <- Query(
"from" expr
"match" pattern
?pick("select" expr)
?pick("if" expr)
)
}