Repository: DesignLiquido/delegua
Pull request #350 (2023-05-04 21:52:37)

Instrução `para cada`
Implementado conforme https://github.com/DesignLiquido/delegua/discussions/342#discussioncomment-5785308.


Patch:
diff --git a/fontes/avaliador-sintatico/avaliador-sintatico.ts b/fontes/avaliador-sintatico/avaliador-sintatico.ts
index c8a5d796..b850b8ed 100644
--- a/fontes/avaliador-sintatico/avaliador-sintatico.ts
+++ b/fontes/avaliador-sintatico/avaliador-sintatico.ts
@@ -44,6 +44,7 @@ import {
     Var,
     Leia,
     Const,
+    ParaCada,
 } from '../declaracoes';
 import { RetornoAvaliadorSintatico } from '../interfaces/retornos/retorno-avaliador-sintatico';
 import { RetornoLexador } from '../interfaces/retornos/retorno-lexador';
@@ -589,47 +590,78 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface {
         }
     }
 
-    declaracaoPara(): Para {
-        try {
-            const simboloPara: SimboloInterface = this.simbolos[this.atual - 1];
-            this.blocos += 1;
+    protected declaracaoParaCada(simboloPara: SimboloInterface): ParaCada {
+        const nomeVariavelIteracao = this.consumir(tiposDeSimbolos.IDENTIFICADOR, 
+            "Esperado identificador de variável de iteração para instrução 'para cada'.");
+        
+        if (!this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.DE, tiposDeSimbolos.EM)) {
+            throw this.erro(
+                this.simbolos[this.atual], 
+                "Esperado palavras reservadas 'em' ou 'de' após variável de iteração em instrução 'para cada'."
+            );
+        }
 
-            const comParenteses = this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PARENTESE_ESQUERDO);
+        const vetor = this.expressao();
+        const corpo = this.resolverDeclaracao();
 
-            let inicializador: Var | Expressao;
-            if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO_E_VIRGULA)) {
-                inicializador = null;
-            } else if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VARIAVEL)) {
-                inicializador = this.declaracaoDeVariavel();
-            } else if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.CONSTANTE)) {
-                inicializador = this.declaracaoDeConstante();
-            } else {
-                inicializador = this.declaracaoExpressao();
-            }
+        return new ParaCada(
+            this.hashArquivo, 
+            Number(simboloPara.linha), 
+            nomeVariavelIteracao.lexema, 
+            vetor, 
+            corpo
+        );
+    }
 
-            let condicao = null;
-            if (!this.verificarTipoSimboloAtual(tiposDeSimbolos.PONTO_E_VIRGULA)) {
-                condicao = this.expressao();
-            }
+    protected declaracaoParaTradicional(simboloPara: SimboloInterface): Para {
+        const comParenteses = this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PARENTESE_ESQUERDO);
+
+        let inicializador: Var | Expressao;
+        if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO_E_VIRGULA)) {
+            inicializador = null;
+        } else if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VARIAVEL)) {
+            inicializador = this.declaracaoDeVariavel();
+        } else if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.CONSTANTE)) {
+            inicializador = this.declaracaoDeConstante();
+        } else {
+            inicializador = this.declaracaoExpressao();
+        }
 
-            // Ponto-e-vírgula é opcional aqui.
-            this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO_E_VIRGULA);
+        let condicao = null;
+        if (!this.verificarTipoSimboloAtual(tiposDeSimbolos.PONTO_E_VIRGULA)) {
+            condicao = this.expressao();
+        }
 
-            let incrementar = null;
-            if (!this.verificarTipoSimboloAtual(tiposDeSimbolos.PARENTESE_DIREITO)) {
-                incrementar = this.expressao();
-            }
+        // Ponto-e-vírgula é opcional aqui.
+        this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO_E_VIRGULA);
 
