@yakuzaa/jade-compiler 0.1.0

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 (65) hide show
  1. package/dist/ast/nodes.d.ts +219 -0
  2. package/dist/ast/nodes.d.ts.map +1 -0
  3. package/dist/ast/nodes.js +2 -0
  4. package/dist/ast/nodes.js.map +1 -0
  5. package/dist/cli.d.ts +14 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +108 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/codegen/ir_generator.d.ts +42 -0
  10. package/dist/codegen/ir_generator.d.ts.map +1 -0
  11. package/dist/codegen/ir_generator.js +691 -0
  12. package/dist/codegen/ir_generator.js.map +1 -0
  13. package/dist/codegen/ir_nodes.d.ts +143 -0
  14. package/dist/codegen/ir_nodes.d.ts.map +1 -0
  15. package/dist/codegen/ir_nodes.js +3 -0
  16. package/dist/codegen/ir_nodes.js.map +1 -0
  17. package/dist/codegen/ir_printer.d.ts +10 -0
  18. package/dist/codegen/ir_printer.d.ts.map +1 -0
  19. package/dist/codegen/ir_printer.js +131 -0
  20. package/dist/codegen/ir_printer.js.map +1 -0
  21. package/dist/codegen/wasm_generator.d.ts +12 -0
  22. package/dist/codegen/wasm_generator.d.ts.map +1 -0
  23. package/dist/codegen/wasm_generator.js +48 -0
  24. package/dist/codegen/wasm_generator.js.map +1 -0
  25. package/dist/codegen/wat_generator.d.ts +29 -0
  26. package/dist/codegen/wat_generator.d.ts.map +1 -0
  27. package/dist/codegen/wat_generator.js +345 -0
  28. package/dist/codegen/wat_generator.js.map +1 -0
  29. package/dist/index.d.ts +61 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +79 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/lexer/lexer.d.ts +31 -0
  34. package/dist/lexer/lexer.d.ts.map +1 -0
  35. package/dist/lexer/lexer.js +475 -0
  36. package/dist/lexer/lexer.js.map +1 -0
  37. package/dist/lexer/token.d.ts +8 -0
  38. package/dist/lexer/token.d.ts.map +1 -0
  39. package/dist/lexer/token.js +2 -0
  40. package/dist/lexer/token.js.map +1 -0
  41. package/dist/lexer/token_type.d.ts +80 -0
  42. package/dist/lexer/token_type.d.ts.map +1 -0
  43. package/dist/lexer/token_type.js +98 -0
  44. package/dist/lexer/token_type.js.map +1 -0
  45. package/dist/parser/parse_result.d.ts +12 -0
  46. package/dist/parser/parse_result.d.ts.map +1 -0
  47. package/dist/parser/parse_result.js +2 -0
  48. package/dist/parser/parse_result.js.map +1 -0
  49. package/dist/parser/parser.d.ts +57 -0
  50. package/dist/parser/parser.d.ts.map +1 -0
  51. package/dist/parser/parser.js +1094 -0
  52. package/dist/parser/parser.js.map +1 -0
  53. package/dist/semantic/semantic_analyzer.d.ts +10 -0
  54. package/dist/semantic/semantic_analyzer.d.ts.map +1 -0
  55. package/dist/semantic/semantic_analyzer.js +16 -0
  56. package/dist/semantic/semantic_analyzer.js.map +1 -0
  57. package/dist/semantic/symbol_table.d.ts +33 -0
  58. package/dist/semantic/symbol_table.d.ts.map +1 -0
  59. package/dist/semantic/symbol_table.js +105 -0
  60. package/dist/semantic/symbol_table.js.map +1 -0
  61. package/dist/semantic/type_checker.d.ts +66 -0
  62. package/dist/semantic/type_checker.d.ts.map +1 -0
  63. package/dist/semantic/type_checker.js +963 -0
  64. package/dist/semantic/type_checker.js.map +1 -0
  65. package/package.json +84 -0
