GDScript 语法
这是用 EBNF 描述的 GDScript 形式文法,供参考。
备注
此语法源自参考文档和当前实现,仅用于描述。GDScript 解析器不是根据语法定义生成的。如果有不一致的地方,应该是此语法的错误,不是 GDScript 的 Bug。
(* GDScript EBNF grammar.
Uppercase words are terminals generated by the tokenizer.
INDENT/DEDENT are not generated by the tokenizer yet, but they are added
here for reading convenience.
Naturally, this only cover syntax. Semantics can't be inferred from this
description.
*)
program = [ inheritance NEWLINE ] [ className ] { topLevelDecl } ;
inheritance = "extends" ( IDENTIFIER | STRING ) { "." IDENTIFIER } ;
className = "class_name" IDENTIFIER [ "," STRING ] NEWLINE ;
topLevelDecl
= classVarDecl
| constDecl
| signalDecl
| enumDecl
| methodDecl
| constructorDecl
| innerClass
| "tool"
;
classVarDecl = [ "onready" ] [ export ] "var" IDENTIFIER [ ":" typeHint ]
[ "=" expression ] [ setget ] NEWLINE ;
setget = "setget" [ IDENTIFIER ] [ "," IDENTIFIER] ;
export = "export" [ "(" [ BUILTINTYPE | IDENTIFIER { "," literal } ] ")" ] ;
typeHint = BUILTINTYPE | IDENTIFIER ;
constDecl = "const" IDENTIFIER [ ":" typeHint ] "=" expression NEWLINE ;
signalDecl = "signal" IDENTIFIER [ signalParList ] NEWLINE ;
signalParList = "(" [ IDENTIFIER { "," IDENTIFIER } ] ")" ;
enumDecl = "enum" [ IDENTIFIER ] "{" [ IDENTIFIER [ "=" INTEGER ]
{ "," IDENTIFIER [ "=" INTEGER ] } [ "," ] ] "}" NEWLINE ;
methodDecl = [ rpc ] [ "static" ] "func" IDENTIFIER "(" [ parList ] ")"
[ "->" typeHint] ":" stmtOrSuite ;
parList = parameter { "," parameter } ;
parameter = [ "var" ] IDENTIFIER [ ":" typeHint ] [ "=" expression ] ;
rpc = "remote" | "master" | "puppet"
| "remotesync" | "mastersync" | "puppetsync";
constructorDecl = "func" IDENTIFIER "(" [ parList ] ")"
[ "." "(" [ argList ] ")" ] ":" stmtOrSuite ;
argList = expression { "," expression } ;
innerClass = "class" IDENTIFIER [ inheritance ] ":" NEWLINE
INDENT [ inheritance NEWLINE ] topLevelDecl { topLevelDecl } DEDENT ;
stmtOrSuite = stmt | NEWLINE INDENT suite DEDENT ;
suite = stmt { stmt };
stmt
= varDeclStmt
| ifStmt
| forStmt
| whileStmt
| matchStmt
| flowStmt
| assignmentStmt
| exprStmt
| assertStmt
| yieldStmt
| preloadStmt
| "breakpoint" stmtEnd
| "pass" stmtEnd
;
stmtEnd = NEWLINE | ";" ;
ifStmt = "if" expression ":" stmtOrSuite { "elif" expression ":" stmtOrSuite }
[ "else" ":" stmtOrSuite ] ;
whileStmt = "while" expression ":" stmtOrSuite;
forStmt = "for" IDENTIFIER "in" expression ":" stmtOrSuite ;
matchStmt = "match" expression ":" NEWLINE INDENT matchBlock DEDENT;
matchBlock = patternList ":" stmtOrSuite { patternList ":" stmtOrSuite };
patternList = pattern { "," pattern } ;
(* Note: you can't have a binding in a pattern list, but to not complicate the
grammar more it won't be restricted syntactically *)
pattern = literal | BUILTINTYPE | CONSTANT | "_" | bindingPattern
| arrayPattern | dictPattern ;
bindingPattern = "var" IDENTIFIER ;
arrayPattern = "[" [ pattern { "," pattern } [ ".." ] ] "]" ;
dictPattern = "{" [ keyValuePattern ] { "," keyValuePattern } [ ".." ] "}" ;
keyValuePattern = STRING [ ":" pattern ] ;
flowStmt
= "continue" stmtEnd
| "break" stmtEnd
| "return" [ expression ] stmtEnd
;
assignmentStmt = subscription ( "=" | "+=" | "-=" | "*=" | "/="
| "%=" | "&=" | "|=" | "^=" ) expression stmtEnd;
varDeclStmt = "var" IDENTIFIER [ "=" expression ] stmtEnd;
assertStmt = "assert" "(" expression [ "," STRING ] ")" stmtEnd ;
yieldStmt = "yield" "(" [ expression "," expression ] ")" ;
preloadStmt = "preload" "(" CONSTANT ")" ;
(* This expression grammar encodes precedence. Items later in the list have
higher precedence than the ones before. *)
exprStmt = expression stmtEnd ;
expression = cast [ "[" expression "]" ] ;
cast = ternaryExpr [ "as" typeHint ];
ternaryExpr = logicOr [ "if" logicOr "else" logicOr ] ;
logicOr = logicAnd { ( "or" | "||" ) logicAnd } ;
logicAnd = logicNot { ( "and" | "&&" ) logicNot };
logicNot = ( "!" | "not" ) logicNot | in;
in = comparison { "in" comparison };
comparison = bitOr { ( "<" | ">" | "<=" | ">=" | "==" | "!=" ) bitOr } ;
bitOr = bitXor { "|" bitXor } ;
bitXor = bitAnd { "^" bitAnd } ;
bitAnd = bitShift { "&" bitShift } ;
bitShift = minus { ( "<<" | ">>" ) minus } ;
minus = plus { "-" plus } ;
plus = factor { "+" factor } ;
factor = sign { ( "*" | "/" | "%" ) sign } ;
sign = ( "-" | "+" ) sign | bitNot ;
bitNot = "~" bitNot | is ;
is = call [ "is" ( IDENTIFIER | BUILTINTYPE ) ] ;
call
= (attribute [ "(" [ argList ] ")" ])
| "." IDENTIFIER "(" [ argList ] ")"
| "$" ( STRING | IDENTIFIER { '/' IDENTIFIER } );
attribute = subscription { "." IDENTIFIER } ;
subscription = primary [ "[" expression "]" ] ;
primary = "true" | "false" | "null" | "self" | literal | arrayDecl
| dictDecl | "(" expression ")" ;
literal = STRING | NUMBER | IDENTIFIER | BUILTINTYPE
| "PI" | "TAU" | "NAN" | "INF" ;
arrayDecl = "[" [ expression { "," expression } "," ] "]" ;
dictDecl = "{" [ keyValue { "," keyValue } "," ] "}" ;
keyValue
= expression ":" expression
| IDENTIFIER "=" expression
;