Skip to content

Commit

Permalink
Melhorias no tratamento de erros
Browse files Browse the repository at this point in the history
Fixes PORTUGOL-WEBSTUDIO-6J0
Fixes PORTUGOL-WEBSTUDIO-6HS
Fixes PORTUGOL-WEBSTUDIO-6HW
Fixes PORTUGOL-WEBSTUDIO-647
Fixes PORTUGOL-WEBSTUDIO-5Z9
Fixes PORTUGOL-WEBSTUDIO-6KE
  • Loading branch information
dgadelha committed Jan 5, 2025
1 parent 30c1df9 commit e305ae6
Show file tree
Hide file tree
Showing 11 changed files with 133 additions and 104 deletions.
11 changes: 11 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"recommendations": [
"angular.ng-template",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"jock.svg",
"wayou.vscode-todo-highlight",
"webhint.vscode-webhint",
"zjcompt.es6-string-javascript"
]
}
10 changes: 10 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"files.eol": "\n",
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "always",
"source.organizeImports": "always"
},
"js/ts.implicitProjectConfig.checkJs": true
}
5 changes: 4 additions & 1 deletion angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@
}
},
"cli": {
"analytics": false
"analytics": false,
"cache": {
"enabled": false
}
}
}
71 changes: 48 additions & 23 deletions packages/antlr/src/PortugolErrorListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,38 +27,66 @@ export class PortugolCodeError extends Error {
static fromContext(ctx: ParseTree, message: string) {
let possibleContext = ctx;

if (!ctx.hasOwnProperty("start") && !ctx.hasOwnProperty("stop") && ctx.parent) {
if (
typeof ctx === "object" &&
ctx !== null &&
!Object.hasOwn(ctx, "start") &&
!Object.hasOwn(ctx, "stop") &&
Object.hasOwn(ctx, "parent") &&
typeof ctx.parent === "object" &&
ctx.parent !== null
) {
possibleContext = ctx.parent;
}

if (!possibleContext) {
return new PortugolCodeError(message, ctx, 1, 0, 9999, 0);
}

if (
possibleContext.hasOwnProperty("start") &&
possibleContext.hasOwnProperty("stop") &&
Object.hasOwn(possibleContext, "start") &&
Object.hasOwn(possibleContext, "stop") &&
typeof (possibleContext as unknown as { start: unknown }).start === "object" &&
typeof (possibleContext as unknown as { stop: unknown }).stop === "object" &&
(possibleContext as unknown as { start: unknown }).start !== null &&
(possibleContext as unknown as { stop: unknown }).stop !== null
(possibleContext as unknown as { start: unknown }).start !== null
) {
const { start, stop } = possibleContext as unknown as { start: Token; stop: Token };
const { start, stop } = possibleContext as unknown as { start: Token; stop?: Token };
const { line: startLine, column: startCol } = start;
let { line: endLine, column: endCol } = stop;

if (startLine === endLine && startCol === endCol) {
endCol += ctx.getText().length - 1;
if (typeof stop === "object" && stop !== null) {
let { line: endLine, column: endCol } = stop;

if (startLine === endLine && startCol === endCol) {
endCol += ctx.getText().length - 1;
}

return new PortugolCodeError(message, ctx, startLine, startCol, endLine, endCol);
}

return new PortugolCodeError(message, ctx, startLine, startCol, endLine, endCol);
return new PortugolCodeError(
message,
ctx,
Math.max(startLine - 1, 1),
startCol,
startLine,
startCol + ctx.getText().length,
);
}

const possibleSymbol = ctx.getPayload() as Token | ParseTree | ParserRuleContext | undefined;
if (Object.hasOwn(ctx, "getPayload") && typeof ctx.getPayload === "function") {
const possibleSymbol = ctx.getPayload() as Token | ParseTree | ParserRuleContext | undefined;

if (possibleSymbol && possibleSymbol.hasOwnProperty("column") && possibleSymbol.hasOwnProperty("line")) {
const { line, column } = possibleSymbol as unknown as Token;
if (possibleSymbol && Object.hasOwn(possibleSymbol, "column") && Object.hasOwn(possibleSymbol, "line")) {
const { line, column } = possibleSymbol as unknown as Token;

return new PortugolCodeError(message, ctx, line, column, line, column + ctx.getText().length);
return new PortugolCodeError(message, ctx, line, column, line, column + ctx.getText().length);
}
}

return new PortugolCodeError(message, ctx, 1, 1, 1, 2 + ctx.getText().length);
if (Object.hasOwn(ctx, "getText") && typeof ctx.getText === "function") {
return new PortugolCodeError(message, ctx, 1, 1, 1, 2 + ctx.getText().length);
}

return new PortugolCodeError(message, ctx, 1, 0, 9999, 0);
}
}

Expand All @@ -68,16 +96,13 @@ export class PortugolErrorListener implements ANTLRErrorListener {
syntaxError<S extends Token, T extends ATNSimulator>(
_recognizer: Recognizer<T>,
offendingSymbol: S | null,
line: number,
charPositionInLine: number,
msg: string,
_line: number,
_charPositionInLine: number,
_msg: string,
e: RecognitionException | null,
): void {
const endColumn =
offendingSymbol && offendingSymbol.text ? charPositionInLine + offendingSymbol.text.length : charPositionInLine;

this.errors.push(
new PortugolCodeError(msg, e?.ctx || offendingSymbol || (null as any), line, charPositionInLine, line, endColumn),
PortugolCodeError.fromContext(e?.ctx || offendingSymbol || (null as any), "Código incompleto ou inválido"),
);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/ide/src/app/file.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ export class FileService {
confidence,
});

return decode(array as any, encoding);
return decode(array as any, encoding || "utf8");
}
}
4 changes: 2 additions & 2 deletions packages/ide/src/app/tab-editor/tab-editor.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export class TabEditorComponent implements OnInit, OnDestroy {

generatedCodeEditorOptions: monaco.editor.IStandaloneEditorConstructionOptions = {
...this.stdOutEditorOptions,
language: "javascript",
language: "swift",
};

sharing = false;
Expand Down Expand Up @@ -423,7 +423,7 @@ export class TabEditorComponent implements OnInit, OnDestroy {
)
.subscribe({
next: result => {
this.setEditorErrors(result.errors);
this.setEditorErrors(result.errors.concat(result.parseErrors));
},
error(err) {
console.error(err);
Expand Down
2 changes: 1 addition & 1 deletion packages/ide/src/app/tab-start/tab-start.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ <h4><svg-icon src="assets/mdi/newspaper.svg" svgAriaLabel="Ícone de jornal para
<p>
<strong>04/01/2025:</strong> Configurações de exibição do editor de código adicionadas, agora é possível alterar o
tamanho da fonte e a quebra de linha. Nova opção para escolher o local de salvar o arquivo (somente no Chrome ou
Edge).
Edge). Melhorias na exibição de erros.
</p>
<p>
<strong>26/12/2024:</strong> Adicionado o tema claro e a tela de configurações para escolher o tema da IDE, mais
Expand Down
2 changes: 1 addition & 1 deletion packages/ide/src/app/worker.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export class WorkerService {

async checkCode(code: string): Promise<{
errors: PortugolCodeError[];
parseErrors: Error[];
parseErrors: PortugolCodeError[];
}> {
if (!this.worker) {
this.init();
Expand Down
46 changes: 35 additions & 11 deletions packages/parser/src/PortugolErrorChecker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,42 +11,66 @@ import errorCheckers from "./errors/index.js";
import { ParseError } from "./helpers/ParseError.js";
import { PortugolNode } from "./PortugolNode.js";

export interface IPortugolErrorCheckerResult {
parseErrors: PortugolCodeError[];
errors: PortugolCodeError[];
tree: ArquivoContext;
}

export class PortugolErrorChecker {
private static portugolNode = new PortugolNode();
private static errorListener = new PortugolErrorListener();

public static checkCode(code: string): PortugolCodeError[] {
public static checkCode(code: string): IPortugolErrorCheckerResult {
const errorListener = new PortugolErrorListener();
const inputStream = CharStream.fromString(code);
const lexer = new PortugolLexer(inputStream);
const tokenStream = new CommonTokenStream(lexer);
const parser = new PortugolParser(tokenStream);
const tree = parser.arquivo();

parser.addErrorListener(this.errorListener);
parser.removeErrorListeners();
parser.addErrorListener(errorListener);

const tree = parser.arquivo();
const treeResult = this.checkTree(tree);

return this.checkTree(tree);
return {
parseErrors: errorListener.getErrors().concat(treeResult.parseErrors),
errors: treeResult.errors,
tree,
};
}

public static checkTree(tree: ArquivoContext): PortugolCodeError[] {
this.errorListener.reset();
private static checkTree(tree: ArquivoContext): IPortugolErrorCheckerResult {
const errors: PortugolCodeError[] = [];

try {
const arquivo = this.portugolNode.visit(tree);
const errors: PortugolCodeError[] = [];

for (const checker of errorCheckers) {
for (const error of checker(arquivo)) {
errors.push(error);
}
}

return this.errorListener.getErrors().concat(errors);
return {
parseErrors: [],
errors,
tree,
};
} catch (error) {
if (error instanceof ParseError) {
return this.errorListener.getErrors().concat(PortugolCodeError.fromContext(error.ctx, error.message));
return {
parseErrors: [PortugolCodeError.fromContext(error.ctx, error.message)],
errors,
tree,
};
}

return this.errorListener.getErrors().concat(PortugolCodeError.fromContext(tree, String(error)));
return {
parseErrors: [],
errors: errors.concat(PortugolCodeError.fromContext(tree, String(error))),
tree,
};
}
}
}
38 changes: 11 additions & 27 deletions packages/runner/src/PortugolExecutor.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { PortugolCodeError, PortugolErrorListener, PortugolLexer, PortugolParser } from "@portugol-webstudio/antlr";
import { PortugolCodeError, PortugolErrorListener } from "@portugol-webstudio/antlr";
import { PortugolErrorChecker } from "@portugol-webstudio/parser";
import { PortugolJs } from "@portugol-webstudio/runtime";
import { CharStream, CommonTokenStream } from "antlr4ng";
import { Subject, Subscription } from "rxjs";

import { IPortugolRunner, PortugolEvent } from "./runners/IPortugolRunner.js";
Expand Down Expand Up @@ -51,54 +50,40 @@ export class PortugolExecutor {

run(code: string) {
let errors: PortugolCodeError[] = [];
let parseErrors: PortugolCodeError[] = [];
let js = "";
let parseStart = 0;
let parseEnd = 0;
let checkStart = 0;
let checkEnd = 0;
let transpileStart = 0;
let transpileEnd = 0;

try {
parseStart = performance.now();

const inputStream = CharStream.fromString(code);
const lexer = new PortugolLexer(inputStream);
const tokenStream = new CommonTokenStream(lexer);
const parser = new PortugolParser(tokenStream);

this.errorListener.reset();

parser.removeErrorListeners();
parser.addErrorListener(this.errorListener);

const tree = parser.arquivo();
checkStart = performance.now();
const checkResult = PortugolErrorChecker.checkCode(code);

parseEnd = performance.now();
errors = checkResult.errors;
parseErrors = checkResult.parseErrors;

checkStart = performance.now();
errors = PortugolErrorChecker.checkTree(tree);
checkEnd = performance.now();

transpileStart = performance.now();
js = new PortugolJs().visit(tree)!;
js = new PortugolJs().visit(checkResult.tree)!;
transpileEnd = performance.now();
} catch {}

this.runTranspiled({
code,
js,
errors,
parseErrors: this.errorListener.getErrors(),
parseErrors,
times: {
parse: parseEnd - parseStart,
check: checkEnd - checkStart,
transpile: transpileEnd - transpileStart,
},
});
}

#printTimes(_times: { parse: number; check: number; transpile: number; execution?: number }) {}
#printTimes(_times: { check: number; transpile: number; execution?: number }) {}

runTranspiled({
code,
Expand All @@ -111,7 +96,7 @@ export class PortugolExecutor {
js: string;
errors: PortugolCodeError[];
parseErrors: PortugolCodeError[];
times: { parse: number; check: number; transpile: number };
times: { check: number; transpile: number };
}) {
try {
this.reset();
Expand Down Expand Up @@ -147,8 +132,7 @@ export class PortugolExecutor {
.join("");

this.stdOut +=
"\n⚠️ Durante essa fase experimental, o código ainda será executado mesmo com erros, porém se não corrigi-los, a execução abaixo pode exibir mensagens de erro em inglês ou sem explicação.\n";
this.stdOut += ` Caso acredite que o erro não faça sentido, por favor, abra uma issue em https://github.com/dgadelha/Portugol-Webstudio/issues/new/choose e anexe o código que você está tentando executar.\n\n`;
"\n⚠️ Estamos aprimorando a detecção de erros. Seu código será executado mesmo com erros, mas se não forem corrigidos, a execução pode exibir mensagens de erro em inglês ou sem explicação.\n";

argueAboutAlgolIfNeeded();

Expand Down
Loading

0 comments on commit e305ae6

Please sign in to comment.