@designliquido/delegua 1.13.2 → 1.15.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.
- package/analisador-documentario/index.d.ts +1 -1
- package/analisador-semantico/analisador-semantico.d.ts.map +1 -1
- package/analisador-semantico/analisador-semantico.js +12 -2
- package/analisador-semantico/analisador-semantico.js.map +1 -1
- package/avaliador-sintatico/avaliador-sintatico.d.ts.map +1 -1
- package/avaliador-sintatico/avaliador-sintatico.js +10 -0
- package/avaliador-sintatico/avaliador-sintatico.js.map +1 -1
- package/avaliador-sintatico/dialetos/avaliador-sintatico-calango.d.ts +25 -5
- package/avaliador-sintatico/dialetos/avaliador-sintatico-calango.d.ts.map +1 -1
- package/avaliador-sintatico/dialetos/avaliador-sintatico-calango.js +301 -25
- package/avaliador-sintatico/dialetos/avaliador-sintatico-calango.js.map +1 -1
- package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.d.ts.map +1 -1
- package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.js +4 -10
- package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.js.map +1 -1
- package/avaliador-sintatico/dialetos/avaliador-sintatico-tenda.d.ts.map +1 -1
- package/avaliador-sintatico/dialetos/avaliador-sintatico-tenda.js +33 -2
- package/avaliador-sintatico/dialetos/avaliador-sintatico-tenda.js.map +1 -1
- package/bibliotecas/biblioteca-global.d.ts.map +1 -1
- package/bibliotecas/biblioteca-global.js +3 -7
- package/bibliotecas/biblioteca-global.js.map +1 -1
- package/bibliotecas/dialetos/tenda/biblioteca-global.d.ts +3 -0
- package/bibliotecas/dialetos/tenda/biblioteca-global.d.ts.map +1 -0
- package/bibliotecas/dialetos/tenda/biblioteca-global.js +365 -0
- package/bibliotecas/dialetos/tenda/biblioteca-global.js.map +1 -0
- package/bin/package.json +1 -1
- package/construtos/vetor.d.ts.map +1 -1
- package/construtos/vetor.js.map +1 -1
- package/interfaces/documentario/documentario-analisado.d.ts +2 -2
- package/interfaces/documentario/index.d.ts +3 -3
- package/interpretador/depuracao/interpretador-com-depuracao.d.ts.map +1 -1
- package/interpretador/depuracao/interpretador-com-depuracao.js +8 -0
- package/interpretador/depuracao/interpretador-com-depuracao.js.map +1 -1
- package/interpretador/dialetos/calango/interpretador-calango.d.ts +2 -0
- package/interpretador/dialetos/calango/interpretador-calango.d.ts.map +1 -1
- package/interpretador/dialetos/calango/interpretador-calango.js +15 -0
- package/interpretador/dialetos/calango/interpretador-calango.js.map +1 -1
- package/interpretador/dialetos/index.d.ts +1 -0
- package/interpretador/dialetos/index.d.ts.map +1 -1
- package/interpretador/dialetos/index.js +1 -0
- package/interpretador/dialetos/index.js.map +1 -1
- package/interpretador/dialetos/pitugues/interpretador-pitugues.d.ts.map +1 -1
- package/interpretador/dialetos/pitugues/interpretador-pitugues.js.map +1 -1
- package/interpretador/dialetos/tenda/index.d.ts +2 -0
- package/interpretador/dialetos/tenda/index.d.ts.map +1 -0
- package/interpretador/dialetos/tenda/index.js +18 -0
- package/interpretador/dialetos/tenda/index.js.map +1 -0
- package/interpretador/dialetos/tenda/interpretador-tenda.d.ts +13 -0
- package/interpretador/dialetos/tenda/interpretador-tenda.d.ts.map +1 -0
- package/interpretador/dialetos/tenda/interpretador-tenda.js +31 -0
- package/interpretador/dialetos/tenda/interpretador-tenda.js.map +1 -0
- package/interpretador/interpretador.d.ts +2 -1
- package/interpretador/interpretador.d.ts.map +1 -1
- package/interpretador/interpretador.js +24 -1
- package/interpretador/interpretador.js.map +1 -1
- package/interpretador/pilha-escopos-execucao.d.ts.map +1 -1
- package/interpretador/pilha-escopos-execucao.js +3 -0
- package/interpretador/pilha-escopos-execucao.js.map +1 -1
- package/lexador/dialetos/lexador-calango.d.ts +1 -0
- package/lexador/dialetos/lexador-calango.d.ts.map +1 -1
- package/lexador/dialetos/lexador-calango.js +77 -0
- package/lexador/dialetos/lexador-calango.js.map +1 -1
- package/lexador/dialetos/lexador-pitugues.d.ts.map +1 -1
- package/lexador/dialetos/lexador-pitugues.js +2 -4
- package/lexador/dialetos/lexador-pitugues.js.map +1 -1
- package/lexador/dialetos/palavras-reservadas/calango.d.ts +31 -4
- package/lexador/dialetos/palavras-reservadas/calango.d.ts.map +1 -1
- package/lexador/dialetos/palavras-reservadas/calango.js +31 -4
- package/lexador/dialetos/palavras-reservadas/calango.js.map +1 -1
- package/package.json +1 -1
- package/tipos-de-simbolos/calango.d.ts +28 -0
- package/tipos-de-simbolos/calango.d.ts.map +1 -1
- package/tipos-de-simbolos/calango.js +28 -0
- package/tipos-de-simbolos/calango.js.map +1 -1
- package/tradutores/index.d.ts +2 -0
- package/tradutores/index.d.ts.map +1 -1
- package/tradutores/index.js +2 -0
- package/tradutores/index.js.map +1 -1
- package/tradutores/tradutor-assembly-risc-v.d.ts +99 -0
- package/tradutores/tradutor-assembly-risc-v.d.ts.map +1 -0
- package/tradutores/tradutor-assembly-risc-v.js +685 -0
- package/tradutores/tradutor-assembly-risc-v.js.map +1 -0
- package/tradutores/tradutor-assemblyscript.js +1 -1
- package/tradutores/tradutor-assemblyscript.js.map +1 -1
- package/tradutores/tradutor-webassembly.d.ts +159 -0
- package/tradutores/tradutor-webassembly.d.ts.map +1 -0
- package/tradutores/tradutor-webassembly.js +901 -0
- package/tradutores/tradutor-webassembly.js.map +1 -0
- package/umd/delegua.js +2066 -279
|
@@ -0,0 +1,901 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TradutorWebAssembly = void 0;
|
|
4
|
+
const construtos_1 = require("../construtos");
|
|
5
|
+
const declaracoes_1 = require("../declaracoes");
|
|
6
|
+
class TradutorWebAssembly {
|
|
7
|
+
constructor() {
|
|
8
|
+
// ── Seções do módulo WAT ───────────────────────────────────────────────
|
|
9
|
+
/** Segmentos de dados estáticos para strings literais */
|
|
10
|
+
this.segmentosTexto = [];
|
|
11
|
+
/** Próximo byte livre na memória linear para strings */
|
|
12
|
+
this.deslocamentoTexto = 0;
|
|
13
|
+
/** Texto WAT completo de cada função declarada pelo usuário */
|
|
14
|
+
this.funcoesCompletas = [];
|
|
15
|
+
/** Declarações WAT de variáveis globais `(global ...)` */
|
|
16
|
+
this.declaracoesGlobais = [];
|
|
17
|
+
// ── Contexto da função sendo traduzida no momento ──────────────────────
|
|
18
|
+
/** Instruções WAT emitidas no corpo da função corrente */
|
|
19
|
+
this.corpoDaFuncaoAtual = '';
|
|
20
|
+
/** Declarações `(param ...)` e `(local ...)` da função corrente */
|
|
21
|
+
this.declaracoesLocaisAtual = '';
|
|
22
|
+
/** Nomes de locais/params já declarados (evita duplicatas) */
|
|
23
|
+
this.locaisDeclaradosAtual = new Set();
|
|
24
|
+
/** Estamos dentro do corpo de uma função nomeada? */
|
|
25
|
+
this.dentroFuncao = false;
|
|
26
|
+
/** A função corrente possui ao menos um `retorna` com valor? */
|
|
27
|
+
this.funcaoTemRetorno = false;
|
|
28
|
+
// ── Mapa de variáveis ─────────────────────────────────────────────────
|
|
29
|
+
/** Nome Delégua → metadados WAT */
|
|
30
|
+
this.variaveis = new Map();
|
|
31
|
+
// ── Controle de fluxo (break/continue) ───────────────────────────────
|
|
32
|
+
/** Pilha de rótulos de laço para `sustar`/`continua` */
|
|
33
|
+
this.pilhaDeControle = [];
|
|
34
|
+
// ── Geração de rótulos ────────────────────────────────────────────────
|
|
35
|
+
this.contadorRotulos = 0;
|
|
36
|
+
// =========================================================================
|
|
37
|
+
// Dicionário de construtos (expressões)
|
|
38
|
+
// =========================================================================
|
|
39
|
+
this.dicionarioConstrutos = {
|
|
40
|
+
AcessoIndiceVariavel: this.traduzirAcessoIndiceVariavel.bind(this),
|
|
41
|
+
AcessoMetodoOuPropriedade: this.traduzirAcessoMetodo.bind(this),
|
|
42
|
+
Agrupamento: this.traduzirAgrupamento.bind(this),
|
|
43
|
+
AtribuicaoPorIndice: this.traduzirAtribuicaoPorIndice.bind(this),
|
|
44
|
+
Atribuir: this.traduzirAtribuir.bind(this),
|
|
45
|
+
Binario: this.traduzirBinario.bind(this),
|
|
46
|
+
Chamada: this.traduzirChamada.bind(this),
|
|
47
|
+
DefinirValor: this.traduzirDefinirValor.bind(this),
|
|
48
|
+
FuncaoConstruto: this.traduzirFuncaoConstruto.bind(this),
|
|
49
|
+
Literal: this.traduzirLiteral.bind(this),
|
|
50
|
+
Logico: this.traduzirLogico.bind(this),
|
|
51
|
+
TipoDe: this.traduzirTipoDe.bind(this),
|
|
52
|
+
Unario: this.traduzirUnario.bind(this),
|
|
53
|
+
Variavel: this.traduzirVariavel.bind(this),
|
|
54
|
+
Vetor: this.traduzirVetor.bind(this),
|
|
55
|
+
};
|
|
56
|
+
// =========================================================================
|
|
57
|
+
// Dicionário de declarações (instruções)
|
|
58
|
+
// =========================================================================
|
|
59
|
+
this.dicionarioDeclaracoes = {
|
|
60
|
+
Bloco: this.traduzirBloco.bind(this),
|
|
61
|
+
Classe: this.traduzirClasse.bind(this),
|
|
62
|
+
Const: this.traduzirConst.bind(this),
|
|
63
|
+
Continua: this.traduzirContinua.bind(this),
|
|
64
|
+
Enquanto: this.traduzirEnquanto.bind(this),
|
|
65
|
+
Escolha: this.traduzirEscolha.bind(this),
|
|
66
|
+
Escreva: this.traduzirEscreva.bind(this),
|
|
67
|
+
EscrevaMesmaLinha: this.traduzirEscreva.bind(this),
|
|
68
|
+
Expressao: this.traduzirExpressao.bind(this),
|
|
69
|
+
Falhar: this.traduzirFalhar.bind(this),
|
|
70
|
+
Fazer: this.traduzirFazer.bind(this),
|
|
71
|
+
FuncaoDeclaracao: this.traduzirFuncaoDeclaracao.bind(this),
|
|
72
|
+
Importar: this.traduzirImportar.bind(this),
|
|
73
|
+
Para: this.traduzirPara.bind(this),
|
|
74
|
+
ParaCada: this.traduzirParaCada.bind(this),
|
|
75
|
+
Retorna: this.traduzirRetorna.bind(this),
|
|
76
|
+
Se: this.traduzirSe.bind(this),
|
|
77
|
+
Sustar: this.traduzirSustar.bind(this),
|
|
78
|
+
Tente: this.traduzirTente.bind(this),
|
|
79
|
+
Var: this.traduzirVar.bind(this),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
// =========================================================================
|
|
83
|
+
// Helpers internos
|
|
84
|
+
// =========================================================================
|
|
85
|
+
gerarRotulo() {
|
|
86
|
+
return `$L${this.contadorRotulos++}`;
|
|
87
|
+
}
|
|
88
|
+
/** Emite uma instrução indentada no corpo da função corrente. */
|
|
89
|
+
emitir(instrucao) {
|
|
90
|
+
this.corpoDaFuncaoAtual += ` ${instrucao}\n`;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Converte uma string JavaScript para bytes UTF-8.
|
|
94
|
+
* Usa `encodeURIComponent` para extrair os bytes — funciona em qualquer ambiente JS
|
|
95
|
+
* sem depender de APIs específicas de Node.js (Buffer) ou browser (TextEncoder).
|
|
96
|
+
*/
|
|
97
|
+
stringParaBytesUtf8(valor) {
|
|
98
|
+
const encoded = encodeURIComponent(valor);
|
|
99
|
+
const bytes = [];
|
|
100
|
+
for (let i = 0; i < encoded.length;) {
|
|
101
|
+
if (encoded[i] === '%') {
|
|
102
|
+
bytes.push(parseInt(encoded.slice(i + 1, i + 3), 16));
|
|
103
|
+
i += 3;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
bytes.push(encoded.charCodeAt(i));
|
|
107
|
+
i++;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return bytes;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Converte uma string JavaScript para o formato de literal de string WAT.
|
|
114
|
+
* Bytes não-ASCII e caracteres especiais são hex-escapados como `\xx`.
|
|
115
|
+
* Retorna o literal pronto para uso em `(data ...)` e o comprimento em bytes UTF-8.
|
|
116
|
+
*/
|
|
117
|
+
escaparStringWat(valor) {
|
|
118
|
+
const bytes = this.stringParaBytesUtf8(valor);
|
|
119
|
+
let watLiteral = '';
|
|
120
|
+
for (const byte of bytes) {
|
|
121
|
+
if (byte === 0x22) {
|
|
122
|
+
watLiteral += '\\"'; // aspas duplas
|
|
123
|
+
}
|
|
124
|
+
else if (byte === 0x5c) {
|
|
125
|
+
watLiteral += '\\\\'; // contrabarra
|
|
126
|
+
}
|
|
127
|
+
else if (byte >= 0x20 && byte <= 0x7e) {
|
|
128
|
+
watLiteral += String.fromCharCode(byte); // ASCII imprimível
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
watLiteral += `\\${byte.toString(16).padStart(2, '0')}`; // \xx
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return { watLiteral, byteLen: bytes.length };
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Internaliza uma string literal na memória linear estática.
|
|
138
|
+
* Strings idênticas são deduplicadas.
|
|
139
|
+
* O comprimento armazenado é o comprimento em bytes UTF-8, não em caracteres.
|
|
140
|
+
*/
|
|
141
|
+
internalizarTexto(valor) {
|
|
142
|
+
const existente = this.segmentosTexto.find((s) => s.conteudo === valor);
|
|
143
|
+
if (existente) {
|
|
144
|
+
return { offset: existente.deslocamento, len: existente.tamanho };
|
|
145
|
+
}
|
|
146
|
+
const { byteLen } = this.escaparStringWat(valor);
|
|
147
|
+
const offset = this.deslocamentoTexto;
|
|
148
|
+
this.segmentosTexto.push({ deslocamento: offset, conteudo: valor, tamanho: byteLen });
|
|
149
|
+
this.deslocamentoTexto += byteLen;
|
|
150
|
+
return { offset, len: byteLen };
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Infere o tipo WAT de um construto.
|
|
154
|
+
* Strings → i32 (ponteiro). Tudo mais → i64 (padrão, inclusive booleanos).
|
|
155
|
+
*/
|
|
156
|
+
inferirTipo(construto) {
|
|
157
|
+
if (construto instanceof construtos_1.Literal && typeof construto.valor === 'string')
|
|
158
|
+
return 'i32';
|
|
159
|
+
return 'i64';
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Declara um parâmetro ou variável local para a função corrente.
|
|
163
|
+
* `ehParam = true` emite `(param ...)`, senão `(local ...)`.
|
|
164
|
+
*/
|
|
165
|
+
declararParamLocal(nome, tipo, ehParam) {
|
|
166
|
+
if (this.locaisDeclaradosAtual.has(nome))
|
|
167
|
+
return;
|
|
168
|
+
this.locaisDeclaradosAtual.add(nome);
|
|
169
|
+
const watNome = `$${nome}`;
|
|
170
|
+
const diretiva = ehParam ? 'param' : 'local';
|
|
171
|
+
this.declaracoesLocaisAtual += ` (${diretiva} ${watNome} ${tipo})`;
|
|
172
|
+
this.variaveis.set(nome, { watNome, tipo, escopo: 'local' });
|
|
173
|
+
}
|
|
174
|
+
/** Salva o contexto da função corrente e inicializa um novo. */
|
|
175
|
+
salvarEIniciarContextoFuncao() {
|
|
176
|
+
const snapshot = {
|
|
177
|
+
corpoDaFuncaoAtual: this.corpoDaFuncaoAtual,
|
|
178
|
+
declaracoesLocaisAtual: this.declaracoesLocaisAtual,
|
|
179
|
+
locaisDeclaradosAtual: this.locaisDeclaradosAtual,
|
|
180
|
+
dentroFuncao: this.dentroFuncao,
|
|
181
|
+
funcaoTemRetorno: this.funcaoTemRetorno,
|
|
182
|
+
variaveis: new Map(this.variaveis),
|
|
183
|
+
};
|
|
184
|
+
this.corpoDaFuncaoAtual = '';
|
|
185
|
+
this.declaracoesLocaisAtual = '';
|
|
186
|
+
this.locaisDeclaradosAtual = new Set();
|
|
187
|
+
this.dentroFuncao = true;
|
|
188
|
+
this.funcaoTemRetorno = false;
|
|
189
|
+
// Remove locais do mapa — globais permanecem
|
|
190
|
+
for (const [nome, meta] of this.variaveis) {
|
|
191
|
+
if (meta.escopo === 'local')
|
|
192
|
+
this.variaveis.delete(nome);
|
|
193
|
+
}
|
|
194
|
+
return snapshot;
|
|
195
|
+
}
|
|
196
|
+
/** Restaura o contexto de função a partir de um snapshot. */
|
|
197
|
+
restaurarContextoFuncao(snapshot) {
|
|
198
|
+
this.corpoDaFuncaoAtual = snapshot.corpoDaFuncaoAtual;
|
|
199
|
+
this.declaracoesLocaisAtual = snapshot.declaracoesLocaisAtual;
|
|
200
|
+
this.locaisDeclaradosAtual = snapshot.locaisDeclaradosAtual;
|
|
201
|
+
this.dentroFuncao = snapshot.dentroFuncao;
|
|
202
|
+
this.funcaoTemRetorno = snapshot.funcaoTemRetorno;
|
|
203
|
+
this.variaveis = snapshot.variaveis;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Garante que uma variável existe no escopo correto.
|
|
207
|
+
* Retorna o nome WAT da variável (e.g. `$x`).
|
|
208
|
+
*/
|
|
209
|
+
garantirVariavel(nome, tipo = 'i64') {
|
|
210
|
+
if (this.variaveis.has(nome)) {
|
|
211
|
+
return this.variaveis.get(nome).watNome;
|
|
212
|
+
}
|
|
213
|
+
if (this.dentroFuncao) {
|
|
214
|
+
this.declararParamLocal(nome, tipo, false);
|
|
215
|
+
return `$${nome}`;
|
|
216
|
+
}
|
|
217
|
+
// Global
|
|
218
|
+
const watNome = `$${nome}`;
|
|
219
|
+
this.declaracoesGlobais.push(` (global ${watNome} (mut ${tipo}) (${tipo}.const 0))`);
|
|
220
|
+
this.variaveis.set(nome, { watNome, tipo, escopo: 'global' });
|
|
221
|
+
return watNome;
|
|
222
|
+
}
|
|
223
|
+
// =========================================================================
|
|
224
|
+
// Dispatch helpers
|
|
225
|
+
// =========================================================================
|
|
226
|
+
traduzirConstruto(construto) {
|
|
227
|
+
const handler = this.dicionarioConstrutos[construto.constructor.name];
|
|
228
|
+
if (handler)
|
|
229
|
+
return handler(construto);
|
|
230
|
+
return `(i64.const 0) ;; construto não suportado: ${construto.constructor.name}`;
|
|
231
|
+
}
|
|
232
|
+
traduzirDeclaracaoInterna(declaracao) {
|
|
233
|
+
const handler = this.dicionarioDeclaracoes[declaracao.constructor.name];
|
|
234
|
+
if (handler)
|
|
235
|
+
handler(declaracao);
|
|
236
|
+
else
|
|
237
|
+
this.emitir(`;; declaração não suportada: ${declaracao.constructor.name}`);
|
|
238
|
+
}
|
|
239
|
+
// =========================================================================
|
|
240
|
+
// Construtos
|
|
241
|
+
// =========================================================================
|
|
242
|
+
traduzirLiteral(construto) {
|
|
243
|
+
if (typeof construto.valor === 'boolean') {
|
|
244
|
+
return `(i64.const ${construto.valor ? 1 : 0})`;
|
|
245
|
+
}
|
|
246
|
+
if (typeof construto.valor === 'string') {
|
|
247
|
+
// Retorna apenas o ponteiro; `escreva` usa internalizarTexto diretamente
|
|
248
|
+
// para obter o comprimento também.
|
|
249
|
+
const { offset } = this.internalizarTexto(construto.valor);
|
|
250
|
+
return `(i32.const ${offset})`;
|
|
251
|
+
}
|
|
252
|
+
if (typeof construto.valor === 'bigint') {
|
|
253
|
+
return `(i64.const ${construto.valor})`;
|
|
254
|
+
}
|
|
255
|
+
// Número: trunca para i64
|
|
256
|
+
return `(i64.const ${Math.trunc(Number(construto.valor))})`;
|
|
257
|
+
}
|
|
258
|
+
traduzirVariavel(construto) {
|
|
259
|
+
var _a;
|
|
260
|
+
const nome = (_a = construto.simbolo) === null || _a === void 0 ? void 0 : _a.lexema;
|
|
261
|
+
if (!nome)
|
|
262
|
+
return '(i64.const 0)';
|
|
263
|
+
const meta = this.variaveis.get(nome);
|
|
264
|
+
if (!meta)
|
|
265
|
+
return `(i64.const 0) ;; variável desconhecida: ${nome}`;
|
|
266
|
+
const instrucao = meta.escopo === 'local' ? 'local.get' : 'global.get';
|
|
267
|
+
return `(${instrucao} ${meta.watNome})`;
|
|
268
|
+
}
|
|
269
|
+
traduzirAtribuir(construto) {
|
|
270
|
+
var _a;
|
|
271
|
+
let nome;
|
|
272
|
+
if (construto.alvo instanceof construtos_1.Variavel) {
|
|
273
|
+
nome = (_a = construto.alvo.simbolo) === null || _a === void 0 ? void 0 : _a.lexema;
|
|
274
|
+
}
|
|
275
|
+
if (!nome)
|
|
276
|
+
return '(i64.const 0)';
|
|
277
|
+
const tipoInferido = this.inferirTipo(construto.valor);
|
|
278
|
+
const watNome = this.garantirVariavel(nome, tipoInferido);
|
|
279
|
+
const valor = this.traduzirConstruto(construto.valor);
|
|
280
|
+
const meta = this.variaveis.get(nome);
|
|
281
|
+
const instrucao = meta.escopo === 'local' ? 'local.set' : 'global.set';
|
|
282
|
+
return `(${instrucao} ${watNome} ${valor})`;
|
|
283
|
+
}
|
|
284
|
+
traduzirBinario(construto) {
|
|
285
|
+
const esq = this.traduzirConstruto(construto.esquerda);
|
|
286
|
+
const dir = this.traduzirConstruto(construto.direita);
|
|
287
|
+
const op = construto.operador.lexema;
|
|
288
|
+
switch (op) {
|
|
289
|
+
case '+':
|
|
290
|
+
return `(i64.add ${esq} ${dir})`;
|
|
291
|
+
case '-':
|
|
292
|
+
return `(i64.sub ${esq} ${dir})`;
|
|
293
|
+
case '*':
|
|
294
|
+
return `(i64.mul ${esq} ${dir})`;
|
|
295
|
+
case '/':
|
|
296
|
+
return `(i64.div_s ${esq} ${dir})`;
|
|
297
|
+
case '%':
|
|
298
|
+
return `(i64.rem_s ${esq} ${dir})`;
|
|
299
|
+
case '<':
|
|
300
|
+
return `(i64.extend_i32_s (i64.lt_s ${esq} ${dir}))`;
|
|
301
|
+
case '>':
|
|
302
|
+
return `(i64.extend_i32_s (i64.gt_s ${esq} ${dir}))`;
|
|
303
|
+
case '<=':
|
|
304
|
+
return `(i64.extend_i32_s (i64.le_s ${esq} ${dir}))`;
|
|
305
|
+
case '>=':
|
|
306
|
+
return `(i64.extend_i32_s (i64.ge_s ${esq} ${dir}))`;
|
|
307
|
+
case '==':
|
|
308
|
+
case '===':
|
|
309
|
+
return `(i64.extend_i32_s (i64.eq ${esq} ${dir}))`;
|
|
310
|
+
case '!=':
|
|
311
|
+
case '!==':
|
|
312
|
+
return `(i64.extend_i32_s (i64.ne ${esq} ${dir}))`;
|
|
313
|
+
default:
|
|
314
|
+
return `(i64.const 0) ;; operador não suportado: ${op}`;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
traduzirLogico(construto) {
|
|
318
|
+
const esq = this.traduzirConstruto(construto.esquerda);
|
|
319
|
+
const dir = this.traduzirConstruto(construto.direita);
|
|
320
|
+
const op = construto.operador.lexema;
|
|
321
|
+
// Ambos os lados avaliados (sem curto-circuito na v1).
|
|
322
|
+
// Converte i64 → i32 (ne 0), aplica i32.and / i32.or, estende de volta.
|
|
323
|
+
const esqBool = `(i32.ne (i32.const 0) (i32.wrap_i64 ${esq}))`;
|
|
324
|
+
const dirBool = `(i32.ne (i32.const 0) (i32.wrap_i64 ${dir}))`;
|
|
325
|
+
if (op === 'e' || op === '&&') {
|
|
326
|
+
return `(i64.extend_i32_s (i32.and ${esqBool} ${dirBool}))`;
|
|
327
|
+
}
|
|
328
|
+
if (op === 'ou' || op === '||') {
|
|
329
|
+
return `(i64.extend_i32_s (i32.or ${esqBool} ${dirBool}))`;
|
|
330
|
+
}
|
|
331
|
+
return `(i64.const 0) ;; operador lógico não suportado: ${op}`;
|
|
332
|
+
}
|
|
333
|
+
traduzirUnario(construto) {
|
|
334
|
+
var _a;
|
|
335
|
+
const op = construto.operador.lexema;
|
|
336
|
+
const operando = this.traduzirConstruto(construto.operando);
|
|
337
|
+
if (op === '-') {
|
|
338
|
+
return `(i64.sub (i64.const 0) ${operando})`;
|
|
339
|
+
}
|
|
340
|
+
if (op === '!' || op === 'nao') {
|
|
341
|
+
return `(i64.extend_i32_s (i64.eqz ${operando}))`;
|
|
342
|
+
}
|
|
343
|
+
if (op === '++' || op === '--') {
|
|
344
|
+
// Apenas pré-incremento/decremento de variável simples na v1
|
|
345
|
+
let nome;
|
|
346
|
+
if (construto.operando instanceof construtos_1.Variavel) {
|
|
347
|
+
nome = (_a = construto.operando.simbolo) === null || _a === void 0 ? void 0 : _a.lexema;
|
|
348
|
+
}
|
|
349
|
+
if (!nome)
|
|
350
|
+
return operando;
|
|
351
|
+
const meta = this.variaveis.get(nome);
|
|
352
|
+
if (!meta)
|
|
353
|
+
return operando;
|
|
354
|
+
const instrSet = meta.escopo === 'local' ? 'local.set' : 'global.set';
|
|
355
|
+
const instrGet = meta.escopo === 'local' ? 'local.get' : 'global.get';
|
|
356
|
+
const delta = op === '++' ? 1 : -1;
|
|
357
|
+
const novoValor = `(i64.add ${operando} (i64.const ${delta}))`;
|
|
358
|
+
// Retorna uma sequência: set + get (usando local.tee para locais, ou set;get para globais)
|
|
359
|
+
if (meta.escopo === 'local') {
|
|
360
|
+
return `(local.tee ${meta.watNome} ${novoValor})`;
|
|
361
|
+
}
|
|
362
|
+
// Para globais não existe tee; emitimos o set e retornamos o get
|
|
363
|
+
this.emitir(`(${instrSet} ${meta.watNome} ${novoValor})`);
|
|
364
|
+
return `(${instrGet} ${meta.watNome})`;
|
|
365
|
+
}
|
|
366
|
+
return operando;
|
|
367
|
+
}
|
|
368
|
+
traduzirAgrupamento(construto) {
|
|
369
|
+
return this.traduzirConstruto(construto.expressao);
|
|
370
|
+
}
|
|
371
|
+
traduzirChamada(construto) {
|
|
372
|
+
var _a;
|
|
373
|
+
let nomeFuncao = 'desconhecida';
|
|
374
|
+
if (construto.entidadeChamada instanceof construtos_1.Variavel) {
|
|
375
|
+
nomeFuncao = ((_a = construto.entidadeChamada.simbolo) === null || _a === void 0 ? void 0 : _a.lexema) || 'desconhecida';
|
|
376
|
+
}
|
|
377
|
+
const args = construto.argumentos
|
|
378
|
+
.map((arg) => this.traduzirConstruto(arg))
|
|
379
|
+
.join(' ');
|
|
380
|
+
return `(call $${nomeFuncao}${args ? ' ' + args : ''})`;
|
|
381
|
+
}
|
|
382
|
+
traduzirAcessoIndiceVariavel(construto) {
|
|
383
|
+
var _a;
|
|
384
|
+
let baseExpr = '(i32.const 0)';
|
|
385
|
+
if (construto.entidadeChamada instanceof construtos_1.Variavel) {
|
|
386
|
+
const nome = (_a = construto.entidadeChamada.simbolo) === null || _a === void 0 ? void 0 : _a.lexema;
|
|
387
|
+
const meta = nome ? this.variaveis.get(nome) : undefined;
|
|
388
|
+
if (meta) {
|
|
389
|
+
const instrGet = meta.escopo === 'local' ? 'local.get' : 'global.get';
|
|
390
|
+
baseExpr = `(${instrGet} ${meta.watNome})`;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
const indice = this.traduzirConstruto(construto.indice);
|
|
394
|
+
// base + indice * 8 (cada elemento i64 ocupa 8 bytes)
|
|
395
|
+
const offset = `(i32.add ${baseExpr} (i32.wrap_i64 (i64.mul ${indice} (i64.const 8))))`;
|
|
396
|
+
return `(i64.load ${offset})`;
|
|
397
|
+
}
|
|
398
|
+
traduzirAtribuicaoPorIndice(construto) {
|
|
399
|
+
var _a;
|
|
400
|
+
let baseExpr = '(i32.const 0)';
|
|
401
|
+
if (construto.objeto instanceof construtos_1.Variavel) {
|
|
402
|
+
const nome = (_a = construto.objeto.simbolo) === null || _a === void 0 ? void 0 : _a.lexema;
|
|
403
|
+
const meta = nome ? this.variaveis.get(nome) : undefined;
|
|
404
|
+
if (meta) {
|
|
405
|
+
const instrGet = meta.escopo === 'local' ? 'local.get' : 'global.get';
|
|
406
|
+
baseExpr = `(${instrGet} ${meta.watNome})`;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
const indice = this.traduzirConstruto(construto.indice);
|
|
410
|
+
const valor = this.traduzirConstruto(construto.valor);
|
|
411
|
+
const offset = `(i32.add ${baseExpr} (i32.wrap_i64 (i64.mul ${indice} (i64.const 8))))`;
|
|
412
|
+
return `(i64.store ${offset} ${valor})`;
|
|
413
|
+
}
|
|
414
|
+
traduzirVetor(construto) {
|
|
415
|
+
var _a, _b;
|
|
416
|
+
// Aloca espaço na memória linear para N × 8 bytes.
|
|
417
|
+
// Os valores são emitidos como instruções de store na função corrente.
|
|
418
|
+
const n = (_b = (_a = construto.valores) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
|
|
419
|
+
const offset = this.deslocamentoTexto;
|
|
420
|
+
// Reserva n * 8 bytes (sem conteúdo estático; preenchido em tempo de execução)
|
|
421
|
+
this.deslocamentoTexto += n * 8;
|
|
422
|
+
if (construto.valores) {
|
|
423
|
+
for (let i = 0; i < n; i++) {
|
|
424
|
+
const valor = this.traduzirConstruto(construto.valores[i]);
|
|
425
|
+
const enderecoElem = `(i32.const ${offset + i * 8})`;
|
|
426
|
+
this.emitir(`(i64.store ${enderecoElem} ${valor})`);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
return `(i32.const ${offset})`;
|
|
430
|
+
}
|
|
431
|
+
traduzirDefinirValor(construto) {
|
|
432
|
+
// Acesso a propriedade de objeto — simplificado na v1
|
|
433
|
+
const valor = this.traduzirConstruto(construto.valor);
|
|
434
|
+
return `${valor} ;; definir valor não totalmente suportado na v1`;
|
|
435
|
+
}
|
|
436
|
+
traduzirFuncaoConstruto(construto) {
|
|
437
|
+
var _a;
|
|
438
|
+
// Função anônima: emite como função nomeada com rótulo gerado
|
|
439
|
+
const rotulo = `__anonima_${this.contadorRotulos++}`;
|
|
440
|
+
const snapshot = this.salvarEIniciarContextoFuncao();
|
|
441
|
+
for (const decl of (_a = construto.corpo) !== null && _a !== void 0 ? _a : []) {
|
|
442
|
+
this.traduzirDeclaracaoInterna(decl);
|
|
443
|
+
}
|
|
444
|
+
this.emitir('(i64.const 0)');
|
|
445
|
+
const funcWat = ` (func $${rotulo}${this.declaracoesLocaisAtual} (result i64)\n` +
|
|
446
|
+
this.corpoDaFuncaoAtual +
|
|
447
|
+
` )`;
|
|
448
|
+
this.funcoesCompletas.push(funcWat);
|
|
449
|
+
this.restaurarContextoFuncao(snapshot);
|
|
450
|
+
return `(i32.const 0) ;; referência à função anônima $${rotulo}`;
|
|
451
|
+
}
|
|
452
|
+
traduzirAcessoMetodo(_construto) {
|
|
453
|
+
return '(i64.const 0) ;; acesso a método não suportado na v1';
|
|
454
|
+
}
|
|
455
|
+
traduzirTipoDe(construto) {
|
|
456
|
+
return this.traduzirConstruto(construto.valor);
|
|
457
|
+
}
|
|
458
|
+
// =========================================================================
|
|
459
|
+
// Declarações
|
|
460
|
+
// =========================================================================
|
|
461
|
+
traduzirVar(declaracao) {
|
|
462
|
+
var _a;
|
|
463
|
+
const nome = (_a = declaracao.simbolo) === null || _a === void 0 ? void 0 : _a.lexema;
|
|
464
|
+
if (!nome)
|
|
465
|
+
return;
|
|
466
|
+
if (declaracao.inicializador instanceof construtos_1.Vetor) {
|
|
467
|
+
// Vetor: aloca em memória e guarda o ponteiro i32 na variável
|
|
468
|
+
if (this.dentroFuncao) {
|
|
469
|
+
this.declararParamLocal(nome, 'i32', false);
|
|
470
|
+
}
|
|
471
|
+
else {
|
|
472
|
+
this.declaracoesGlobais.push(` (global $${nome} (mut i32) (i32.const 0))`);
|
|
473
|
+
this.variaveis.set(nome, { watNome: `$${nome}`, tipo: 'i32', escopo: 'global' });
|
|
474
|
+
}
|
|
475
|
+
const ponteiro = this.traduzirVetor(declaracao.inicializador);
|
|
476
|
+
const meta = this.variaveis.get(nome);
|
|
477
|
+
const instrSet = meta.escopo === 'local' ? 'local.set' : 'global.set';
|
|
478
|
+
this.emitir(`(${instrSet} $${nome} ${ponteiro})`);
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
const tipo = declaracao.inicializador ? this.inferirTipo(declaracao.inicializador) : 'i64';
|
|
482
|
+
if (this.dentroFuncao) {
|
|
483
|
+
this.declararParamLocal(nome, tipo, false);
|
|
484
|
+
if (declaracao.inicializador) {
|
|
485
|
+
const valor = this.traduzirConstruto(declaracao.inicializador);
|
|
486
|
+
this.emitir(`(local.set $${nome} ${valor})`);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
// Globais WAT só aceitam const-exprs como inicializadores.
|
|
491
|
+
// Literais → inicializador imediato; expressões complexas → init 0 + global.set em $principal.
|
|
492
|
+
if (declaracao.inicializador instanceof construtos_1.Literal) {
|
|
493
|
+
const init = this.traduzirGlobalInit(declaracao.inicializador, tipo);
|
|
494
|
+
this.declaracoesGlobais.push(` (global $${nome} (mut ${tipo}) ${init})`);
|
|
495
|
+
this.variaveis.set(nome, { watNome: `$${nome}`, tipo, escopo: 'global' });
|
|
496
|
+
}
|
|
497
|
+
else {
|
|
498
|
+
this.declaracoesGlobais.push(` (global $${nome} (mut ${tipo}) (${tipo}.const 0))`);
|
|
499
|
+
this.variaveis.set(nome, { watNome: `$${nome}`, tipo, escopo: 'global' });
|
|
500
|
+
if (declaracao.inicializador) {
|
|
501
|
+
const valor = this.traduzirConstruto(declaracao.inicializador);
|
|
502
|
+
this.emitir(`(global.set $${nome} ${valor})`);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
traduzirConst(declaracao) {
|
|
508
|
+
var _a;
|
|
509
|
+
const nome = (_a = declaracao.simbolo) === null || _a === void 0 ? void 0 : _a.lexema;
|
|
510
|
+
if (!nome)
|
|
511
|
+
return;
|
|
512
|
+
const tipo = this.inferirTipo(declaracao.inicializador);
|
|
513
|
+
if (this.dentroFuncao) {
|
|
514
|
+
// Dentro de função: trata como local (sem imutabilidade real em WAT)
|
|
515
|
+
this.declararParamLocal(nome, tipo, false);
|
|
516
|
+
const valor = this.traduzirConstruto(declaracao.inicializador);
|
|
517
|
+
this.emitir(`(local.set $${nome} ${valor})`);
|
|
518
|
+
}
|
|
519
|
+
else {
|
|
520
|
+
// Constante global: sem `mut`; apenas literais são válidos como init
|
|
521
|
+
if (declaracao.inicializador instanceof construtos_1.Literal) {
|
|
522
|
+
const init = this.traduzirGlobalInit(declaracao.inicializador, tipo);
|
|
523
|
+
this.declaracoesGlobais.push(` (global $${nome} ${tipo} ${init})`);
|
|
524
|
+
}
|
|
525
|
+
else {
|
|
526
|
+
// Expressão complexa: global imutável não pode ser sobrescrita em WAT.
|
|
527
|
+
// Tratamos como mutável para permitir inicialização tardia.
|
|
528
|
+
this.declaracoesGlobais.push(` (global $${nome} (mut ${tipo}) (${tipo}.const 0))`);
|
|
529
|
+
const valor = this.traduzirConstruto(declaracao.inicializador);
|
|
530
|
+
this.emitir(`(global.set $${nome} ${valor})`);
|
|
531
|
+
}
|
|
532
|
+
this.variaveis.set(nome, { watNome: `$${nome}`, tipo, escopo: 'global' });
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Traduz um literal para um WAT const-expr válido como inicializador de global.
|
|
537
|
+
* Apenas literais são aceitos como inicializadores de globais em WAT.
|
|
538
|
+
*/
|
|
539
|
+
traduzirGlobalInit(construto, tipo) {
|
|
540
|
+
if (typeof construto.valor === 'boolean')
|
|
541
|
+
return `(i64.const ${construto.valor ? 1 : 0})`;
|
|
542
|
+
if (typeof construto.valor === 'string') {
|
|
543
|
+
const { offset } = this.internalizarTexto(construto.valor);
|
|
544
|
+
return `(i32.const ${offset})`;
|
|
545
|
+
}
|
|
546
|
+
if (typeof construto.valor === 'bigint')
|
|
547
|
+
return `(i64.const ${construto.valor})`;
|
|
548
|
+
return `(${tipo}.const ${Math.trunc(Number(construto.valor))})`;
|
|
549
|
+
}
|
|
550
|
+
traduzirSe(declaracao) {
|
|
551
|
+
const condicao = this.traduzirConstruto(declaracao.condicao);
|
|
552
|
+
this.emitir(`(if`);
|
|
553
|
+
this.emitir(` (i32.wrap_i64 ${condicao})`);
|
|
554
|
+
this.emitir(` (then`);
|
|
555
|
+
if (this.dicionarioDeclaracoes[declaracao.caminhoEntao.constructor.name]) {
|
|
556
|
+
const corpoPrevio = this.corpoDaFuncaoAtual;
|
|
557
|
+
this.corpoDaFuncaoAtual = '';
|
|
558
|
+
this.traduzirDeclaracaoInterna(declaracao.caminhoEntao);
|
|
559
|
+
const corpoEntao = this.corpoDaFuncaoAtual
|
|
560
|
+
.split('\n')
|
|
561
|
+
.map((l) => ` ${l}`)
|
|
562
|
+
.join('\n');
|
|
563
|
+
this.corpoDaFuncaoAtual = corpoPrevio + corpoEntao;
|
|
564
|
+
}
|
|
565
|
+
this.emitir(` )`);
|
|
566
|
+
if (declaracao.caminhoSenao) {
|
|
567
|
+
this.emitir(` (else`);
|
|
568
|
+
const corpoPrevio = this.corpoDaFuncaoAtual;
|
|
569
|
+
this.corpoDaFuncaoAtual = '';
|
|
570
|
+
this.traduzirDeclaracaoInterna(declaracao.caminhoSenao);
|
|
571
|
+
const corpoSenao = this.corpoDaFuncaoAtual
|
|
572
|
+
.split('\n')
|
|
573
|
+
.map((l) => ` ${l}`)
|
|
574
|
+
.join('\n');
|
|
575
|
+
this.corpoDaFuncaoAtual = corpoPrevio + corpoSenao;
|
|
576
|
+
this.emitir(` )`);
|
|
577
|
+
}
|
|
578
|
+
this.emitir(`)`);
|
|
579
|
+
}
|
|
580
|
+
traduzirEnquanto(declaracao) {
|
|
581
|
+
const labelSaida = this.gerarRotulo();
|
|
582
|
+
const labelLaco = this.gerarRotulo();
|
|
583
|
+
this.pilhaDeControle.push({ labelSaida, labelLaco });
|
|
584
|
+
const condicao = this.traduzirConstruto(declaracao.condicao);
|
|
585
|
+
this.emitir(`(block ${labelSaida}`);
|
|
586
|
+
this.emitir(` (loop ${labelLaco}`);
|
|
587
|
+
this.emitir(` (br_if ${labelSaida}`);
|
|
588
|
+
this.emitir(` (i32.eqz (i32.wrap_i64 ${condicao}))`);
|
|
589
|
+
this.emitir(` )`);
|
|
590
|
+
this.traduzirDeclaracaoInterna(declaracao.corpo);
|
|
591
|
+
this.emitir(` (br ${labelLaco})`);
|
|
592
|
+
this.emitir(` )`);
|
|
593
|
+
this.emitir(`)`);
|
|
594
|
+
this.pilhaDeControle.pop();
|
|
595
|
+
}
|
|
596
|
+
traduzirPara(declaracao) {
|
|
597
|
+
// Inicializador
|
|
598
|
+
if (declaracao.inicializador) {
|
|
599
|
+
if (Array.isArray(declaracao.inicializador)) {
|
|
600
|
+
for (const decl of declaracao.inicializador) {
|
|
601
|
+
this.traduzirDeclaracaoInterna(decl);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
this.traduzirDeclaracaoInterna(declaracao.inicializador);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
const labelSaida = this.gerarRotulo();
|
|
609
|
+
const labelLaco = this.gerarRotulo();
|
|
610
|
+
this.pilhaDeControle.push({ labelSaida, labelLaco });
|
|
611
|
+
const condicao = declaracao.condicao
|
|
612
|
+
? this.traduzirConstruto(declaracao.condicao)
|
|
613
|
+
: '(i64.const 1)';
|
|
614
|
+
this.emitir(`(block ${labelSaida}`);
|
|
615
|
+
this.emitir(` (loop ${labelLaco}`);
|
|
616
|
+
this.emitir(` (br_if ${labelSaida}`);
|
|
617
|
+
this.emitir(` (i32.eqz (i32.wrap_i64 ${condicao}))`);
|
|
618
|
+
this.emitir(` )`);
|
|
619
|
+
if (declaracao.corpo) {
|
|
620
|
+
this.traduzirDeclaracaoInterna(declaracao.corpo);
|
|
621
|
+
}
|
|
622
|
+
if (declaracao.incrementar) {
|
|
623
|
+
const inc = this.traduzirConstruto(declaracao.incrementar);
|
|
624
|
+
this.emitir(`(drop ${inc})`);
|
|
625
|
+
}
|
|
626
|
+
this.emitir(` (br ${labelLaco})`);
|
|
627
|
+
this.emitir(` )`);
|
|
628
|
+
this.emitir(`)`);
|
|
629
|
+
this.pilhaDeControle.pop();
|
|
630
|
+
}
|
|
631
|
+
traduzirFazer(declaracao) {
|
|
632
|
+
var _a;
|
|
633
|
+
const labelSaida = this.gerarRotulo();
|
|
634
|
+
const labelLaco = this.gerarRotulo();
|
|
635
|
+
this.pilhaDeControle.push({ labelSaida, labelLaco });
|
|
636
|
+
this.emitir(`(block ${labelSaida}`);
|
|
637
|
+
this.emitir(` (loop ${labelLaco}`);
|
|
638
|
+
if ((_a = declaracao.caminhoFazer) === null || _a === void 0 ? void 0 : _a.declaracoes) {
|
|
639
|
+
for (const decl of declaracao.caminhoFazer.declaracoes) {
|
|
640
|
+
this.traduzirDeclaracaoInterna(decl);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
if (declaracao.condicaoEnquanto) {
|
|
644
|
+
const condicao = this.traduzirConstruto(declaracao.condicaoEnquanto);
|
|
645
|
+
// Repete se a condição for verdadeira
|
|
646
|
+
this.emitir(` (br_if ${labelLaco}`);
|
|
647
|
+
this.emitir(` (i32.wrap_i64 ${condicao})`);
|
|
648
|
+
this.emitir(` )`);
|
|
649
|
+
}
|
|
650
|
+
this.emitir(` )`);
|
|
651
|
+
this.emitir(`)`);
|
|
652
|
+
this.pilhaDeControle.pop();
|
|
653
|
+
}
|
|
654
|
+
traduzirEscolha(declaracao) {
|
|
655
|
+
const rotuloEscolha = `__escolha_${this.contadorRotulos++}`;
|
|
656
|
+
const tipo = 'i64';
|
|
657
|
+
// Declara local temporário para o valor do escolha
|
|
658
|
+
this.declararParamLocal(rotuloEscolha, tipo, false);
|
|
659
|
+
const sujeito = this.traduzirConstruto(declaracao.identificadorOuLiteral);
|
|
660
|
+
this.emitir(`(local.set $${rotuloEscolha} ${sujeito})`);
|
|
661
|
+
// Gera cadeia de if/else aninhados
|
|
662
|
+
this.emitirCadeiaEscolha(rotuloEscolha, declaracao.caminhos, declaracao.caminhoPadrao);
|
|
663
|
+
}
|
|
664
|
+
emitirCadeiaEscolha(rotuloEscolha, caminhos, caminhoPadrao, indice = 0) {
|
|
665
|
+
var _a, _b;
|
|
666
|
+
if (indice >= caminhos.length) {
|
|
667
|
+
// Emite o caminho padrão (senao) se existir
|
|
668
|
+
if (caminhoPadrao) {
|
|
669
|
+
for (const decl of (_a = caminhoPadrao.declaracoes) !== null && _a !== void 0 ? _a : []) {
|
|
670
|
+
this.traduzirDeclaracaoInterna(decl);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
const caminho = caminhos[indice];
|
|
676
|
+
if (!caminho.condicoes || caminho.condicoes.length === 0) {
|
|
677
|
+
this.emitirCadeiaEscolha(rotuloEscolha, caminhos, caminhoPadrao, indice + 1);
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
// Condição: qualquer das condicoes casa com o valor do escolha
|
|
681
|
+
const primeiraCond = `(i64.eq (local.get $${rotuloEscolha}) ${this.traduzirConstruto(caminho.condicoes[0])})`;
|
|
682
|
+
let condicaoFinal = primeiraCond;
|
|
683
|
+
for (let i = 1; i < caminho.condicoes.length; i++) {
|
|
684
|
+
const outraCond = `(i64.eq (local.get $${rotuloEscolha}) ${this.traduzirConstruto(caminho.condicoes[i])})`;
|
|
685
|
+
condicaoFinal = `(i32.or ${condicaoFinal} ${outraCond})`;
|
|
686
|
+
}
|
|
687
|
+
this.emitir(`(if`);
|
|
688
|
+
this.emitir(` ${condicaoFinal}`);
|
|
689
|
+
this.emitir(` (then`);
|
|
690
|
+
for (const decl of (_b = caminho.declaracoes) !== null && _b !== void 0 ? _b : []) {
|
|
691
|
+
this.traduzirDeclaracaoInterna(decl);
|
|
692
|
+
}
|
|
693
|
+
this.emitir(` )`);
|
|
694
|
+
const temProximo = indice + 1 < caminhos.length || caminhoPadrao != null;
|
|
695
|
+
if (temProximo) {
|
|
696
|
+
this.emitir(` (else`);
|
|
697
|
+
this.emitirCadeiaEscolha(rotuloEscolha, caminhos, caminhoPadrao, indice + 1);
|
|
698
|
+
this.emitir(` )`);
|
|
699
|
+
}
|
|
700
|
+
this.emitir(`)`);
|
|
701
|
+
}
|
|
702
|
+
traduzirBloco(declaracao) {
|
|
703
|
+
var _a;
|
|
704
|
+
for (const decl of (_a = declaracao.declaracoes) !== null && _a !== void 0 ? _a : []) {
|
|
705
|
+
this.traduzirDeclaracaoInterna(decl);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
traduzirExpressao(declaracao) {
|
|
709
|
+
if (!declaracao.expressao)
|
|
710
|
+
return;
|
|
711
|
+
const expr = this.traduzirConstruto(declaracao.expressao);
|
|
712
|
+
// Atribuições e stores não deixam valor na pilha; outros sim → drop
|
|
713
|
+
const deixaValor = !(declaracao.expressao instanceof construtos_1.Atribuir) &&
|
|
714
|
+
!(declaracao.expressao instanceof construtos_1.AtribuicaoPorIndice);
|
|
715
|
+
if (deixaValor) {
|
|
716
|
+
this.emitir(`(drop ${expr})`);
|
|
717
|
+
}
|
|
718
|
+
else {
|
|
719
|
+
this.emitir(expr);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
traduzirEscreva(declaracao) {
|
|
723
|
+
for (const arg of declaracao.argumentos) {
|
|
724
|
+
if (arg instanceof construtos_1.Literal && typeof arg.valor === 'string') {
|
|
725
|
+
const { offset, len } = this.internalizarTexto(arg.valor);
|
|
726
|
+
this.emitir(`(call $__escreva_texto (i32.const ${offset}) (i32.const ${len}))`);
|
|
727
|
+
}
|
|
728
|
+
else {
|
|
729
|
+
const expr = this.traduzirConstruto(arg);
|
|
730
|
+
this.emitir(`(call $__escreva_inteiro ${expr})`);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
traduzirRetorna(declaracao) {
|
|
735
|
+
this.funcaoTemRetorno = true;
|
|
736
|
+
if (declaracao.valor) {
|
|
737
|
+
const valor = this.traduzirConstruto(declaracao.valor);
|
|
738
|
+
this.emitir(`(return ${valor})`);
|
|
739
|
+
}
|
|
740
|
+
else {
|
|
741
|
+
this.emitir(`(return (i64.const 0))`);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
traduzirSustar(_declaracao) {
|
|
745
|
+
const topo = this.pilhaDeControle[this.pilhaDeControle.length - 1];
|
|
746
|
+
if (topo) {
|
|
747
|
+
this.emitir(`(br ${topo.labelSaida})`);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
traduzirContinua(_declaracao) {
|
|
751
|
+
const topo = this.pilhaDeControle[this.pilhaDeControle.length - 1];
|
|
752
|
+
if (topo) {
|
|
753
|
+
this.emitir(`(br ${topo.labelLaco})`);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
traduzirFuncaoDeclaracao(declaracao) {
|
|
757
|
+
var _a, _b, _c, _d, _e, _f;
|
|
758
|
+
const nome = (_b = (_a = declaracao.simbolo) === null || _a === void 0 ? void 0 : _a.lexema) !== null && _b !== void 0 ? _b : `__func_${this.contadorRotulos++}`;
|
|
759
|
+
const snapshot = this.salvarEIniciarContextoFuncao();
|
|
760
|
+
// Declara parâmetros
|
|
761
|
+
for (const param of (_d = (_c = declaracao.funcao) === null || _c === void 0 ? void 0 : _c.parametros) !== null && _d !== void 0 ? _d : []) {
|
|
762
|
+
this.declararParamLocal(param.nome.lexema, 'i64', true);
|
|
763
|
+
}
|
|
764
|
+
// Traduz corpo
|
|
765
|
+
for (const decl of (_f = (_e = declaracao.funcao) === null || _e === void 0 ? void 0 : _e.corpo) !== null && _f !== void 0 ? _f : []) {
|
|
766
|
+
this.traduzirDeclaracaoInterna(decl);
|
|
767
|
+
}
|
|
768
|
+
// Retorno implícito 0 (garante stack completo)
|
|
769
|
+
this.emitir('(i64.const 0)');
|
|
770
|
+
const ehPrincipal = nome === 'principal';
|
|
771
|
+
const exportar = ehPrincipal ? ' (export "principal")' : '';
|
|
772
|
+
const funcWat = ` (func $${nome}${exportar}${this.declaracoesLocaisAtual} (result i64)\n` +
|
|
773
|
+
this.corpoDaFuncaoAtual +
|
|
774
|
+
` )`;
|
|
775
|
+
this.funcoesCompletas.push(funcWat);
|
|
776
|
+
this.restaurarContextoFuncao(snapshot);
|
|
777
|
+
}
|
|
778
|
+
traduzirFalhar(declaracao) {
|
|
779
|
+
// `unreachable` = trap incondicional em WebAssembly
|
|
780
|
+
let msg = '';
|
|
781
|
+
if (declaracao.explicacao) {
|
|
782
|
+
try {
|
|
783
|
+
msg = ` ;; ${this.traduzirConstruto(declaracao.explicacao)}`;
|
|
784
|
+
}
|
|
785
|
+
catch (_a) {
|
|
786
|
+
// ignore
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
this.emitir(`(unreachable)${msg}`);
|
|
790
|
+
}
|
|
791
|
+
traduzirImportar(_declaracao) {
|
|
792
|
+
this.emitir(`;; importar não suportado em WebAssembly nativo`);
|
|
793
|
+
}
|
|
794
|
+
traduzirTente(declaracao) {
|
|
795
|
+
var _a;
|
|
796
|
+
this.emitir(`;; tente/pegue: tratamento de exceções é v2`);
|
|
797
|
+
for (const decl of (_a = declaracao.caminhoTente) !== null && _a !== void 0 ? _a : []) {
|
|
798
|
+
this.traduzirDeclaracaoInterna(decl);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
traduzirClasse(_declaracao) {
|
|
802
|
+
this.emitir(`;; classe: não suportada na v1`);
|
|
803
|
+
}
|
|
804
|
+
traduzirParaCada(declaracao) {
|
|
805
|
+
this.emitir(`;; para cada: requer suporte a iteráveis (v2)`);
|
|
806
|
+
if (declaracao.corpo) {
|
|
807
|
+
this.traduzirDeclaracaoInterna(declaracao.corpo);
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
// =========================================================================
|
|
811
|
+
// Método principal
|
|
812
|
+
// =========================================================================
|
|
813
|
+
/**
|
|
814
|
+
* Traduz uma lista de declarações Delégua para um módulo WAT.
|
|
815
|
+
* Retorna a string completa do módulo.
|
|
816
|
+
*/
|
|
817
|
+
traduzir(declaracoes) {
|
|
818
|
+
// Verifica se o usuário declarou explicitamente `funcao principal()`
|
|
819
|
+
const principalDeclarado = declaracoes.some((d) => { var _a; return d instanceof declaracoes_1.FuncaoDeclaracao && ((_a = d.simbolo) === null || _a === void 0 ? void 0 : _a.lexema) === 'principal'; });
|
|
820
|
+
// Processa todas as declarações de nível superior
|
|
821
|
+
for (const declaracao of declaracoes) {
|
|
822
|
+
this.traduzirDeclaracaoInterna(declaracao);
|
|
823
|
+
}
|
|
824
|
+
// Se o usuário não declarou principal(), envolve os stmts de topo em $principal
|
|
825
|
+
if (!principalDeclarado) {
|
|
826
|
+
const corpoTopo = this.corpoDaFuncaoAtual;
|
|
827
|
+
const locaisDeclarados = this.declaracoesLocaisAtual;
|
|
828
|
+
const funcPrincipal = ` (func $principal (export "principal")${locaisDeclarados} (result i64)\n` +
|
|
829
|
+
corpoTopo +
|
|
830
|
+
` (i64.const 0)\n` +
|
|
831
|
+
` )`;
|
|
832
|
+
this.funcoesCompletas.push(funcPrincipal);
|
|
833
|
+
}
|
|
834
|
+
// ── Monta as seções do módulo ────────────────────────────────────────
|
|
835
|
+
const linhasImports = [
|
|
836
|
+
` (import "delegua" "escreva_texto" (func $__escreva_texto (param i32 i32)))`,
|
|
837
|
+
` (import "delegua" "escreva_inteiro" (func $__escreva_inteiro (param i64)))`,
|
|
838
|
+
];
|
|
839
|
+
const linhaMemoria = ` (memory (export "memory") 1)`;
|
|
840
|
+
const linhasDados = this.segmentosTexto.map((s) => {
|
|
841
|
+
const { watLiteral } = this.escaparStringWat(s.conteudo);
|
|
842
|
+
return ` (data (i32.const ${s.deslocamento}) "${watLiteral}")`;
|
|
843
|
+
});
|
|
844
|
+
const partes = ['(module', ...linhasImports, '', linhaMemoria];
|
|
845
|
+
if (linhasDados.length > 0) {
|
|
846
|
+
partes.push('');
|
|
847
|
+
partes.push(...linhasDados);
|
|
848
|
+
}
|
|
849
|
+
if (this.declaracoesGlobais.length > 0) {
|
|
850
|
+
partes.push('');
|
|
851
|
+
partes.push(...this.declaracoesGlobais);
|
|
852
|
+
}
|
|
853
|
+
if (this.funcoesCompletas.length > 0) {
|
|
854
|
+
partes.push('');
|
|
855
|
+
partes.push(...this.funcoesCompletas);
|
|
856
|
+
}
|
|
857
|
+
partes.push(')');
|
|
858
|
+
return partes.join('\n');
|
|
859
|
+
}
|
|
860
|
+
// =========================================================================
|
|
861
|
+
// Arquivo host JavaScript
|
|
862
|
+
// =========================================================================
|
|
863
|
+
/**
|
|
864
|
+
* Gera um arquivo `.mjs` host para executar o módulo WASM no Node.js.
|
|
865
|
+
* Fornece os imports necessários (`delegua.escreva_texto`, `delegua.escreva_inteiro`).
|
|
866
|
+
*/
|
|
867
|
+
gerarArquivoHost() {
|
|
868
|
+
return `// Gerado por Delégua -> WebAssembly
|
|
869
|
+
// Uso: node delegua-host.mjs <arquivo.wasm>
|
|
870
|
+
import { readFileSync } from 'fs';
|
|
871
|
+
|
|
872
|
+
const args = process.argv.slice(2);
|
|
873
|
+
const wasmPath = args[0] ?? 'saida.wasm';
|
|
874
|
+
|
|
875
|
+
let memoryExport;
|
|
876
|
+
|
|
877
|
+
const importObject = {
|
|
878
|
+
delegua: {
|
|
879
|
+
/** Imprime texto a partir de um ponteiro e comprimento na memória linear. */
|
|
880
|
+
escreva_texto(ptr, len) {
|
|
881
|
+
const bytes = new Uint8Array(memoryExport.buffer, ptr, len);
|
|
882
|
+
process.stdout.write(new TextDecoder('utf-8').decode(bytes));
|
|
883
|
+
},
|
|
884
|
+
/** Imprime um inteiro de 64 bits (recebido como BigInt no JS). */
|
|
885
|
+
escreva_inteiro(valor) {
|
|
886
|
+
process.stdout.write(String(valor));
|
|
887
|
+
},
|
|
888
|
+
}
|
|
889
|
+
};
|
|
890
|
+
|
|
891
|
+
const wasmBuffer = readFileSync(wasmPath);
|
|
892
|
+
const { instance } = await WebAssembly.instantiate(wasmBuffer, importObject);
|
|
893
|
+
memoryExport = instance.exports.memory;
|
|
894
|
+
|
|
895
|
+
const codigoSaida = Number(instance.exports.principal());
|
|
896
|
+
process.exit(codigoSaida);
|
|
897
|
+
`;
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
exports.TradutorWebAssembly = TradutorWebAssembly;
|
|
901
|
+
//# sourceMappingURL=tradutor-webassembly.js.map
|