Gramática de leitura e correspondência com o parser
Antes: sintaxe. Aprofunde-se: arquitetura.
Esta gramática resume as produções implementadas. Não substitui o parser
Pratt nem promete aceitar todos os programas que uma EBNF isolada produziria:
a visibilidade, os tipos e os locais válidos de ref são validados depois.
Notação
Aspas indicam texto literal. [...] indica opcional; {...} repetição;
| separa alternativas. expr usa a tabela de precedência da referência.
sep é fim de linha ou ;; as listas permitem novas linhas e vírgula final.
programa = { sentencia [sep] } ;
sentencia = declaracion | destructuracion | funcion | clase | record | interfaz | enum
| inicializador | guard | defer | select
| "return" [expr] | "throw" expr
| "break" | "continue" | ciclo | captura
| ("print" | "echo") ["("] expr [")"] | expr ;
variable = "$" identificador ;
declaracion = [visibilidad] ["static"] ["const"]
("var" | "let" [tipo] | tipo) variable ["=" expr]
{"," variable ["=" expr]} ;
destructuracion = "[" [variable] {"," [variable]} "]" "=" expr ;
funcion = [visibilidad] ["abstract"] ["static"] "func" identificador firma (bloque | [sep]) ;
firma = "(" [parametros] ")" [":" tipo] ;
parametros = parametro {"," parametro} [","] ;
parametro = [visibilidad] ["const"] ["ref"] tipo variable ["=" expr] ;
closure = "func" firma bloque ;
clase = visibilidad ["abstract"] ["static"] "class" identificador ["<" identificador {"," identificador} ">"]
["extends" identificador]
["implements" identificador {"," identificador}] "{" {miembro} "}" ;
record = visibilidad "record" identificador "(" [parametrosRecord] ")" ;
parametrosRecord = [visibilidad] ["const"] tipo variable ["=" expr] {"," [visibilidad] ["const"] tipo variable ["=" expr]} ;
interfaz = visibilidad "interface" identificador
["extends" identificador {"," identificador}] "{" {protoMetodo} "}" ;
enum = visibilidad "enum" identificador [":" tipo] "{" {casoEnum} "}" ;
casoEnum = "case" identificador ["=" expr] [sep] ;
protoMetodo = [visibilidad] "func" identificador "(" [parametros] ")" [":" tipo] [sep] ;
miembro = declaracion | funcion | inicializador ;
inicializador = "Init" [identificador] "(" [parametros] ")" bloque ;
guard = "guard" "(" expr ")" ":" bloque ;
defer = "defer" (bloque | sentencia) ;
visibilidad = "public" | "private" | "protected" ;
tipo = simple {"|" simple} ["?"] ;
simple = nombreTipo ["<" tipo {"," tipo} ">"] ;
bloque = "{" {sentencia [sep]} "}" ;
ciclo = "while" "(" expr ")" bloque
| "do" bloque "while" "(" expr ")"
| "foreach" "(" expr "as" [variable "=>"] variable ")" bloque ;
captura = "try" bloque "catch" "(" variable ")" bloque ;
select = "select" "{" {casoSelect} "}" ;
casoSelect = ("case" (("send" "(" expr "," expr ")") | ("recv" "(" expr ")") | (variable "=" "recv" "(" expr ")")) | "default") ":" {sentencia [sep]} ;
array = "[" [elementoArray {"," elementoArray} [","]] "]" ;
elementoArray = expr | "..." expr ;
map = "{" [elementoMap {"," elementoMap} [","]] "}" ;
elementoMap = expr ":" expr | "..." expr ;
match = "match" "(" expr ")" "{" {brazo} "}" ;
brazo = ("default" | expr {"," expr}) "=>" (expr | bloque) [","] ;
llamada = expr "(" [argumento {"," argumento} [","]] ")" ;
argumento = expr | "ref" variable | identificador ":" expr | "..." expr ;
yield = "yield" [expr ["=>" expr]] ;
await = "await" ( "(" expr ")" | expr ) ;
comprobacion = expr ("is" | "instanceof") tipo ;
acceso = expr ("->" | "?->" | "::") nombreMiembro ;
indice = expr "[" [expr] "]" ;
nuevo = "new" identificador ["<" tipo {"," tipo} ">"] "(" [argumentos] ")" ;
asincrono = "async" bloque ;
Restrições que a notação não expressa
protectedaplica-se apenas a membros de classe, não a classes/funções globais.staticrequer visibilidade explícita.Inite closures não a possuem.- O parser preserva parâmetros sem tipo para poder emitir
JOSS-TYPE-011; a gramática de código válido exige o tipo. constexige inicializador e tem sua própria rota de análise.- Os nomes de tipos canônicos são descritos em tipos; aceitar o nome no parser não prova que exista uma classe.
- Um índice vazio
[]só serve para append como destino de atribuição ($arr[] = $v). - Em expressão,
{}é interpretado como mapa vazio. Um corpo obrigatório é analisado como bloco.{ "a": 1 }distingue-se de um bloco por:. - O ternário usa
cond ? expr : expr,cond ?: exprou condicional de uma única ramificação(cond) ? bloque; suas ramificações admitem blocos ou expressões. guard (cond) : { ... }exige que seu bloco saia do callable mediantereturnouthrow(JOSS-FLOW-005).- As cadeias com aspas duplas admitem interpolação de expressões
${expr}desaçucarada para concatenação.. Incorporam-se os operadores de intervalo numérico.., decremento postfix--e atribuição nula coalescente??=. async expresiónainda é uma rota do parser, com avaliação antecipada do argumento;async(...)é rejeitado. A forma recomendada é o blocoasync { ... }.- Chamadas, arrays e assinaturas permitem vírgulas finais. A continuidade de uma
expressão após uma quebra de linha é decidida por
isExpressionContinuation.
Do texto ao nó
| Produção | Parser | Nó AST |
|---|---|---|
| Programa | ParseProgram |
Program |
| Expressão por precedência | parseExpression, registros prefix/infix |
Expression e tipos concretos |
| Atribuição | parseAssignExpression |
AssignExpression |
| Variável declarada | Rotas de parseStatement |
LetStatement, MultiLetStatement |
| Desestruturação | parseDestructureStatement |
DestructureStatement |
| Função global/método | parseMethodStatement |
MethodStatement |
| Closure | parseFunctionLiteral |
FunctionLiteral |
| Tipo | parseTypeReference |
Token normalizado preservado na declaração/assinatura |
| Classe / Record / Init | parseClassStatement, parseRecordStatement, parseInitStatement |
ClassStatement, InitStatement |
| Interface | parseInterfaceStatement |
InterfaceStatement |
| Enum | parseEnumStatement |
EnumStatement |
| Guard | parseGuardStatement |
GuardStatement |
| Defer | parseDeferStatement |
DeferStatement |
| Select | parseSelectStatement |
SelectStatement |
| Yield | parseYieldExpression |
YieldExpression |
| Spread | parseSpreadExpression |
SpreadExpression |
| Verificação de tipo | parseIsInfix |
IsExpression |
| Laços | parseForeachStatement, parseWhileStatement, parseDoWhileStatement |
Seus nós de instrução |
| Erro | parseTryCatchStatement, parseThrowStatement |
TryCatchStatement, ThrowStatement |
| Async / Await | parseAsyncExpression, parseAwaitExpression |
CallExpression a async, PrefixExpression / CallExpression |
Os arquivos são pkg/parser/parser*.go, ast*.go, lexer.go e token.go.
Para adicionar sintaxe, atualize testes positivos e negativos antes de alterar
esta referência. Não converta nomes de tokens residuais em funcionalidades públicas.