diff --git a/simulator/src/jack/compiler.ts b/simulator/src/jack/compiler.ts index debb48c2f..105302b4f 100644 --- a/simulator/src/jack/compiler.ts +++ b/simulator/src/jack/compiler.ts @@ -9,100 +9,106 @@ import JackLexer from "./generated/JackLexer.js"; import { CompilationError } from "../languages/base.js"; export function compile( - files: Record, + files: Record, ): Record { - try { - return _compile(files) - } catch (err) { - const result: Record = {}; - console.error(err); - const keys = Object.keys(files); - for (const name of keys) { - result[name] = { message: "Something went wrong while compiling files. Please create a bug report" } as CompilationError; - } - return result; + try { + return _compile(files); + } catch (err) { + const result: Record = {}; + console.error(err); + const keys = Object.keys(files); + for (const name of keys) { + result[name] = { + message: + "Something went wrong while compiling files. Please create a bug report", + } as CompilationError; } + return result; + } } -function _compile(files: Record, +function _compile( + files: Record, ): Record { - if (files instanceof LexerOrParserError) { - throw new Error("Expected tree but got a lexer or parser error"); - } - const result: Record = {}; - for (const name of Object.keys(files)) { - result[name] = ""; + if (files instanceof LexerOrParserError) { + throw new Error("Expected tree but got a lexer or parser error"); + } + const result: Record = {}; + for (const name of Object.keys(files)) { + result[name] = ""; + } + const trees: Record = {}; + const errors: Record = {}; + const compiler = new Compiler(); + for (const [name, content] of Object.entries(files)) { + const treeOrErrors = compiler.parserAndBind(content); + if (Array.isArray(treeOrErrors)) { + errors[name] = toCompilerError(treeOrErrors); } - const trees: Record = {}; - const errors: Record = {}; - const compiler = new Compiler(); - for (const [name, content] of Object.entries(files)) { - const treeOrErrors = compiler.parserAndBind(content); - if (Array.isArray(treeOrErrors)) { - errors[name] = toCompilerError(treeOrErrors); - } - trees[name] = treeOrErrors as ProgramContext; - } - if (Object.keys(errors).length > 0) { - for (const [name, error] of Object.entries(errors)) { - result[name] = error; - } - return result; + trees[name] = treeOrErrors as ProgramContext; + } + if (Object.keys(errors).length > 0) { + for (const [name, error] of Object.entries(errors)) { + result[name] = error; } + return result; + } - for (const [name, tree] of Object.entries(trees)) { - const compiledOrErrors = compiler.compile(tree); - if (Array.isArray(compiledOrErrors)) { - result[name] = toCompilerError(compiledOrErrors); - } else { - result[name] = compiledOrErrors; - } + for (const [name, tree] of Object.entries(trees)) { + const compiledOrErrors = compiler.compile(tree); + if (Array.isArray(compiledOrErrors)) { + result[name] = toCompilerError(compiledOrErrors); + } else { + result[name] = compiledOrErrors; } - return result; + } + return result; } function toCompilerError(errors: JackCompilerError[]): CompilationError { - const err = errors[0]; - return { message: `Line ${err.span.line}: ${err.msg}`, span: err.span } as CompilationError + const err = errors[0]; + return { + message: `Line ${err.span.line}: ${err.msg}`, + span: err.span, + } as CompilationError; } - export class Compiler { - private binder = new BinderListener(); - private errorListener = new CustomErrorListener(); - compile(tree: ProgramContext): string | JackCompilerError[] { - if (Object.keys(this.binder.globalSymbolTable).length == 0) { - throw new Error( - "Please populate global symbol table using parserAndBind method", - ); - } - const validator = new ValidatorListener(this.binder.globalSymbolTable); - ParseTreeWalker.DEFAULT.walk(validator, tree); - if (validator.errors.length > 0) { - console.log("Errors in validator " + JSON.stringify(validator.errors)); - return validator.errors; - } - const vmWriter = new VMWriter(this.binder.globalSymbolTable); - ParseTreeWalker.DEFAULT.walk(vmWriter, tree); - return vmWriter.result; + private binder = new BinderListener(); + private errorListener = new CustomErrorListener(); + compile(tree: ProgramContext): string | JackCompilerError[] { + if (Object.keys(this.binder.globalSymbolTable).length == 0) { + throw new Error( + "Please populate global symbol table using parserAndBind method", + ); } + const validator = new ValidatorListener(this.binder.globalSymbolTable); + ParseTreeWalker.DEFAULT.walk(validator, tree); + if (validator.errors.length > 0) { + console.log("Errors in validator " + JSON.stringify(validator.errors)); + return validator.errors; + } + const vmWriter = new VMWriter(this.binder.globalSymbolTable); + ParseTreeWalker.DEFAULT.walk(vmWriter, tree); + return vmWriter.result; + } - parserAndBind(src: string): ProgramContext | JackCompilerError[] { - const lexer = new JackLexer(CharStreams.fromString(src)); - lexer.removeErrorListeners(); - lexer.addErrorListener(this.errorListener); - const tokenStream = new CommonTokenStream(lexer); - const parser = new JackParser(tokenStream); - parser.removeErrorListeners(); - parser.addErrorListener(this.errorListener); - const tree = parser.program(); - if (this.errorListener.errors.length > 0) { - console.log("Errors when parsing or lexing"); - return this.errorListener.errors; - } - ParseTreeWalker.DEFAULT.walk(this.binder, tree); - if (this.binder.errors.length > 0) { - console.log("Errors in binder"); - return this.binder.errors; - } - return tree; + parserAndBind(src: string): ProgramContext | JackCompilerError[] { + const lexer = new JackLexer(CharStreams.fromString(src)); + lexer.removeErrorListeners(); + lexer.addErrorListener(this.errorListener); + const tokenStream = new CommonTokenStream(lexer); + const parser = new JackParser(tokenStream); + parser.removeErrorListeners(); + parser.addErrorListener(this.errorListener); + const tree = parser.program(); + if (this.errorListener.errors.length > 0) { + console.log("Errors when parsing or lexing"); + return this.errorListener.errors; + } + ParseTreeWalker.DEFAULT.walk(this.binder, tree); + if (this.binder.errors.length > 0) { + console.log("Errors in binder"); + return this.binder.errors; } + return tree; + } } diff --git a/simulator/src/jack/generated/JackLexer.ts b/simulator/src/jack/generated/JackLexer.ts index 55f6427e8..c5a8dc225 100644 --- a/simulator/src/jack/generated/JackLexer.ts +++ b/simulator/src/jack/generated/JackLexer.ts @@ -9,7 +9,7 @@ import { Lexer, LexerATNSimulator, PredictionContextCache, - Token + Token, } from "antlr4"; export default class JackLexer extends Lexer { public static readonly CLASS = 1; diff --git a/simulator/src/jack/generated/JackParser.ts b/simulator/src/jack/generated/JackParser.ts index b32052619..85b6338ff 100644 --- a/simulator/src/jack/generated/JackParser.ts +++ b/simulator/src/jack/generated/JackParser.ts @@ -2,21 +2,21 @@ // noinspection ES6UnusedImports,JSUnusedGlobalSymbols,JSUnusedLocalSymbols import { - ATN, - ATNDeserializer, - DecisionState, - DFA, - FailedPredicateException, - NoViableAltException, - Parser, - ParserATNSimulator, - ParserRuleContext, - PredictionContextCache, - RecognitionException, - RuleContext, - TerminalNode, - Token, - TokenStream + ATN, + ATNDeserializer, + DecisionState, + DFA, + FailedPredicateException, + NoViableAltException, + Parser, + ParserATNSimulator, + ParserRuleContext, + PredictionContextCache, + RecognitionException, + RuleContext, + TerminalNode, + Token, + TokenStream, } from "antlr4"; import JackParserListener from "./JackParserListener.js"; // for running tests with parameters, TODO: discuss strategy for typed parameters in CI diff --git a/simulator/src/jack/listener/error.listener.ts b/simulator/src/jack/listener/error.listener.ts index 1d443cd41..63b6594a2 100644 --- a/simulator/src/jack/listener/error.listener.ts +++ b/simulator/src/jack/listener/error.listener.ts @@ -12,6 +12,6 @@ export class CustomErrorListener extends ErrorListener { e: RecognitionException | undefined, ) => { const t = offendingSymbol as Token; - this.errors.push(new LexerOrParserError(line, t.start, t.stop+1, msg)); + this.errors.push(new LexerOrParserError(line, t.start, t.stop + 1, msg)); }; -} \ No newline at end of file +} diff --git a/simulator/src/jack/listener/validator.listener.test.ts b/simulator/src/jack/listener/validator.listener.test.ts index 3876cfa8e..ce0ed44f7 100644 --- a/simulator/src/jack/listener/validator.listener.test.ts +++ b/simulator/src/jack/listener/validator.listener.test.ts @@ -806,8 +806,8 @@ function testValidator( } catch (e) { throw new Error( `Expected error ${expectedError.name} but got '` + - validator.errors.join(",") + - "'", + validator.errors.join(",") + + "'", ); } } else { diff --git a/simulator/src/jack/listener/validator.listener.ts b/simulator/src/jack/listener/validator.listener.ts index b2e8db2e2..d2ccb209d 100644 --- a/simulator/src/jack/listener/validator.listener.ts +++ b/simulator/src/jack/listener/validator.listener.ts @@ -521,7 +521,7 @@ class BinaryTreeNode { public parent?: BinaryTreeNode, public left?: BinaryTreeNode, public right?: BinaryTreeNode, - ) { } + ) {} public get returns(): boolean { if (this._returns) { diff --git a/simulator/src/jack/parser.test.ts b/simulator/src/jack/parser.test.ts index b3d88db63..73e227899 100644 --- a/simulator/src/jack/parser.test.ts +++ b/simulator/src/jack/parser.test.ts @@ -2,59 +2,59 @@ import fs from "fs"; import path from "path"; import { - getTestResourcePath, - listenToTheTree, - parseJackFile, - parseJackText, - testResourceDirs, + getTestResourcePath, + listenToTheTree, + parseJackFile, + parseJackText, + testResourceDirs, } from "./test.helper"; import { BinderListener } from "./listener/binder.listener"; describe("Parser", () => { - const jestConsole = console; - beforeEach(() => { - global.console = require("console"); - }); + const jestConsole = console; + beforeEach(() => { + global.console = require("console"); + }); - afterEach(() => { - global.console = jestConsole; - }); + afterEach(() => { + global.console = jestConsole; + }); - test.each(testResourceDirs)("%s", (dir: string) => { - testJackDir(getTestResourcePath(dir)); - }); - test("expected EOF", () => { - try { - parseJackText(` + test.each(testResourceDirs)("%s", (dir: string) => { + testJackDir(getTestResourcePath(dir)); + }); + test("expected EOF", () => { + try { + parseJackText(` class A{ } var a; `); - } catch (e) { - if (e instanceof Error) { - expect(e.message).toContain("expecting "); - return; - } else { - fail("Expected Error"); - } - } + } catch (e) { + if (e instanceof Error) { + expect(e.message).toContain("expecting "); + return; + } else { fail("Expected Error"); - }); + } + } + fail("Expected Error"); + }); }); function testJackDir(testFolder: string): void { - const files = fs - .readdirSync(testFolder) - .filter((file) => file.endsWith(".jack")) - .map((file) => path.join(testFolder, file)); - for (const filePath of files) { - const tree = parseJackFile(filePath); - const globalSymbolsListener = listenToTheTree(tree, new BinderListener()); - const symbolsErrors = globalSymbolsListener.errors.join("\n"); - try { - expect(globalSymbolsListener.errors.length).toBe(0); - } catch (e) { - throw new Error(symbolsErrors); - } + const files = fs + .readdirSync(testFolder) + .filter((file) => file.endsWith(".jack")) + .map((file) => path.join(testFolder, file)); + for (const filePath of files) { + const tree = parseJackFile(filePath); + const globalSymbolsListener = listenToTheTree(tree, new BinderListener()); + const symbolsErrors = globalSymbolsListener.errors.join("\n"); + try { + expect(globalSymbolsListener.errors.length).toBe(0); + } catch (e) { + throw new Error(symbolsErrors); } + } } diff --git a/simulator/src/jack/test.helper.ts b/simulator/src/jack/test.helper.ts index e462e4bd6..81d3c6022 100644 --- a/simulator/src/jack/test.helper.ts +++ b/simulator/src/jack/test.helper.ts @@ -3,80 +3,80 @@ import path from "path"; import { JackCompilerError } from "./error"; import { CustomErrorListener } from "./listener/error.listener"; import { - CharStreams, - CommonTokenStream, - ParseTreeListener, - ParseTreeWalker, + CharStreams, + CommonTokenStream, + ParseTreeListener, + ParseTreeWalker, } from "antlr4"; import JackLexer from "./generated/JackLexer"; import JackParser, { ProgramContext } from "./generated/JackParser"; export function parseJackFile(filePath: string, trace = false) { - const errorListener: CustomErrorListener = new CustomErrorListener(); - const f = fs.readFileSync(filePath, "utf8"); - return parseJackText(f, errorListener, trace); + const errorListener: CustomErrorListener = new CustomErrorListener(); + const f = fs.readFileSync(filePath, "utf8"); + return parseJackText(f, errorListener, trace); } export function parseJackText( - src: string, - errorListener?: CustomErrorListener, - trace = false, - throwOnErrors = true, + src: string, + errorListener?: CustomErrorListener, + trace = false, + throwOnErrors = true, ): ProgramContext { - if (errorListener === undefined) { - errorListener = new CustomErrorListener(); - } - const inputStream = CharStreams.fromString(src); - const lexer = new JackLexer(inputStream); - if (errorListener) { - lexer.removeErrorListeners(); - lexer.addErrorListener(errorListener); - } + if (errorListener === undefined) { + errorListener = new CustomErrorListener(); + } + const inputStream = CharStreams.fromString(src); + const lexer = new JackLexer(inputStream); + if (errorListener) { + lexer.removeErrorListeners(); + lexer.addErrorListener(errorListener); + } - const tokenStream = new CommonTokenStream(lexer); - const parser = new JackParser(tokenStream); - if (errorListener != undefined) { - parser.removeErrorListeners(); - parser.addErrorListener(errorListener); - } - const tree = parser.program(); + const tokenStream = new CommonTokenStream(lexer); + const parser = new JackParser(tokenStream); + if (errorListener != undefined) { + parser.removeErrorListeners(); + parser.addErrorListener(errorListener); + } + const tree = parser.program(); - expect(tokenStream.tokens.length).toBeGreaterThan(0); - if (errorListener.errors.length > 0) { - console.error("Parser or lexer errors found"); - handleErrors(src, errorListener.errors); - } - return tree; + expect(tokenStream.tokens.length).toBeGreaterThan(0); + if (errorListener.errors.length > 0) { + console.error("Parser or lexer errors found"); + handleErrors(src, errorListener.errors); + } + return tree; } export function getTestResourcePath(relativePath: string) { - return path.join(__dirname, "resources", "test", relativePath); + return path.join(__dirname, "resources", "test", relativePath); } export function listenToTheTree( - tree: ProgramContext, - listener: T, + tree: ProgramContext, + listener: T, ) { - ParseTreeWalker.DEFAULT.walk(listener, tree); - return listener; + ParseTreeWalker.DEFAULT.walk(listener, tree); + return listener; } export function handleErrors(src: string, errors: JackCompilerError[]) { - const msg = errors - .map((e) => { - return `${e.span.line}:${e.span.start} ${e.msg}\n${src.split("\n")[e.span.line]}`; - }) - .join("\n"); - console.error(msg); - throw new Error(msg); + const msg = errors + .map((e) => { + return `${e.span.line}:${e.span.start} ${e.msg}\n${src.split("\n")[e.span.line]}`; + }) + .join("\n"); + console.error(msg); + throw new Error(msg); } export const testResourceDirs: string[] = [ - "Average", - "ConvertToBin", - "Fraction", - "HelloWorld", - "List", - "Pong", - "Square", - "ComplexArrays", + "Average", + "ConvertToBin", + "Fraction", + "HelloWorld", + "List", + "Pong", + "Square", + "ComplexArrays", ];