-            if (comParenteses) {
-                this.consumir(
-                    tiposDeSimbolos.PARENTESE_DIREITO,
-                    "Esperado ')' após cláusulas de inicialização, condição e incremento."
-                );
-            }
+        let incrementar = null;
+        if (!this.verificarTipoSimboloAtual(tiposDeSimbolos.PARENTESE_DIREITO)) {
+            incrementar = this.expressao();
+        }
 
-            const corpo = this.resolverDeclaracao();
+        if (comParenteses) {
+            this.consumir(
+                tiposDeSimbolos.PARENTESE_DIREITO,
+                "Esperado ')' após cláusulas de inicialização, condição e incremento."
+            );
+        }
+
+        const corpo = this.resolverDeclaracao();
+
+        return new Para(this.hashArquivo, Number(simboloPara.linha), inicializador, condicao, incrementar, corpo);
+    }
+
+    declaracaoPara(): Para | ParaCada {
+        try {
+            const simboloPara: SimboloInterface = this.simbolos[this.atual - 1];
+            this.blocos += 1;
+
+            if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.CADA)) {
+                return this.declaracaoParaCada(simboloPara);
+            } 
 
-            return new Para(this.hashArquivo, Number(simboloPara.linha), inicializador, condicao, incrementar, corpo);
+            return this.declaracaoParaTradicional(simboloPara);
         } finally {
             this.blocos -= 1;
         }
@@ -796,7 +828,7 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface {
             Number(simboloTente.linha),
             blocoTente,
             blocoPegue,
-            null,
+            blocoSenao,
             blocoFinalmente
         );
     }
diff --git a/fontes/declaracoes/index.ts b/fontes/declaracoes/index.ts
index 54401add..4f2532e7 100644
--- a/fontes/declaracoes/index.ts
+++ b/fontes/declaracoes/index.ts
@@ -13,6 +13,7 @@ export * from './funcao';
 export * from './importar';
 export * from './leia';
 export * from './para';
+export * from './para-cada';
 export * from './sustar';
 export * from './retorna';
 export * from './se';
