@yakuzaa/jade-compiler 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/cli.js +198 -29
  2. package/dist/cli.js.map +1 -1
  3. package/dist/codegen/ir_generator.d.ts +13 -0
  4. package/dist/codegen/ir_generator.d.ts.map +1 -1
  5. package/dist/codegen/ir_generator.js +167 -6
  6. package/dist/codegen/ir_generator.js.map +1 -1
  7. package/dist/codegen/ir_nodes.d.ts +19 -0
  8. package/dist/codegen/ir_nodes.d.ts.map +1 -1
  9. package/dist/codegen/wasm_generator.d.ts.map +1 -1
  10. package/dist/codegen/wasm_generator.js +0 -1
  11. package/dist/codegen/wasm_generator.js.map +1 -1
  12. package/dist/formatter/formatter.d.ts +48 -0
  13. package/dist/formatter/formatter.d.ts.map +1 -0
  14. package/dist/formatter/formatter.js +280 -0
  15. package/dist/formatter/formatter.js.map +1 -0
  16. package/dist/import_resolver.d.ts +15 -0
  17. package/dist/import_resolver.d.ts.map +1 -0
  18. package/dist/import_resolver.js +88 -0
  19. package/dist/import_resolver.js.map +1 -0
  20. package/dist/index.d.ts +21 -0
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +116 -1
  23. package/dist/index.js.map +1 -1
  24. package/dist/lexer/lexer.d.ts.map +1 -1
  25. package/dist/lexer/lexer.js +15 -7
  26. package/dist/lexer/lexer.js.map +1 -1
  27. package/dist/lexer/token_type.d.ts +3 -1
  28. package/dist/lexer/token_type.d.ts.map +1 -1
  29. package/dist/lexer/token_type.js +2 -0
  30. package/dist/lexer/token_type.js.map +1 -1
  31. package/dist/linter/linter.d.ts +46 -0
  32. package/dist/linter/linter.d.ts.map +1 -0
  33. package/dist/linter/linter.js +166 -0
  34. package/dist/linter/linter.js.map +1 -0
  35. package/dist/parser/parse_result.d.ts +2 -0
  36. package/dist/parser/parse_result.d.ts.map +1 -1
  37. package/dist/parser/parser.d.ts.map +1 -1
  38. package/dist/parser/parser.js +117 -21
  39. package/dist/parser/parser.js.map +1 -1
  40. package/dist/semantic/symbol_table.d.ts +1 -0
  41. package/dist/semantic/symbol_table.d.ts.map +1 -1
  42. package/dist/semantic/symbol_table.js +11 -0
  43. package/dist/semantic/symbol_table.js.map +1 -1
  44. package/dist/semantic/type_checker.d.ts +7 -0
  45. package/dist/semantic/type_checker.d.ts.map +1 -1
  46. package/dist/semantic/type_checker.js +187 -72
  47. package/dist/semantic/type_checker.js.map +1 -1
  48. package/dist/tsconfig.tsbuildinfo +1 -0
  49. package/package.json +1 -1
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Linter JADE — analisa o AST e reporta problemas de estilo e qualidade.
3
+ *
4
+ * Regras implementadas:
5
+ * NOME001 Entidade/Classe/Evento/Interface deve ser PascalCase
6
+ * NOME002 Função/Serviço deve iniciar com letra minúscula
7
+ * NOME003 Valores de enum devem ser UPPER_CASE
8
+ * NOME004 Variável deve iniciar com letra minúscula
9
+ * VAZIO001 Função com corpo vazio
10
+ * VAZIO002 Entidade sem campos
11
+ * VAZIO003 Serviço sem métodos nem ouvintes
12
+ * PARAM001 Função com mais de 5 parâmetros
13
+ * VAR001 Variável declarada sem tipo nem inicializador
14
+ * MORT001 Código morto — instrução após retornar
15
+ */
16
+ export class Linter {
17
+ warnings = [];
18
+ lint(program) {
19
+ this.warnings = [];
20
+ for (const decl of program.declaracoes) {
21
+ this.checkDeclaracao(decl);
22
+ }
23
+ return this.warnings;
24
+ }
25
+ // ── Declarações ──────────────────────────────────────────────────────────
26
+ checkDeclaracao(node) {
27
+ switch (node.kind) {
28
+ case 'Entidade':
29
+ this.checkEntidade(node);
30
+ break;
31
+ case 'Classe':
32
+ this.checkClasse(node);
33
+ break;
34
+ case 'Servico':
35
+ this.checkServico(node);
36
+ break;
37
+ case 'Funcao':
38
+ this.checkFuncao(node);
39
+ break;
40
+ case 'Evento':
41
+ this.checkEvento(node);
42
+ break;
43
+ case 'Interface':
44
+ this.checkInterface(node);
45
+ break;
46
+ case 'Enum':
47
+ this.checkEnum(node);
48
+ break;
49
+ case 'Modulo':
50
+ for (const d of node.declaracoes)
51
+ this.checkDeclaracao(d);
52
+ break;
53
+ }
54
+ }
55
+ checkEntidade(node) {
56
+ this.assertPascalCase(node.nome, 'NOME001', 'Entidade', node.line, node.column);
57
+ if (node.campos.length === 0) {
58
+ this.warn('VAZIO002', `Entidade '${node.nome}' não tem campos`, node.line, node.column);
59
+ }
60
+ }
61
+ checkClasse(node) {
62
+ this.assertPascalCase(node.nome, 'NOME001', 'Classe', node.line, node.column);
63
+ for (const metodo of node.metodos)
64
+ this.checkFuncao(metodo);
65
+ }
66
+ checkServico(node) {
67
+ this.assertCamelCase(node.nome, 'NOME002', 'Serviço', node.line, node.column);
68
+ if (node.metodos.length === 0 && node.ouvintes.length === 0) {
69
+ this.warn('VAZIO003', `Serviço '${node.nome}' não tem métodos nem ouvintes`, node.line, node.column);
70
+ }
71
+ for (const metodo of node.metodos)
72
+ this.checkFuncao(metodo);
73
+ for (const ouvinte of node.ouvintes)
74
+ this.checkBloco(ouvinte.corpo);
75
+ }
76
+ checkFuncao(node) {
77
+ this.assertCamelCase(node.nome, 'NOME002', 'Função', node.line, node.column);
78
+ if (node.parametros.length > 5) {
79
+ this.warn('PARAM001', `Função '${node.nome}' tem ${node.parametros.length} parâmetros — considere agrupar em uma entidade`, node.line, node.column);
80
+ }
81
+ if (node.corpo.instrucoes.length === 0) {
82
+ this.warn('VAZIO001', `Função '${node.nome}' tem corpo vazio`, node.line, node.column);
83
+ }
84
+ this.checkBloco(node.corpo);
85
+ }
86
+ checkEvento(node) {
87
+ this.assertPascalCase(node.nome, 'NOME001', 'Evento', node.line, node.column);
88
+ }
89
+ checkInterface(node) {
90
+ this.assertPascalCase(node.nome, 'NOME001', 'Interface', node.line, node.column);
91
+ }
92
+ checkEnum(node) {
93
+ this.assertPascalCase(node.nome, 'NOME001', 'Enum', node.line, node.column);
94
+ for (const valor of node.valores) {
95
+ if (!this.isUpperCase(valor)) {
96
+ this.warn('NOME003', `Valor de enum '${valor}' deve ser UPPER_CASE (ex: ${valor.toUpperCase()})`, node.line, node.column);
97
+ }
98
+ }
99
+ }
100
+ // ── Bloco e instruções ───────────────────────────────────────────────────
101
+ checkBloco(bloco) {
102
+ const instrucoes = bloco.instrucoes;
103
+ for (let i = 0; i < instrucoes.length; i++) {
104
+ const instr = instrucoes[i];
105
+ this.checkInstrucao(instr);
106
+ // MORT001 — código morto após retornar
107
+ if (instr.kind === 'Retorno' && i < instrucoes.length - 1) {
108
+ const proxima = instrucoes[i + 1];
109
+ this.warn('MORT001', 'Código morto — instrução após retornar nunca será executada', proxima.line, proxima.column, 'error');
110
+ break; // não reporta múltiplos por bloco
111
+ }
112
+ }
113
+ }
114
+ checkInstrucao(node) {
115
+ switch (node.kind) {
116
+ case 'Variavel':
117
+ this.assertCamelCase(node.nome, 'NOME004', 'Variável', node.line, node.column);
118
+ if (!node.tipo && !node.inicializador) {
119
+ this.warn('VAR001', `Variável '${node.nome}' declarada sem tipo nem valor inicial`, node.line, node.column);
120
+ }
121
+ break;
122
+ case 'Condicional':
123
+ this.checkBloco(node.entao);
124
+ if (node.senao)
125
+ this.checkBloco(node.senao);
126
+ break;
127
+ case 'Enquanto':
128
+ this.checkBloco(node.corpo);
129
+ break;
130
+ case 'Para':
131
+ this.checkBloco(node.corpo);
132
+ break;
133
+ }
134
+ }
135
+ // ── Helpers de nomenclatura ──────────────────────────────────────────────
136
+ assertPascalCase(nome, code, tipo, line, col) {
137
+ if (!this.isPascalCase(nome)) {
138
+ this.warn(code, `${tipo} '${nome}' deve usar PascalCase (ex: ${this.toPascalCase(nome)})`, line, col);
139
+ }
140
+ }
141
+ assertCamelCase(nome, code, tipo, line, col) {
142
+ if (!this.isCamelCase(nome)) {
143
+ this.warn(code, `${tipo} '${nome}' deve iniciar com letra minúscula (ex: ${this.toCamelCase(nome)})`, line, col);
144
+ }
145
+ }
146
+ isPascalCase(nome) {
147
+ return /^[A-Z][a-zA-Z0-9]*$/.test(nome);
148
+ }
149
+ isCamelCase(nome) {
150
+ return /^[a-z][a-zA-Z0-9]*$/.test(nome);
151
+ }
152
+ isUpperCase(nome) {
153
+ return /^[A-Z][A-Z0-9_]*$/.test(nome);
154
+ }
155
+ toPascalCase(nome) {
156
+ return nome.charAt(0).toUpperCase() + nome.slice(1);
157
+ }
158
+ toCamelCase(nome) {
159
+ return nome.charAt(0).toLowerCase() + nome.slice(1);
160
+ }
161
+ // ── Emissão ──────────────────────────────────────────────────────────────
162
+ warn(code, message, line, column, severity = 'warning') {
163
+ this.warnings.push({ code, message, line, column, severity });
164
+ }
165
+ }
166
+ //# sourceMappingURL=linter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linter.js","sourceRoot":"","sources":["../../linter/linter.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,8 @@ export interface ParseError {
3
3
  message: string;