@@ -0,0 +1,691 @@
1
+ export class IRGenerator {
2
+ module;
3
+ currentFunction = null;
4
+ currentBlock = null;
5
+ tempCounter = 0;
6
+ blockCounter = 0;
7
+ constructor(moduleName) {
8
+ this.module = {
9
+ name: moduleName,
10
+ typeDefinitions: [],
11
+ globals: [],
12
+ functions: []
13
+ };
14
+ }
15
+ generate(program) {
16
+ // Passo 1: registrar todos os tipos (entidades/classes)
17
+ for (const declaracao of program.declaracoes) {
18
+ if (declaracao.kind === 'Entidade') {
19
+ this.generateEntidade(declaracao);
20
+ }
21
+ else if (declaracao.kind === 'Classe') {
22
+ this.generateClasse(declaracao);
23
+ }
24
+ }
25
+ // Passo 2: gerar funções
26
+ for (const declaracao of program.declaracoes) {
27
+ if (declaracao.kind === 'Funcao') {
28
+ this.generateFuncao(declaracao);
29
+ }
30
+ else if (declaracao.kind === 'Servico') {
31
+ this.generateServico(declaracao);
32
+ }
33
+ else if (declaracao.kind === 'Tela') {
34
+ // Telas são tratadas pelo UIEngine em runtime — sem geração de IR
35
+ }
36
+ }
37
+ return this.module;
38
+ }
39
+ // ── Geradores de declaração ──────────────────────────────
40
+ generateEntidade(node) {
41
+ const fields = node.campos.map(campo => ({
42
+ name: campo.nome,
43
+ type: this.jadeTypeToIR(campo.tipo)
44
+ }));
45
+ this.module.typeDefinitions.push({
46
+ name: node.nome,
47
+ fields
48
+ });
49
+ }
50
+ generateClasse(node) {
51
+ const fields = node.campos.map(campo => ({
52
+ name: campo.nome,
53
+ type: this.jadeTypeToIR(campo.tipo)
54
+ }));
55
+ this.module.typeDefinitions.push({
56
+ name: node.nome,
57
+ fields
58
+ });
59
+ }
60
+ generateFuncao(node) {
61
+ const parameters = node.parametros.map(param => ({
62
+ name: '%' + param.nome,
63
+ type: this.jadeTypeToIR(param.tipo)
64
+ }));
65
+ const returnType = node.tipoRetorno ? this.jadeTypeToIR(node.tipoRetorno) : 'void';
66
+ const func = {
67
+ name: '@' + node.nome,
68
+ parameters,
69
+ returnType,
70
+ blocks: [],
71
+ locals: []
72
+ };
73
+ this.currentFunction = func;
74
+ this.module.functions.push(func);
75
+ // Criar bloco entry
76
+ const entryBlock = this.createBlock('entry');
77
+ this.switchToBlock(entryBlock);
78
+ // Gerar corpo da função
79
+ this.generateBloco(node.corpo);
80
+ // Garantir que o último bloco tem terminador
81
+ if (this.currentBlock && !this.currentBlock.terminator) {
82
+ this.setTerminator({ kind: 'Return' });
83
+ }
84
+ this.currentFunction = null;
85
+ this.currentBlock = null;
86
+ }
87
+ generateServico(node) {
88
+ // Gera cada método como função independente
89
+ // Nome: '@NomeServico_nomeFuncao'
90
+ for (const metodo of node.metodos) {
91
+ const parameters = metodo.parametros.map(param => ({
92
+ name: '%' + param.nome,
93
+ type: this.jadeTypeToIR(param.tipo)
94
+ }));
95
+ const returnType = metodo.tipoRetorno ? this.jadeTypeToIR(metodo.tipoRetorno) : 'void';
96
+ const func = {
97
+ name: '@' + node.nome + '_' + metodo.nome,
98
+ parameters,
99
+ returnType,
100
+ blocks: [],
101
+ locals: []
102
+ };
103
+ this.currentFunction = func;
104
+ this.module.functions.push(func);
105
+ // Criar bloco entry
106
+ const entryBlock = this.createBlock('entry');
107
+ this.switchToBlock(entryBlock);
108
+ // Gerar corpo do método
109
+ this.generateBloco(metodo.corpo);
110
+ // Garantir que o último bloco tem terminador
111
+ if (this.currentBlock && !this.currentBlock.terminator) {
112
+ this.setTerminator({ kind: 'Return' });
113
+ }
114
+ this.currentFunction = null;
115
+ this.currentBlock = null;
116
+ }
117
+ }
118
+ // ── Geradores de instrução ───────────────────────────────
119
+ generateBloco(node) {
120
+ for (const instrucao of node.instrucoes) {
121
+ this.generateInstrucao(instrucao);
122
+ }
123
+ }
124
+ generateInstrucao(node) {
125
+ switch (node.kind) {
126
+ case 'Variavel':
127
+ this.generateVariavel(node);
128
+ break;
129
+ case 'Atribuicao':
130
+ this.generateAtribuicao(node);
131
+ break;
132
+ case 'Condicional':
133
+ this.generateCondicional(node);
134
+ break;
135
+ case 'Enquanto':
136
+ this.generateEnquanto(node);
137
+ break;
138
+ case 'Para':
139
+ this.generatePara(node);
140
+ break;
141
+ case 'Retorno':
142
+ this.generateRetorno(node);
143
+ break;
144
+ case 'Erro':
145
+ this.generateErro(node);
146
+ break;
147
+ case 'EmissaoEvento':
148
+ this.generateEmissaoEvento(node);
149
+ break;
150
+ case 'ChamadaFuncao':
151
+ this.generateExpressao(node); // Chamada como instrução
152
+ break;
153
+ }
154
+ }
155
+ generateVariavel(node) {
156
+ const type = node.tipo ? this.jadeTypeToIR(node.tipo) : 'void';
157
+ if (node.inicializador) {
158
+ const value = this.generateExpressao(node.inicializador);
159
+ this.emit({
160
+ kind: 'Store',
161
+ target: '%' + node.nome,
162
+ value,
163
+ type
164
+ });
165
+ }
166
+ else {
167
+ // Se não tem inicializador: emite Store com valor zero do tipo
168
+ const zeroValue = {
169
+ kind: 'Constant',
170
+ type,
171
+ value: type === 'i1' ? false : type === 'f64' ? 0.0 : 0
172
+ };
173
+ this.emit({
174
+ kind: 'Store',
175
+ target: '%' + node.nome,
176
+ value: zeroValue,
177
+ type
178
+ });
179
+ }
180
+ }
181
+ generateAtribuicao(node) {
182
+ const value = this.generateExpressao(node.valor);
183
+ if (typeof node.alvo === 'string') {
184
+ // Se alvo é string: Store simples
185
+ this.emit({
186
+ kind: 'Store',
187
+ target: '%' + node.alvo,
188
+ value,
189
+ type: 'void' // Tipo será inferido do valor
190
+ });
191
+ }
192
+ else {
193
+ // Se alvo é AcessoMembro: SetField
194
+ const objeto = this.generateExpressao(node.alvo.objeto);
195
+ this.emit({
196
+ kind: 'SetField',
197
+ object: objeto,
198
+ field: node.alvo.membro,
199
+ value,
200
+ type: 'void'
201
+ });
202
+ }
203
+ }
204
+ generateCondicional(node) {
205
+ // Cria blocos: 'then_N', 'else_N', 'merge_N'
206
+ const thenBlock = this.createBlock(this.newBlockLabel('then'));
207
+ const elseBlock = this.createBlock(this.newBlockLabel('else'));
208
+ const mergeBlock = this.createBlock(this.newBlockLabel('merge'));
209
+ // Gera condição → CondBranch
210
+ const condition = this.generateExpressao(node.condicao);
211
+ this.setTerminator({
212
+ kind: 'CondBranch',
213
+ condition,
214
+ trueBlock: thenBlock.label,
215
+ falseBlock: node.senao ? elseBlock.label : mergeBlock.label
216
+ });
217
+ // Gera corpo then → Branch para merge
218
+ this.switchToBlock(thenBlock);
219
+ this.generateBloco(node.entao);
220
+ if (this.currentBlock && !this.currentBlock.terminator) {
221
+ this.setTerminator({ kind: 'Branch', target: mergeBlock.label });
222
+ }
223
+ // Gera corpo else (se houver) → Branch para merge
224
+ if (node.senao) {
225
+ this.switchToBlock(elseBlock);
226
+ this.generateBloco(node.senao);
227
+ if (this.currentBlock && !this.currentBlock.terminator) {
228
+ this.setTerminator({ kind: 'Branch', target: mergeBlock.label });
229
+ }
230
+ }
231
+ // Continua no bloco merge
232
+ this.switchToBlock(mergeBlock);
233
+ }
234
+ generateEnquanto(node) {
235
+ // Cria blocos: 'loop_header_N', 'loop_body_N', 'loop_exit_N'
236
+ const headerBlock = this.createBlock(this.newBlockLabel('loop_header'));
237
+ const bodyBlock = this.createBlock(this.newBlockLabel('loop_body'));
238
+ const exitBlock = this.createBlock(this.newBlockLabel('loop_exit'));
239
+ // Branch para header
240
+ this.setTerminator({ kind: 'Branch', target: headerBlock.label });
241
+ // Header: avalia condição → CondBranch body/exit
242
+ this.switchToBlock(headerBlock);
243
+ const condition = this.generateExpressao(node.condicao);
244
+ this.setTerminator({
245
+ kind: 'CondBranch',
246
+ condition,
247
+ trueBlock: bodyBlock.label,
248
+ falseBlock: exitBlock.label
249
+ });
250
+ // Body: gera instruções → Branch para header
251
+ this.switchToBlock(bodyBlock);
252
+ this.generateBloco(node.corpo);
253
+ if (this.currentBlock && !this.currentBlock.terminator) {
254
+ this.setTerminator({ kind: 'Branch', target: headerBlock.label });
255
+ }
256
+ // Continua no exit
257
+ this.switchToBlock(exitBlock);
258
+ }
259
+ generatePara(node) {
260
+ // 1. Obter a lista e seu tamanho
261
+ const lista = this.generateExpressao(node.iteravel);
262
+ const lenVar = this.newTemp();
263
+ this.emit({
264
+ kind: 'Call',
265
+ result: lenVar,
266
+ callee: '@jade_lista_tamanho',
267
+ args: [lista],
268
+ returnType: 'i32'
269
+ });
270
+ // 2. Inicializar contador %i = 0
271
+ const iVar = this.newTemp();
272
+ this.emit({
273
+ kind: 'Store',
274
+ target: iVar,
275
+ value: { kind: 'Constant', type: 'i32', value: 0 },
276
+ type: 'i32'
277
+ });
278
+ // 3. Criar blocos
279
+ const headerBlock = this.createBlock(this.newBlockLabel('loop_header'));
280
+ const bodyBlock = this.createBlock(this.newBlockLabel('loop_body'));
281
+ const exitBlock = this.createBlock(this.newBlockLabel('loop_exit'));
282
+ // Branch para header
283
+ this.setTerminator({ kind: 'Branch', target: headerBlock.label });
284
+ // 4. loop_header: condição %i < %len → body, senão → exit
285
+ this.switchToBlock(headerBlock);
286
+ const iLoadHeader = this.newTemp();
287
+ this.emit({
288
+ kind: 'Load',
289
+ result: iLoadHeader,
290
+ source: iVar,
291
+ type: 'i32'
292
+ });
293
+ const condVar = this.newTemp();
294
+ this.emit({
295
+ kind: 'BinaryOp',
296
+ result: condVar,
297
+ op: 'lt',
298
+ left: { kind: 'LocalRef', name: iLoadHeader, type: 'i32' },
299
+ right: { kind: 'LocalRef', name: lenVar, type: 'i32' },
300
+ type: 'i1'
301
+ });
302
+ this.setTerminator({
303
+ kind: 'CondBranch',
304
+ condition: { kind: 'LocalRef', name: condVar, type: 'i1' },
305
+ trueBlock: bodyBlock.label,
306
+ falseBlock: exitBlock.label
307
+ });
308
+ // 5. loop_body: obter elemento, gerar corpo, incrementar %i
309
+ this.switchToBlock(bodyBlock);
310
+ const iLoadBody = this.newTemp();
311
+ this.emit({
312
+ kind: 'Load',
313
+ result: iLoadBody,
314
+ source: iVar,
315
+ type: 'i32'
316
+ });
317
+ const elemVar = this.newTemp();
318
+ this.emit({
319
+ kind: 'Call',
320
+ result: elemVar,
321
+ callee: '@jade_lista_obter',
322
+ args: [lista, { kind: 'LocalRef', name: iLoadBody, type: 'i32' }],
323
+ returnType: 'ptr'
324
+ });
325
+ this.emit({
326
+ kind: 'Store',
327
+ target: '%' + node.variavel,
328
+ value: { kind: 'LocalRef', name: elemVar, type: 'ptr' },
329
+ type: 'ptr'
330
+ });
331
+ this.generateBloco(node.corpo);
332
+ if (this.currentBlock && this.currentBlock.terminator.kind === 'Unreachable') {
333
+ const iLoadInc = this.newTemp();
334
+ this.emit({
335
+ kind: 'Load',
336
+ result: iLoadInc,
337
+ source: iVar,
338
+ type: 'i32'
339
+ });
340
+ const iPlusOne = this.newTemp();
341
+ this.emit({
342
+ kind: 'BinaryOp',
343
+ result: iPlusOne,
344
+ op: 'add',
345
+ left: { kind: 'LocalRef', name: iLoadInc, type: 'i32' },
346
+ right: { kind: 'Constant', type: 'i32', value: 1 },
347
+ type: 'i32'
348
+ });
349
+ this.emit({
350
+ kind: 'Store',
351
+ target: iVar,
352
+ value: { kind: 'LocalRef', name: iPlusOne, type: 'i32' },
353
+ type: 'i32'
354
+ });
355
+ this.setTerminator({ kind: 'Branch', target: headerBlock.label });
356
+ }
357
+ // 6. Continua no exit
358
+ this.switchToBlock(exitBlock);
359
+ }
360
+ generateRetorno(node) {
361
+ // Se tem valor: gera expressão → Return com valor
362
+ // Se não tem: Return sem valor
363
+ if (node.valor) {
364
+ const value = this.generateExpressao(node.valor);
365
+ this.setTerminator({ kind: 'Return', value });
366
+ }
367
+ else {
368
+ this.setTerminator({ kind: 'Return' });
369
+ }
370
+ }
371
+ generateErro(node) {
372
+ // Emite Call para função runtime @jade_erro
373
+ const mensagem = this.generateExpressao(node.mensagem);
374
+ this.emit({
375
+ kind: 'Call',
376
+ callee: '@jade_erro',
377
+ args: [mensagem],
378
+ returnType: 'void'
379
+ });
380
+ // Emite Unreachable (erro nunca retorna)
381
+ this.setTerminator({ kind: 'Unreachable' });
382
+ }
383
+ generateEmissaoEvento(node) {
384
+ // Emite Call para função runtime @jade_emitir_evento
385
+ const args = node.argumentos.map(arg => this.generateExpressao(arg));
386
+ this.emit({
387
+ kind: 'Call',
388
+ callee: '@jade_emitir_evento',
389
+ args: [{ kind: 'Constant', type: 'ptr', value: node.evento }, ...args],
390
+ returnType: 'void'
391
+ });
392
+ }
393
+ // ── Geradores de expressão (retornam IRValue) ────────────
394
+ generateExpressao(node) {
395
+ switch (node.kind) {
396
+ case 'Literal':
397
+ return this.generateLiteral(node);
398
+ case 'Identificador':
399
+ return this.generateIdentificador(node);
400
+ case 'Binario':
401
+ return this.generateBinario(node);
402
+ case 'Unario':
403
+ return this.generateUnario(node);
404
+ case 'ChamadaFuncao':
405
+ return this.generateChamadaFuncao(node);
406
+ case 'AcessoMembro':
407
+ return this.generateAcessoMembro(node);
408
+ case 'Atribuicao':
409
+ this.generateAtribuicao(node);
410
+ // Retornar valor atribuído
411
+ return this.generateExpressao(node.valor);
412
+ default:
413
+ throw new Error(`Expressão não suportada: ${node.kind}`);
414
+ }
415
+ }
416
+ generateLiteral(node) {
417
+ // Retorna IRConstant com o valor e tipo corretos
418
+ let type;
419
+ let value = node.valor;
420
+ switch (node.tipoLiteral) {
421
+ case 'texto':
422
+ type = 'ptr';
423
+ break;
424
+ case 'numero':
425
+ type = 'i32';
426
+ value = Number(node.valor);
427
+ break;
428
+ case 'decimal':
429
+ type = 'f64';
430
+ value = Number(node.valor);
431
+ break;
432
+ case 'booleano':
433
+ type = 'i1';
434
+ value = Boolean(node.valor);
435
+ break;
436
+ case 'data':
437
+ case 'hora':
438
+ type = 'ptr';
439
+ break;
440
+ default:
441
+ type = 'ptr';
442
+ }
443
+ return {
444
+ kind: 'Constant',
445
+ type,
446
+ value
447
+ };
448
+ }
449
+ generateIdentificador(node) {
450
+ // Emite Load da variável local
451
+ const result = this.newTemp();
452
+ // Busca tipo nos parâmetros da função atual
453
+ const param = this.currentFunction?.parameters.find(p => p.name === '%' + node.nome || p.name === node.nome);
454
+ // Busca tipo nas variáveis locais da função atual
455
+ const local = this.currentFunction?.locals.find(l => l.name === '%' + node.nome || l.name === node.nome);
456
+ const type = param?.type || local?.type || 'i32';
457
+ this.emit({
458
+ kind: 'Load',
459
+ result,
460
+ source: '%' + node.nome,
461
+ type
462
+ });
463
+ return {
464
+ kind: 'LocalRef',
465
+ name: result,
466
+ type
467
+ };
468
+ }
469
+ generateBinario(node) {
470
+ // Gera esquerda e direita
471
+ const left = this.generateExpressao(node.esquerda);
472
+ const right = this.generateExpressao(node.direita);
473
+ const result = this.newTemp();
474
+ const op = this.mapOperator(node.operador);
475
+ // Concatenação de texto: op '+' com operando esquerdo do tipo 'ptr'
476
+ if (op === 'add' && left.type === 'ptr') {
477
+ this.emit({
478
+ kind: 'Call',
479
+ result,
480
+ callee: '@jade_concat',
481
+ args: [left, right],
482
+ returnType: 'ptr'
483
+ });
484
+ return { kind: 'LocalRef', name: result, type: 'ptr' };
485
+ }
486
+ // Propaga tipo do operando esquerdo
487
+ const type = left.type !== 'void' ? left.type : right.type !== 'void' ? right.type : 'i32';
488
+ // Operadores de comparação sempre retornam i1
489
+ const resultType = ['eq', 'ne', 'lt', 'le', 'gt', 'ge', 'and', 'or'].includes(op) ? 'i1' : type;
490
+ this.emit({
491
+ kind: 'BinaryOp',
492
+ result,
493
+ op,
494
+ left,
495
+ right,
496
+ type: resultType
497
+ });
498
+ return {
499
+ kind: 'LocalRef',
500
+ name: result,
501
+ type: resultType
502
+ };
503
+ }
504
+ generateUnario(node) {
505
+ const operand = this.generateExpressao(node.operando);
506
+ const result = this.newTemp();
507
+ const op = node.operador === '-' ? 'neg' : 'not';
508
+ const type = operand.type !== 'void' ? operand.type : 'i32';
509
+ const resultType = op === 'not' ? 'i1' : type;
510
+ this.emit({
511
+ kind: 'UnaryOp',
512
+ result,
513
+ op,
514
+ operand,
515
+ type: resultType
516
+ });
517
+ return {
518
+ kind: 'LocalRef',
519
+ name: result,
520
+ type: resultType
521
+ };
522
+ }
523
+ generateChamadaFuncao(node) {
524
+ const args = node.argumentos.map(arg => this.generateExpressao(arg));
525
+ const result = this.newTemp();
526
+ // Busca o tipo de retorno na lista de funções do módulo
527
+ const funcIR = this.module.functions.find(f => f.name === '@' + node.nome || f.name === node.nome);
528
+ const returnType = funcIR?.returnType || 'void';
529
+ this.emit({
530
+ kind: 'Call',
531
+ result: returnType === 'void' ? undefined : result,
532
+ callee: '@' + node.nome,
533
+ args,
534
+ returnType
535
+ });
536
+ if (returnType === 'void') {
537
+ return { kind: 'Constant', type: 'void', value: 0 };
538
+ }
539
+ return {
540
+ kind: 'LocalRef',
541
+ name: result,
542
+ type: returnType
543
+ };
544
+ }
545
+ generateAcessoMembro(node) {
546
+ // Gera objeto
547
+ const object = this.generateExpressao(node.objeto);
548
+ // Emite GetField
549
+ const result = this.newTemp();
550
+ const type = 'void'; // TODO: Obter tipo do campo
551
+ this.emit({
552
+ kind: 'GetField',
553
+ result,
554
+ object,
555
+ field: node.membro,
556
+ type
557
+ });
558
+ return {
559
+ kind: 'LocalRef',
560
+ name: result,
561
+ type
562
+ };
563
+ }
564
+ // ── Utilitários ──────────────────────────────────────────
565
+ newTemp() {
566
+ return `%t${this.tempCounter++}`;
567
+ }
568
+ newBlockLabel(prefix) {
569
+ return `${prefix}_${this.blockCounter++}`;
570
+ }
571
+ emit(instruction) {
572
+ if (!this.currentBlock) {
573
+ throw new Error('Não há bloco atual para emitir instrução');
574
+ }
575
+ this.currentBlock.instructions.push(instruction);
576
+ this.declareLocalIfNeeded(instruction);
577
+ }
578
+ declareLocalIfNeeded(instr) {
579
+ if (!this.currentFunction)
580
+ return;
581
+ let name;
582
+ let type;
583
+ switch (instr.kind) {
584
+ case 'BinaryOp':
585
+ name = instr.result;
586
+ type = instr.type;
587
+ break;
588
+ case 'UnaryOp':
589
+ name = instr.result;
590
+ type = instr.type;
591
+ break;
592
+ case 'Load':
593
+ name = instr.result;
594
+ type = instr.type;
595
+ break;
596
+ case 'GetField':
597
+ name = instr.result;
598
+ type = instr.type;
599
+ break;
600
+ case 'Assign':
601
+ name = instr.result;
602
+ type = instr.type;
603
+ break;
604
+ case 'Alloc':
605
+ name = instr.result;
606
+ type = 'ptr';
607
+ break;
608
+ case 'Call':
609
+ if (instr.result) {
610
+ name = instr.result;
611
+ type = instr.returnType;
612
+ }
613
+ break;
614
+ case 'Store':
615
+ name = instr.target;
616
+ type = instr.type;
617
+ break;
618
+ }
619
+ if (!name || !type || type === 'void')
620
+ return;
621
+ const isParam = this.currentFunction.parameters.some(p => p.name === name);
622
+ if (isParam)
623
+ return;
624
+ const alreadyDeclared = this.currentFunction.locals.some(l => l.name === name);
625
+ if (alreadyDeclared)
626
+ return;
627
+ this.currentFunction.locals.push({ name, type });
628
+ }
629
+ setTerminator(terminator) {
630
+ if (!this.currentBlock) {
631
+ throw new Error('Não há bloco atual para definir terminador');
632
+ }
633
+ this.currentBlock.terminator = terminator;
634
+ }
635
+ switchToBlock(block) {
636
+ this.currentBlock = block;
637
+ }
638
+ createBlock(label) {
639
+ if (!this.currentFunction) {
640
+ throw new Error('Não há função atual para criar bloco');
641
+ }
642
+ const block = {
643
+ label,
644
+ instructions: [],
645
+ terminator: { kind: 'Unreachable' }
646
+ };
647
+ this.currentFunction.blocks.push(block);
648
+ return block;
649
+ }
650
+ jadeTypeToIR(type) {
651
+ switch (type.kind) {
652
+ case 'TipoSimples':
653
+ const nome = type.nome;
654
+ // Mapeamento tipo JADE → IRType
655
+ switch (nome) {
656
+ case 'numero': return 'i32';
657
+ case 'decimal': return 'f64';
658
+ case 'booleano': return 'i1';
659
+ case 'texto': return 'ptr';
660
+ case 'id': return 'ptr';
661
+ case 'data': return 'ptr';
662
+ case 'hora': return 'ptr';
663
+ default: return 'ptr'; // classes/entidades são ponteiros
664
+ }
665
+ case 'TipoLista':
666
+ case 'TipoMapa':
667
+ case 'TipoObjeto':
668
+ return 'ptr';
669
+ default:
670
+ return 'ptr';
671
+ }
672
+ }
673
+ mapOperator(op) {
674
+ switch (op) {
675
+ case '+': return 'add';
676
+ case '-': return 'sub';
677
+ case '*': return 'mul';
678
+ case '/': return 'div';
679
+ case '==': return 'eq';
680
+ case '!=': return 'ne';
681
+ case '<': return 'lt';
682
+ case '<=': return 'le';
683
+ case '>': return 'gt';
684
+ case '>=': return 'ge';
685
+ case 'e': return 'and';
686
+ case 'ou': return 'or';
687
+ default: throw new Error(`Operador não suportado: ${op}`);
688
+ }
689
+ }
690
+ }
691
+ //# sourceMappingURL=ir_generator.js.map