diff --git a/fontes/declaracoes/para-cada.ts b/fontes/declaracoes/para-cada.ts
new file mode 100644
index 00000000..e6c09998
--- /dev/null
+++ b/fontes/declaracoes/para-cada.ts
@@ -0,0 +1,28 @@
+import { InterpretadorInterface } from "../interfaces";
+import { Bloco } from "./bloco";
+import { Declaracao } from "./declaracao";
+
+export class ParaCada extends Declaracao {
+    nomeVariavelIteracao: string;
+    vetor: any;
+    corpo: Bloco;
+    posicaoAtual: number;
+
+    constructor(
+        hashArquivo: number,
+        linha: number,
+        nomeVariavelIteracao: string,
+        vetor: any,
+        corpo: Bloco
+    ) {
+        super(linha, hashArquivo);
+        this.nomeVariavelIteracao = nomeVariavelIteracao;
+        this.vetor = vetor;
+        this.corpo = corpo;
+        this.posicaoAtual = 0;
+    }
+
+    async aceitar(visitante: InterpretadorInterface): Promise<any> {
+        return await visitante.visitarDeclaracaoParaCada(this);
+    }
+}
\ No newline at end of file
diff --git a/fontes/interfaces/avaliador-sintatico-interface.ts b/fontes/interfaces/avaliador-sintatico-interface.ts
index 8f6913c7..f20fb225 100644
--- a/fontes/interfaces/avaliador-sintatico-interface.ts
+++ b/fontes/interfaces/avaliador-sintatico-interface.ts
@@ -13,6 +13,7 @@ import {
     Importar,
     Leia,
     Para,
+    ParaCada,
     Retorna,
     Se,
     Sustar,
@@ -59,7 +60,7 @@ export interface AvaliadorSintaticoInterface {
     declaracaoEscreva(): Escreva;
     declaracaoExpressao(): Expressao;
     declaracaoLeia(): Leia;
-    declaracaoPara(): Para;
+    declaracaoPara(): Para | ParaCada;
     declaracaoSe(): Se;
     declaracaoSustar(): Sustar;
     declaracaoContinua(): Continua;
diff --git a/fontes/interfaces/interpretador-interface.ts b/fontes/interfaces/interpretador-interface.ts
index 880c54f6..d88ea174 100644
--- a/fontes/interfaces/interpretador-interface.ts
+++ b/fontes/interfaces/interpretador-interface.ts
@@ -15,6 +15,7 @@ import {
     Importar,
     Leia,
     Para,
+    ParaCada,
     Retorna,
     Se,
     Sustar,
@@ -45,8 +46,9 @@ export interface InterpretadorInterface {
     visitarDeclaracaoDeExpressao(declaracao: Expressao): any;
     visitarExpressaoLeia(expressao: Leia): any;
     visitarExpressaoLogica(expressao: any): any;
+    visitarDeclaracaoPara(declaracao: Para): Promise<any>;
+    visitarDeclaracaoParaCada(declaracao: ParaCada): Promise<any>;
     visitarDeclaracaoSe(declaracao: Se): any;
-    visitarDeclaracaoPara(declaracao: Para): any;
     visitarExpressaoFimPara(declaracao: FimPara): any;
     visitarDeclaracaoFazer(declaracao: Fazer): any;
     visitarExpressaoFormatacaoEscrita(declaracao: FormatacaoEscrita): any;
diff --git a/fontes/interpretador/dialetos/egua-classico/interpretador-egua-classico.ts b/fontes/interpretador/dialetos/egua-classico/interpretador-egua-classico.ts
index b62a098c..d2193292 100644
--- a/fontes/interpretador/dialetos/egua-classico/interpretador-egua-classico.ts
+++ b/fontes/interpretador/dialetos/egua-classico/interpretador-egua-classico.ts
@@ -23,6 +23,7 @@ import {
     Importar,
     Leia,
     Para,
+    ParaCada,
     Se,
     Tente,
     Var,
@@ -86,6 +87,10 @@ export class InterpretadorEguaClassico implements InterpretadorInterface {
         carregarBibliotecaGlobal(this, this.pilhaEscoposExecucao);
     }
     
+    visitarDeclaracaoParaCada(declaracao: ParaCada): Promise<any> {
+        throw new Error('Método não implementado.');
+    }
+    
     visitarDeclaracaoConst(declaracao: Const): Promise<any> {
         throw new Error('Método não implementado.');
     }
diff --git a/fontes/interpretador/dialetos/egua-classico/resolvedor/resolvedor.ts b/fontes/interpretador/dialetos/egua-classico/resolvedor/resolvedor.ts
index 1b919892..12b79c15 100644
--- a/fontes/interpretador/dialetos/egua-classico/resolvedor/resolvedor.ts
+++ b/fontes/interpretador/dialetos/egua-classico/resolvedor/resolvedor.ts
@@ -2,7 +2,7 @@ import { ResolvedorInterface } from '../../../../interfaces/resolvedor-interface
 import { PilhaEscopos } from './pilha-escopos';
 import { ErroResolvedor } from './erro-resolvedor';
 import { InterpretadorInterface, SimboloInterface } from '../../../../interfaces';
-import { Bloco, Const, Declaracao, EscrevaMesmaLinha, Expressao, Leia, Se } from '../../../../declaracoes';
+import { Bloco, Const, Declaracao, EscrevaMesmaLinha, Expressao, Leia, ParaCada, Se } from '../../../../declaracoes';
 import { AcessoMetodo, Construto, FimPara, FormatacaoEscrita, Super, Variavel } from '../../../../construtos';
 import { RetornoResolvedor } from './retorno-resolvedor';
 import { EspacoVariaveis } from '../../../../espaco-variaveis';
@@ -62,6 +62,11 @@ export class ResolvedorEguaClassico implements ResolvedorInterface, Interpretado
         this.classeAtual = TipoClasse.NENHUM;
         this.cicloAtual = TipoClasse.NENHUM;
     }
+
+    visitarDeclaracaoParaCada(declaracao: ParaCada): Promise<any> {
+        throw new Error('Método não implementado.');
+    }
+    
     visitarDeclaracaoConst(declaracao: Const): Promise<any> {
         throw new Error('Método não implementado.');
     }
diff --git a/fontes/interpretador/dialetos/portugol-ipt/interpretador-portugol-ipt.ts b/fontes/interpretador/dialetos/portugol-ipt/interpretador-portugol-ipt.ts
index b40bd4a1..82d450ca 100644
--- a/fontes/interpretador/dialetos/portugol-ipt/interpretador-portugol-ipt.ts
+++ b/fontes/interpretador/dialetos/portugol-ipt/interpretador-portugol-ipt.ts
@@ -1,5 +1,5 @@
 import { Literal, Construto, Atribuir, FimPara, FormatacaoEscrita, Super, Variavel } from "../../../construtos";
-import { Declaracao, Expressao, Leia, Se, Para, Fazer, Escolha, Tente, Enquanto, Importar, Escreva, EscrevaMesmaLinha, Bloco, Var, Const, Continua, Sustar, Retorna, FuncaoDeclaracao, Classe } from "../../../declaracoes";
+import { Declaracao, Expressao, Leia, Se, Para, Fazer, Escolha, Tente, Enquanto, Importar, Escreva, EscrevaMesmaLinha, Bloco, Var, Const, Continua, Sustar, Retorna, FuncaoDeclaracao, Classe, ParaCada } from "../../../declaracoes";
 import { EspacoVariaveis } from "../../../espaco-variaveis";
 import { ObjetoPadrao } from "../../../estruturas";
 import { ErroEmTempoDeExecucao } from "../../../excecoes";
@@ -55,6 +55,10 @@ export class InterpretadorPortugolIpt
         this.pilhaEscoposExecucao.empilhar(escopoExecucao);
     }
 
+    visitarDeclaracaoParaCada(declaracao: ParaCada): Promise<any> {
+        throw new Error("Método não implementado.");
+    }
+
     visitarExpressaoLiteral(expressao: Literal): Promise<any> {
         return expressao.valor;
     }
@@ -256,11 +260,13 @@ export class InterpretadorPortugolIpt
     }
 
     visitarDeclaracaoPara(declaracao: Para) {
-        throw new Error("Método não implementado");
+        return Promise.reject("Método não implementado");
     }
+
     visitarExpressaoFimPara(declaracao: FimPara) {
         throw new Error("Método não implementado");
     }
+
     visitarDeclaracaoFazer(declaracao: Fazer) {
         throw new Error("Método não implementado");
     }
diff --git a/fontes/interpretador/interpretador-base.ts b/fontes/interpretador/interpretador-base.ts
index 2357dabe..558a15e1 100644
--- a/fontes/interpretador/interpretador-base.ts
+++ b/fontes/interpretador/interpretador-base.ts
@@ -21,6 +21,7 @@ import {
     Importar,
     Leia,
     Para,
+    ParaCada,
     Retorna,
     Se,
     Tente,
@@ -581,32 +582,6 @@ export class InterpretadorBase implements InterpretadorInterface {
         return await this.avaliar(expressao.direita);
     }
 
-    /**
-     * Executa uma expressão Se, que tem uma condição, pode ter um bloco
-     * Senão, e múltiplos blocos Senão-se.
-     * @param declaracao A declaração Se.
-     * @returns O resultado da avaliação do bloco cuja condição é verdadeira.
-     */
-    async visitarDeclaracaoSe(declaracao: Se): Promise<any> {
-        if (this.eVerdadeiro(await this.avaliar(declaracao.condicao))) {
-            return await this.executar(declaracao.caminhoEntao);
-        }
-
-        for (let i = 0; i < declaracao.caminhosSeSenao.length; i++) {
-            const atual = declaracao.caminhosSeSenao[i];
-
-            if (this.eVerdadeiro(await this.avaliar(atual.condicao))) {
-                return await this.executar(atual.caminho);
-            }
-        }
-
-        if (declaracao.caminhoSenao !== null) {
-            return await this.executar(declaracao.caminhoSenao);
-        }
-
-        return null;
-    }
-
     async visitarDeclaracaoPara(declaracao: Para): Promise<any> {
         if (declaracao.inicializador !== null) {
             await this.avaliar(declaracao.inicializador);
@@ -635,9 +610,72 @@ export class InterpretadorBase implements InterpretadorInterface {
                 await this.avaliar(declaracao.incrementar);
             }
         }
+
         return retornoExecucao;
     }
 
+    async visitarDeclaracaoParaCada(declaracao: ParaCada): Promise<any> {
+        let retornoExecucao: any;
+        const vetorResolvido = await this.avaliar(declaracao.vetor);
+        const valorVetorResolvido = vetorResolvido.hasOwnProperty('valor') ? 
+            vetorResolvido.valor :
+            vetorResolvido;
+
+        if (!Array.isArray(valorVetorResolvido)) {
+            return Promise.reject("Variável ou literal provida em instrução 'para cada' não é um vetor.");
+        }
+
+        while (!(retornoExecucao instanceof Quebra) && declaracao.posicaoAtual < valorVetorResolvido.length) {
+            try {
+                this.pilhaEscoposExecucao.definirVariavel(
+                    declaracao.nomeVariavelIteracao, 
+                    valorVetorResolvido[declaracao.posicaoAtual]
+                );
+
+                retornoExecucao = await this.executar(declaracao.corpo);
+                if (retornoExecucao instanceof SustarQuebra) {
+                    return null;
+                }
+
+                if (retornoExecucao instanceof ContinuarQuebra) {
+                    retornoExecucao = null;
+                }
+
+                declaracao.posicaoAtual++;
+            } catch (erro: any) {
+                return Promise.reject(erro);
+            }
+        }
+
+        return retornoExecucao;
+    }
+
+    /**
+     * Executa uma expressão Se, que tem uma condição, pode ter um bloco
+     * Senão, e múltiplos blocos Senão-se.
+     * @param declaracao A declaração Se.
+     * @returns O resultado da avaliação do bloco cuja condição é verdadeira.
+     */
+    async visitarDeclaracaoSe(declaracao: Se): Promise<any> {
+        if (this.eVerdadeiro(await this.avaliar(declaracao.condicao))) {
+            return await this.executar(declaracao.caminhoEntao);
+        }
+
+        for (let i = 0; i < declaracao.caminhosSeSenao.length; i++) {
+            const atual = declaracao.caminhosSeSenao[i];
+
+            if (this.eVerdadeiro(await this.avaliar(atual.condicao))) {
+                return await this.executar(atual.caminho);
+            }
+        }
+
+        if (declaracao.caminhoSenao !== null) {
+            return await this.executar(declaracao.caminhoSenao);
+        }
+
+        return null;
+    }
+
     async visitarDeclaracaoEnquanto(declaracao: Enquanto): Promise<any> {
         let retornoExecucao: any;
         while (!(retornoExecucao instanceof Quebra) && this.eVerdadeiro(await this.avaliar(declaracao.condicao))) {
diff --git a/fontes/lexador/palavras-reservadas.ts b/fontes/lexador/palavras-reservadas.ts
index 3f57d6f1..e2037aa6 100644
--- a/fontes/lexador/palavras-reservadas.ts
+++ b/fontes/lexador/palavras-reservadas.ts
@@ -1,12 +1,14 @@
 import tiposDeSimbolos from '../tipos-de-simbolos/delegua';
 
 export default {
+    cada: tiposDeSimbolos.CADA,
     caso: tiposDeSimbolos.CASO,
     classe: tiposDeSimbolos.CLASSE,
     construtor: tiposDeSimbolos.CONSTRUTOR,
     continua: tiposDeSimbolos.CONTINUA,
     constante: tiposDeSimbolos.CONSTANTE,
     const: tiposDeSimbolos.CONSTANTE,
+    de: tiposDeSimbolos.DE,
     e: tiposDeSimbolos.E,
     em: tiposDeSimbolos.EM,
     enquanto: tiposDeSimbolos.ENQUANTO,
diff --git a/fontes/tipos-de-simbolos/delegua.ts b/fontes/tipos-de-simbolos/delegua.ts
index a049a35e..8fe0f81e 100644
--- a/fontes/tipos-de-simbolos/delegua.ts
+++ b/fontes/tipos-de-simbolos/delegua.ts
@@ -4,6 +4,7 @@ export default {
     BIT_OR: 'BIT_OR',
     BIT_XOR: 'BIT_XOR',
     BIT_NOT: 'BIT_NOT',
+    CADA: 'CADA',
     CASO: 'CASO',
     CHAVE_DIREITA: 'CHAVE_DIREITA',
     CHAVE_ESQUERDA: 'CHAVE_ESQUERDA',
@@ -13,6 +14,7 @@ export default {
     CONSTANTE: 'CONSTANTE',
     CONSTRUTOR: 'CONSTRUTOR',
     CONTINUA: 'CONTINUA',
+    DE: 'DE',
     DECREMENTAR: 'DECREMENTAR',
     DIFERENTE: 'DIFERENTE',
     DIVISAO: 'DIVISAO',


Test patch:
diff --git a/testes/avaliador-sintatico.test.ts b/testes/avaliador-sintatico.test.ts
index 3d762072..928bf733 100644
--- a/testes/avaliador-sintatico.test.ts
+++ b/testes/avaliador-sintatico.test.ts
@@ -75,6 +75,20 @@ describe('Avaliador sintático', () => {
                 expect(retornoAvaliadorSintatico).toBeTruthy();
                 expect(retornoAvaliadorSintatico.erros).toHaveLength(0);
             });
+
+            it('Sucesso - para cada', async () => {
+                const retornoLexador = lexador.mapear(
+                    [
+                        'para cada elemento em [1, 2, 3] {',
+                        "   escreva('Valor: ', elemento)",
+                        '}',
+                    ],
+                    -1
+                );
+                const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+    
+                expect(retornoAvaliadorSintatico.erros).toHaveLength(0);
+            });
     
             it('Sucesso - para/sustar', async () => {
                 const retornoLexador = lexador.mapear(
diff --git a/testes/interpretador.test.ts b/testes/interpretador.test.ts
index 0cad771b..66f9710a 100644
--- a/testes/interpretador.test.ts
+++ b/testes/interpretador.test.ts
@@ -493,6 +493,47 @@ describe('Interpretador', () => {
                     expect(retornoInterpretador.erros).toHaveLength(0);
                 });
 
+                it('Laços de repetição - para cada - trivial', async () => {
+                    const retornoLexador = lexador.mapear([
+                        "para cada elemento em [1, 2, 3] {",
+                        "   escreva('Valor: ', elemento)",
+                        "}",
+                    ], -1);
+                    const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+
+                    const retornoInterpretador = await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes);
+
+                    expect(retornoInterpretador.erros).toHaveLength(0);
+                });
+
+                it('Laços de repetição - para cada - vetor variável', async () => {
+                    const retornoLexador = lexador.mapear([
+                        "var v = [1, 2, 3]",
+                        "para cada elemento em v {",
+                        "   escreva('Valor: ', elemento)",
+                        "}",
+                    ], -1);
+                    const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+
+                    const retornoInterpretador = await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes);
+
+                    expect(retornoInterpretador.erros).toHaveLength(0);
+                });
+
+                it('Laços de repetição - para cada - vetor inválido', async () => {
+                    const retornoLexador = lexador.mapear([
+                        "var v = falso",
+                        "para cada elemento em v {",
+                        "   escreva('Valor: ', elemento)",
+                        "}",
+                    ], -1);
+                    const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+
+                    const retornoInterpretador = await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes);
+
+                    expect(retornoInterpretador.erros.length).toBeGreaterThan(0);
+                });
+
                 it('Laços de repetição - para', async () => {
                     const retornoLexador = lexador.mapear(["para (var i = 0; i < 10; i = i + 1) { escreva(i) }"], -1);
                     const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);