4
4
  line: number;
5
5
  column: number;
6
+ /** Dica educativa sobre como corrigir o erro */
7
+ dica?: string;
6
8
  }
7
9
  export interface ParseResult {
8
10
  program: ProgramaNode | null;
@@ -1 +1 @@
1
- {"version":3,"file":"parse_result.d.ts","sourceRoot":"","sources":["../../parser/parse_result.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;CAClB"}
1
+ {"version":3,"file":"parse_result.d.ts","sourceRoot":"","sources":["../../parser/parse_result.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;CAClB"}
@@ -1 +1 @@
1
- {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../parser/parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C,OAAO,EAAE,WAAW,EAAc,MAAM,mBAAmB,CAAC;AAG5D,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,MAAM,CAAoB;gBAEtB,MAAM,EAAE,KAAK,EAAE;IAI3B,KAAK,IAAI,WAAW;IAkCpB,OAAO,CAAC,eAAe;IAoBvB,OAAO,CAAC,WAAW;IAqBnB,OAAO,CAAC,WAAW;IAyCnB,OAAO,CAAC,aAAa;IAoBrB,OAAO,CAAC,YAAY;IA4BpB,OAAO,CAAC,WAAW;IAkCnB,OAAO,CAAC,WAAW;IAoBnB,OAAO,CAAC,UAAU;IA0BlB,OAAO,CAAC,cAAc;IA2CtB,OAAO,CAAC,SAAS;IAqBjB,OAAO,CAAC,eAAe;IA6BvB,OAAO,CAAC,SAAS;IAwBjB,OAAO,CAAC,iBAAiB;IA2EzB,OAAO,CAAC,UAAU;IA2BlB,OAAO,CAAC,cAAc;IA2BtB,OAAO,CAAC,SAAS;IA8DjB,OAAO,CAAC,YAAY;IAepB,OAAO,CAAC,UAAU;IA4BlB,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,aAAa;IAwBrB,OAAO,CAAC,wBAAwB;IA4GhC,OAAO,CAAC,YAAY;IAepB,OAAO,CAAC,gBAAgB;IAgCxB,OAAO,CAAC,sBAAsB;IA6B9B,OAAO,CAAC,aAAa;IAcrB,OAAO,CAAC,SAAS;IAkBjB,OAAO,CAAC,kBAAkB;IAsB1B,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,oBAAoB;IAsB5B,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,wBAAwB;IAsBhC,OAAO,CAAC,wBAAwB;IAoBhC,OAAO,CAAC,UAAU;IAoBlB,OAAO,CAAC,UAAU;IAiBlB,OAAO,CAAC,aAAa;IA8HrB,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,OAAO;IAKf,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,KAAK;IAKb,OAAO,CAAC,KAAK;IAUb,OAAO,CAAC,OAAO;IAKf,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,KAAK;IASb,OAAO,CAAC,WAAW;CAuBpB"}
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../parser/parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C,OAAO,EAAE,WAAW,EAAc,MAAM,mBAAmB,CAAC;AA8G5D,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,MAAM,CAAoB;gBAEtB,MAAM,EAAE,KAAK,EAAE;IAI3B,KAAK,IAAI,WAAW;IAgDpB,OAAO,CAAC,eAAe;IAoBvB,OAAO,CAAC,WAAW;IA+BnB,OAAO,CAAC,WAAW;IAyCnB,OAAO,CAAC,aAAa;IAwBrB,OAAO,CAAC,YAAY;IA4BpB,OAAO,CAAC,WAAW;IAkCnB,OAAO,CAAC,WAAW;IAwBnB,OAAO,CAAC,UAAU;IA0BlB,OAAO,CAAC,cAAc;IA2CtB,OAAO,CAAC,SAAS;IAqBjB,OAAO,CAAC,eAAe;IA6BvB,OAAO,CAAC,SAAS;IA4BjB,OAAO,CAAC,iBAAiB;IA2EzB,OAAO,CAAC,UAAU;IA4BlB,OAAO,CAAC,cAAc;IA4BtB,OAAO,CAAC,SAAS;IA+DjB,OAAO,CAAC,YAAY;IAepB,OAAO,CAAC,UAAU;IAgClB,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,aAAa;IAwBrB,OAAO,CAAC,wBAAwB;IA4GhC,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,gBAAgB;IAgCxB,OAAO,CAAC,sBAAsB;IA6B9B,OAAO,CAAC,aAAa;IAcrB,OAAO,CAAC,SAAS;IAkBjB,OAAO,CAAC,kBAAkB;IAsB1B,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,oBAAoB;IAsB5B,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,wBAAwB;IAsBhC,OAAO,CAAC,wBAAwB;IAoBhC,OAAO,CAAC,UAAU;IAoBlB,OAAO,CAAC,UAAU;IAiBlB,OAAO,CAAC,aAAa;IAkIrB,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,OAAO;IAKf,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,KAAK;IAKb,OAAO,CAAC,KAAK;IAUb,OAAO,CAAC,OAAO;IAKf,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,KAAK;IAUb,OAAO,CAAC,WAAW;CAuBpB"}
@@ -1,4 +1,60 @@
1
1
  import { TokenType } from '../lexer/token_type.js';
2
+ /**
3
+ * Tabela de dicas educativas para erros de sintaxe.
4
+ * Mapeamento: mensagem de erro → dica de como corrigir.
5
+ */
6
+ const DICAS_PARSER = {
7
+ "Esperado nome do módulo": "Dê um nome ao módulo logo após a palavra 'modulo', ex: `modulo estoque`",
8
+ "Esperado 'fim' para fechar módulo": "Todo bloco 'modulo' precisa terminar com 'fim'",
9
+ "Esperado nome da classe": "Dê um nome à classe, ex: `classe Funcionario`",
10
+ "Esperado nome da superclasse": "Informe o nome da classe pai após 'extends', ex: `classe Gerente extends Funcionario`",
11
+ "Esperado nome da interface": "Informe o nome da interface após 'implements', ex: `classe Produto implements Estocavel`",
12
+ "Esperado 'fim' para fechar classe": "Todo bloco 'classe' precisa terminar com 'fim'",
13
+ "Esperado nome da entidade": "Dê um nome à entidade, ex: `entidade Produto`",
14
+ "Esperado 'fim' para fechar entidade": "Todo bloco 'entidade' precisa terminar com 'fim'",
15
+ "Esperado nome do serviço": "Dê um nome ao serviço, ex: `servico EstoqueService`",
16
+ "Esperado 'funcao' ou 'escutar' no serviço": "Dentro de um serviço só pode haver funções (`funcao nome()`) e ouvintes de evento (`escutar NomeEvento`)",
17
+ "Esperado 'fim' para fechar serviço": "Todo bloco 'servico' precisa terminar com 'fim'",
18
+ "Esperado nome da função": "Dê um nome à função, ex: `funcao calcularTotal()`",
19
+ "Esperado '('": "A declaração de função precisa de parênteses, mesmo sem parâmetros: `funcao nome()`",
20
+ "Esperado ')'": "Feche os parênteses — pode estar faltando ')' após os parâmetros ou argumentos",
21
+ "Esperado 'fim' para fechar função": "Todo bloco 'funcao' precisa terminar com 'fim'",
22
+ "Esperado nome do evento": "Dê um nome ao evento, ex: `evento PedidoCriado`",
23
+ "Esperado 'fim' para fechar evento": "Todo bloco 'evento' precisa terminar com 'fim'",
24
+ "Esperado nome da regra": "Dê um nome à regra, ex: `regra reposicaoAutomatica`",
25
+ "Esperado 'quando'": "A regra precisa de uma condição após o nome: `regra nome quando produto.estoque < 10`",
26
+ "Esperado 'entao'": "Após a condição do 'quando', use 'entao' para definir o que acontece: `quando x > 0 entao`",
27
+ "Esperado 'fim' para fechar regra": "Todo bloco 'regra' precisa terminar com 'fim'",
28
+ "Esperado 'funcao' na interface": "Interfaces só podem declarar assinaturas de função: `funcao nome(param: tipo) -> tipo`",
29
+ "Esperado nome da assinatura": "Dê um nome à assinatura da função na interface, ex: `funcao calcular(x: numero) -> numero`",
30
+ "Esperado '->'": "Informe o tipo de retorno após '->', ex: `funcao calcular() -> numero`",
31
+ "Esperado 'fim' para fechar interface": "Todo bloco 'interface' precisa terminar com 'fim'",
32
+ "Esperado nome do enum": "Dê um nome ao enum, ex: `enum StatusPedido`",
33
+ "Esperado valor do enum": "Liste os valores do enum, um por linha, em letras maiúsculas, ex: PENDENTE, CONFIRMADO, CANCELADO",
34
+ "Esperado 'fim' para fechar enum": "Todo bloco 'enum' precisa terminar com 'fim'",
35
+ "Esperado item importado": "Informe o item do módulo: `importar estoque.Produto`, ou use alias: `importar estoque como est`",
36
+ "Esperado alias": "Informe o nome alternativo após 'como', ex: `importar estoque como est`",
37
+ "Esperado nome da tela": "Dê um nome à tela, ex: `tela ListaProdutos \"Produtos\"`",
38
+ "Esperado título da tela entre aspas": "Informe o título da tela entre aspas logo após o nome: `tela ListaProdutos \"Lista de Produtos\"`",
39
+ "Esperado 'fim' para fechar tela": "Todo bloco 'tela' precisa terminar com 'fim'",
40
+ "Esperado tipo do elemento (tabela, formulario, botao, card)": "Use um dos tipos de elemento: tabela, formulario, botao, card, modal ou grafico",
41
+ "Esperado nome do elemento": "Dê um nome ao elemento da tela, ex: `tabela listagem`",
42
+ "Esperado nome da propriedade": "Informe o nome da propriedade seguido de ':', ex: `entidade: Produto`",
43
+ "Esperado ':' após nome da propriedade": "Use ':' para separar nome e valor da propriedade, ex: `titulo: \"Meu Título\"`",
44
+ "Esperado identificador": "Informe um nome válido (começa com letra, sem espaços)",
45
+ "Esperado valor para a propriedade": "O valor pode ser texto entre aspas, um identificador ou verdadeiro/falso",
46
+ "Esperado nome do campo": "O campo precisa de um nome seguido de ':', ex: `nome: texto`",
47
+ "Esperado ':'": "Use ':' para declarar o tipo do campo, ex: `preco: decimal`",
48
+ "Esperado '<'": "Especifique o tipo do elemento entre '<' e '>', ex: `lista<texto>` ou `lista<Produto>`",
49
+ "Esperado '>'": "Feche o tipo genérico com '>', ex: `lista<texto>` ou `mapa<texto, numero>`",
50
+ "Esperado tipo": "Informe um tipo válido: texto, numero, decimal, booleano, data, hora, id, lista<T> ou mapa<K,V>",
51
+ "Esperado nome da variável": "Dê um nome à variável, ex: `variavel total: numero` ou `variavel nome = \"João\"`",
52
+ "Esperado nome do membro após '.'": "Informe o nome do campo ou método após o ponto, ex: `produto.preco`",
53
+ "Esperado ')' após expressão": "Feche os parênteses da expressão",
54
+ "Esperado ')' após argumentos": "Feche os parênteses dos argumentos da função",
55
+ "Esperado nome do membro": "Informe o nome do campo ou método após o ponto",
56
+ "Esperado ','": "Separe os tipos com vírgula, ex: `mapa<texto, numero>`",
57
+ };
2
58
  export class Parser {
3
59
  tokens;
4
60
  current = 0;
@@ -10,17 +66,33 @@ export class Parser {
10
66
  const declaracoes = [];
11
67
  while (!this.isAtEnd()) {
12
68
  try {
69
+ const before = this.current;
13
70
  const declaracao = this.parseDeclaracao();
14
71
  if (declaracao) {
15
72
  declaracoes.push(declaracao);
16
73
  }
74
+ else if (this.current === before) {
75
+ // Token não reconhecido como declaração — registra erro e avança para não travar
76
+ this.errors.push({
77
+ message: `Token inesperado '${this.peek().value}' — esperado início de declaração (modulo, entidade, funcao, servico, etc.)`,
78
+ line: this.peek().line,
79
+ column: this.peek().column
80
+ });
81
+ this.advance();
82
+ }
17
83
  }
18
84
  catch (error) {
19
- this.errors.push({
20
- message: error.message || 'Erro de sintaxe',
21
- line: this.peek().line,
22
- column: this.peek().column
23
- });
85
+ // ParseError thrown by consume/error() already has line, column and dica
86
+ if (error && typeof error.line === 'number' && typeof error.column === 'number') {
87
+ this.errors.push(error);
88
+ }
89
+ else {
90
+ this.errors.push({
91
+ message: error.message || 'Erro de sintaxe',
92
+ line: this.peek().line,
93
+ column: this.peek().column
94
+ });
95
+ }
24
96
  this.synchronize();
25
97
  }
26
98
  }
@@ -72,9 +144,15 @@ export class Parser {
72
144
  const nome = nomeToken.value;
73
145
  const declaracoes = [];
74
146
  while (!this.check(TokenType.FIM) && !this.isAtEnd()) {
147
+ const before = this.current;
75
148
  const declaracao = this.parseDeclaracao();
76
- if (declaracao)
149
+ if (declaracao) {
77
150
  declaracoes.push(declaracao);
151
+ }
152
+ else if (this.current === before) {
153
+ // Token não reconhecido dentro do módulo — lança erro para sair do loop
154
+ throw this.error(`Token inesperado '${this.peek().value}' dentro do módulo`, undefined, "Verifique se uma declaração está incompleta ou se há 'fim' faltando");
155
+ }
78
156
  }
79
157
  this.consume(TokenType.FIM, "Esperado 'fim' para fechar módulo");
80
158
  return {
@@ -125,7 +203,11 @@ export class Parser {
125
203
  const nome = nomeToken.value;
126
204
  const campos = [];
127
205
  while (!this.check(TokenType.FIM) && !this.isAtEnd()) {
206
+ const before = this.current;
128
207
  campos.push(this.parseCampo());
208
+ if (this.current === before) {
209
+ throw this.error(`Token inesperado '${this.peek().value}' na entidade — esperado nome de campo`);
210
+ }
129
211
  }
130
212
  this.consume(TokenType.FIM, "Esperado 'fim' para fechar entidade");
131
213
  return {
@@ -194,7 +276,11 @@ export class Parser {
194
276
  const nome = nomeToken.value;
195
277
  const campos = [];
196
278
  while (!this.check(TokenType.FIM) && !this.isAtEnd()) {
279
+ const before = this.current;
197
280
  campos.push(this.parseCampo());
281
+ if (this.current === before) {
282
+ throw this.error(`Token inesperado '${this.peek().value}' no evento — esperado nome de campo`);
283
+ }
198
284
  }
199
285
  this.consume(TokenType.FIM, "Esperado 'fim' para fechar evento");
200
286
  return {
@@ -311,10 +397,14 @@ export class Parser {
311
397
  const nomeToken = this.consume(TokenType.IDENTIFICADOR, "Esperado nome da tela");
312
398
  const nome = nomeToken.value;
313
399
  const tituloToken = this.consume(TokenType.LITERAL_TEXTO, "Esperado título da tela entre aspas");
314
- const titulo = tituloToken.value;
400
+ const titulo = tituloToken.value.slice(1, -1);
315
401
  const elementos = [];
316
402
  while (!this.check(TokenType.FIM) && !this.isAtEnd()) {
403
+ const before = this.current;
317
404
  elementos.push(this.parseTelaElemento());
405
+ if (this.current === before) {
406
+ throw this.error(`Token inesperado '${this.peek().value}' na tela — esperado elemento (tabela, formulario, botao, card)`);
407
+ }
318
408
  }
319
409
  this.consume(TokenType.FIM, "Esperado 'fim' para fechar tela");
320
410
  return {
@@ -354,7 +444,7 @@ export class Parser {
354
444
  }
355
445
  else if (this.checkAny([
356
446
  TokenType.IDENTIFICADOR,
357
- TokenType.TIPO_TEXTO, TokenType.TIPO_NUMERO, TokenType.TIPO_DECIMAL,
447
+ TokenType.TIPO_TEXTO, TokenType.TIPO_NUMERO, TokenType.TIPO_DECIMAL, TokenType.TIPO_MOEDA,
358
448
  TokenType.TIPO_BOOLEANO, TokenType.TIPO_DATA, TokenType.TIPO_HORA,
359
449
  TokenType.TIPO_ID, TokenType.TIPO_LISTA, TokenType.TIPO_MAPA
360
450
  ])) {
@@ -373,7 +463,7 @@ export class Parser {
373
463
  while (this.match(TokenType.VIRGULA)) {
374
464
  lista.push(this.consumeAny([
375
465
  TokenType.IDENTIFICADOR,
376
- TokenType.TIPO_TEXTO, TokenType.TIPO_NUMERO, TokenType.TIPO_DECIMAL,
466
+ TokenType.TIPO_TEXTO, TokenType.TIPO_NUMERO, TokenType.TIPO_DECIMAL, TokenType.TIPO_MOEDA,
377
467
  TokenType.TIPO_BOOLEANO, TokenType.TIPO_DATA, TokenType.TIPO_HORA,
378
468
  TokenType.TIPO_ID
379
469
  ], "Esperado identificador").value);
@@ -406,6 +496,7 @@ export class Parser {
406
496
  TokenType.TIPO_TEXTO,
407
497
  TokenType.TIPO_NUMERO,
408
498
  TokenType.TIPO_DECIMAL,
499
+ TokenType.TIPO_MOEDA,
409
500
  TokenType.TIPO_BOOLEANO,
410
501
  TokenType.TIPO_DATA,
411
502
  TokenType.TIPO_HORA,
@@ -431,6 +522,7 @@ export class Parser {
431
522
  TokenType.TIPO_TEXTO,
432
523
  TokenType.TIPO_NUMERO,
433
524
  TokenType.TIPO_DECIMAL,
525
+ TokenType.TIPO_MOEDA,
434
526
  TokenType.TIPO_BOOLEANO,
435
527
  TokenType.TIPO_DATA,
436
528
  TokenType.TIPO_HORA,
@@ -481,6 +573,7 @@ export class Parser {
481
573
  TokenType.TIPO_TEXTO,
482
574
  TokenType.TIPO_NUMERO,
483
575
  TokenType.TIPO_DECIMAL,
576
+ TokenType.TIPO_MOEDA,
484
577
  TokenType.TIPO_BOOLEANO,
485
578
  TokenType.TIPO_DATA,
486
579
  TokenType.TIPO_HORA,
@@ -531,7 +624,7 @@ export class Parser {
531
624
  if (this.isAtEnd()) {
532
625
  break;
533
626
  }
534
- throw this.error(`Parser travado: token inesperado ${this.peek().type}='${this.peek().value}'`);
627
+ throw this.error(`Token inesperado '${this.peek().value}' — verifique se um 'fim' está faltando acima desta linha`, undefined, "Erros desse tipo costumam acontecer quando um bloco (entidade, funcao, servico, se...) não foi fechado com 'fim'");
535
628
  }
536
629
  }
537
630
  return {
@@ -675,18 +768,20 @@ export class Parser {
675
768
  }
676
769
  // Token consumido mas não reconhecido como instrução válida
677
770
  // Volta o token para não perder (usando current--)
678
- this.current--;
771
+ if (this.current > 0)
772
+ this.current--;
679
773
  return null;
680
774
  }
681
775
  parseRetorno() {
776
+ const retornarToken = this.previous(); // 'retornar' já consumido por match()
682
777
  let valor;
683
778
  if (!this.check(TokenType.FIM) && !this.check(TokenType.EOF)) {
684
779
  valor = this.parseExpressao();
685
780
  }
686
781
  return {
687
782
  kind: 'Retorno',
688
- line: 1,
689
- column: 1,
783
+ line: retornarToken.line,
784
+ column: retornarToken.column,
690
785
  valor
691
786
  };
692
787
  }
@@ -985,7 +1080,7 @@ export class Parser {
985
1080
  const membroToken = this.consumeAny([
986
1081
  TokenType.IDENTIFICADOR,
987
1082
  TokenType.TIPO_ID, TokenType.TIPO_TEXTO, TokenType.TIPO_NUMERO,
988
- TokenType.TIPO_DECIMAL, TokenType.TIPO_BOOLEANO, TokenType.TIPO_DATA,
1083
+ TokenType.TIPO_DECIMAL, TokenType.TIPO_MOEDA, TokenType.TIPO_BOOLEANO, TokenType.TIPO_DATA,
989
1084
  TokenType.TIPO_HORA, TokenType.TIPO_LISTA, TokenType.TIPO_MAPA, TokenType.TIPO_OBJETO
990
1085
  ], "Esperado nome do membro");
991
1086
  if (this.match(TokenType.ABRE_PAREN)) {
@@ -1011,7 +1106,7 @@ export class Parser {
1011
1106
  nome: token.value
1012
1107
  };
1013
1108
  }
1014
- throw this.error(`Expressão inesperada: ${this.peek().value}`);
1109
+ throw this.error(`Expressão inesperada: '${this.peek().value}'`, undefined, "Use um valor (número, texto, verdadeiro/falso), uma variável, chamada de função ou expressão entre parênteses");
1015
1110
  }
1016
1111
  // ── Utilitários ───────────────────────────────────────────
1017
1112
  peek() {
@@ -1046,27 +1141,28 @@ export class Parser {
1046
1141
  }
1047
1142
  return false;
1048
1143
  }
1049
- consume(type, message) {
1144
+ consume(type, message, dica) {
1050
1145
  if (this.check(type))
1051
1146
  return this.advance();
1052
- throw this.error(message);
1147
+ throw this.error(message, undefined, dica);
1053
1148
  }
1054
- consumeAny(types, message) {
1149
+ consumeAny(types, message, dica) {
1055
1150
  for (const type of types) {
1056
1151
  if (this.check(type))
1057
1152
  return this.advance();
1058
1153
  }
1059
- throw this.error(message);
1154
+ throw this.error(message, undefined, dica);
1060
1155
  }
1061
1156
  isAtEnd() {
1062
1157
  return this.peek().type === TokenType.EOF;
1063
1158
  }
1064
- error(message, token) {
1159
+ error(message, token, dica) {
1065
1160
  const errorToken = token || this.peek();
1066
1161
  return {
1067
1162
  message,
1068
1163
  line: errorToken.line,
1069
- column: errorToken.column
1164
+ column: errorToken.column,
1165
+ dica: dica ?? DICAS_PARSER[message]
1070
1166
  };
1071
1167
  }
1072
1168
  synchronize() {