From 1d7f28df9cd4257f2a77b1f633c4f3d50a64f188 Mon Sep 17 00:00:00 2001 From: R-unic Date: Fri, 6 Oct 2023 22:24:17 -0400 Subject: [PATCH] refactor: move all code analysis/runtime elements into a new class, PHost --- package-lock.json | 8 ++--- package.json | 4 ++- src/runtime/interpreter.ts | 9 +++-- src/runtime/intrinsics/eval.ts | 8 ++--- src/runtime/intrinsics/index.ts | 2 +- src/unit-tests/binder-test.ts | 2 +- src/unit-tests/interpreter-test.ts | 2 +- src/unit-tests/resolver-test.ts | 2 +- src/unit-tests/type-checker-test.ts | 6 ++-- tools/classes/ast-viewer.ts | 3 +- tools/classes/p-host.ts | 32 ++++++++++++++++++ tools/p.ts | 52 ++++++++++------------------- 12 files changed, 72 insertions(+), 58 deletions(-) create mode 100644 tools/classes/p-host.ts diff --git a/package-lock.json b/package-lock.json index 0e3836b7..e31bc4d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "plang", - "version": "0.1.5a", + "version": "0.1.6a", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "plang", - "version": "0.1.5a", + "version": "0.1.6a", "license": "LGPL-2.1-or-later", "dependencies": { "colors.ts": "^1.0.20", @@ -18,9 +18,7 @@ "typescript": "^5.2.2" }, "bin": { - "ast-viewer": "dist/tools/ast-viewer.js", - "pint": "dist/tools/pint.js", - "prepl": "dist/tools/repl.js" + "pint": "dist/tools/pint.js" }, "devDependencies": { "@types/mocha": "^10.0.2", diff --git a/package.json b/package.json index 9a7c4855..b4706729 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,9 @@ "displayName": "PLang", "icon": "https://avatars.githubusercontent.com/u/146694713?s=400&u=4e01b5afefbf7e40641702e5cbdf785ff183fe35&v=4", "main": "dist/src/main.js", - "bin": { "pint": "dist/tools/pint.js" }, + "bin": { + "pint": "dist/tools/pint.js" + }, "scripts": { "test": "mocha dist/src/unit-tests -j 4 --extension js", "build": "tsc --skipLibCheck", diff --git a/src/runtime/interpreter.ts b/src/runtime/interpreter.ts index 95a4b53c..9edf9dd0 100644 --- a/src/runtime/interpreter.ts +++ b/src/runtime/interpreter.ts @@ -6,13 +6,13 @@ import { fakeToken, getIntrinsicExtension } from "../utility"; import { INTRINSIC_EXTENDED_LITERAL_VALUE_TYPES } from "../code-analysis/type-checker/types/type-sets"; import type Binder from "../code-analysis/type-checker/binder"; import type Resolver from "../code-analysis/resolver"; +import type P from "../../tools/p"; +import Syntax from "../code-analysis/tokenization/syntax-type"; import Scope from "./scope"; -import PFunction from "./values/function"; import HookedException from "./hooked-exceptions"; import Intrinsics from "./intrinsics"; -import Syntax from "../code-analysis/tokenization/syntax-type"; +import PFunction from "./values/function"; import AST from "../code-analysis/parser/ast"; -import P from "../../tools/p"; import { LiteralExpression } from "../code-analysis/parser/ast/expressions/literal"; import type { StringInterpolationExpression } from "../code-analysis/parser/ast/expressions/string-interpolation"; @@ -37,7 +37,6 @@ import type { IfStatement } from "../code-analysis/parser/ast/statements/if"; import type { WhileStatement } from "../code-analysis/parser/ast/statements/while"; import type { FunctionDeclarationStatement } from "../code-analysis/parser/ast/statements/function-declaration"; import type { ReturnStatement } from "../code-analysis/parser/ast/statements/return"; -import Intrinsic from "./values/intrinsic"; const MAX_RECURSION_DEPTH = 1200; @@ -50,7 +49,7 @@ export default class Interpreter implements AST.Visitor.Expression, A private readonly intrinsics = new Intrinsics(this); public constructor( - public readonly runner: P, + public readonly host: P, public readonly resolver: Resolver, public readonly binder: Binder, public fileName = "unnamed" diff --git a/src/runtime/intrinsics/eval.ts b/src/runtime/intrinsics/eval.ts index dbebb9cb..430406c2 100644 --- a/src/runtime/intrinsics/eval.ts +++ b/src/runtime/intrinsics/eval.ts @@ -8,10 +8,10 @@ export default class Eval extends Intrinsic.Function { public readonly argumentTypes = { code: new SingularType("string") }; public call(code: string): ValueType { - const enclosingResultOutputEnabled = this.interpreter!.runner.executionOptions.outputResult; - this.interpreter!.runner.executionOptions.outputResult = false; - const result = this.interpreter!.runner.doString(code); - this.interpreter!.runner.executionOptions.outputResult = enclosingResultOutputEnabled; + const enclosingResultOutputEnabled = this.interpreter!.host.executionOptions.outputResult; + this.interpreter!.host.executionOptions.outputResult = false; + const result = this.interpreter!.host.doString(code); + this.interpreter!.host.executionOptions.outputResult = enclosingResultOutputEnabled; return result; } } \ No newline at end of file diff --git a/src/runtime/intrinsics/index.ts b/src/runtime/intrinsics/index.ts index b6930216..43de2f94 100644 --- a/src/runtime/intrinsics/index.ts +++ b/src/runtime/intrinsics/index.ts @@ -21,7 +21,7 @@ export default class Intrinsics { ) {} public inject(): void { - this.define("version$", this.interpreter.runner.version, new SingularType("string")); + this.define("version$", this.interpreter.host.version, new SingularType("string")); this.define("filename$", this.interpreter.fileName, new SingularType("string")); this.define("dirname$", path.dirname(this.interpreter.fileName), new SingularType("string")); this.define("argv", argv.slice(3), new ArrayType(new SingularType("string"))); diff --git a/src/unit-tests/binder-test.ts b/src/unit-tests/binder-test.ts index 2e36ae4f..f1c273ad 100644 --- a/src/unit-tests/binder-test.ts +++ b/src/unit-tests/binder-test.ts @@ -24,7 +24,7 @@ function bind(source: string): BoundStatement[] { const p = new P("test"); const parser = p.createParser(source); const ast = parser.parse(); - return p.binder.bindStatements(ast); + return p.host.binder.bindStatements(ast); } const testDirectory = "./tests/"; diff --git a/src/unit-tests/interpreter-test.ts b/src/unit-tests/interpreter-test.ts index 66157524..6c703fc1 100644 --- a/src/unit-tests/interpreter-test.ts +++ b/src/unit-tests/interpreter-test.ts @@ -15,7 +15,7 @@ let p = new P("test"); function evaluate(source: string, createNewEnvironment = true): ValueType { const result = p.doString(source); if (createNewEnvironment) - p.refreshResources(); + p.newHost(); return result; } diff --git a/src/unit-tests/resolver-test.ts b/src/unit-tests/resolver-test.ts index 6a5ea0a1..9d731cb2 100644 --- a/src/unit-tests/resolver-test.ts +++ b/src/unit-tests/resolver-test.ts @@ -13,7 +13,7 @@ function getResolveFunction(source: string): () => void { const p = new P("test"); const parser = p.createParser(source); const ast = parser.parse(); - return () => p.resolver.resolve(ast); + return () => p.host.resolver.resolve(ast); } const testDirectory = "./tests/"; diff --git a/src/unit-tests/type-checker-test.ts b/src/unit-tests/type-checker-test.ts index 5ab8a1b4..5d5dc375 100644 --- a/src/unit-tests/type-checker-test.ts +++ b/src/unit-tests/type-checker-test.ts @@ -13,9 +13,9 @@ function getCheckFunction(source: string): () => void { const p = new P("test"); const parser = p.createParser(source); const ast = parser.parse(); - p.resolver.resolve(ast); - const boundAST = p.binder.bindStatements(ast); - return () => p.typeChecker.check(boundAST); + p.host.resolver.resolve(ast); + const boundAST = p.host.binder.bindStatements(ast); + return () => p.host.typeChecker.check(boundAST); } const testDirectory = "./tests/"; diff --git a/tools/classes/ast-viewer.ts b/tools/classes/ast-viewer.ts index 2cde9bb5..94615523 100644 --- a/tools/classes/ast-viewer.ts +++ b/tools/classes/ast-viewer.ts @@ -3,7 +3,6 @@ import reader from "readline-sync"; import { BoundNode } from "../../src/code-analysis/type-checker/binder/bound-node"; import { Type } from "../../src/code-analysis/type-checker/types/type"; import type P from "../p"; -import Parser from "../../src/code-analysis/parser"; import AST from "../../src/code-analysis/parser/ast"; namespace ASTViewer { @@ -17,7 +16,7 @@ namespace ASTViewer { const parser = p.createParser(source); const ast = parser.parse(); if (option === "bound") { - const boundAST = p.binder.bindStatements(ast); + const boundAST = p.host.binder.bindStatements(ast); viewNodeList(boundAST); } else diff --git a/tools/classes/p-host.ts b/tools/classes/p-host.ts new file mode 100644 index 00000000..3be0a3f7 --- /dev/null +++ b/tools/classes/p-host.ts @@ -0,0 +1,32 @@ +import { TypeChecker } from "../../src/code-analysis/type-checker"; +import type P from "../p"; +import Lexer from "../../src/code-analysis/tokenization/lexer"; +import TypeTracker from "../../src/code-analysis/parser/type-tracker"; +import TypeAnalyzer from "../../src/code-analysis/parser/type-analyzer"; +import Parser from "../../src/code-analysis/parser"; +import Resolver from "../../src/code-analysis/resolver"; +import Binder from "../../src/code-analysis/type-checker/binder"; +import Interpreter from "../../src/runtime/interpreter"; + +export default class PHost { + private typeTracker = new TypeTracker; + public resolver = new Resolver; + public binder = new Binder; + public typeChecker = new TypeChecker; + public interpreter: Interpreter; + + public constructor( + private readonly runner: P, + fileName?: string + ) { + this.interpreter = new Interpreter(runner, this.resolver, this.binder, fileName) + } + + public createParser(source: string): Parser { + const lexer = new Lexer(source); + const tokens = lexer.tokenize(); + const typeAnalyzer = new TypeAnalyzer(tokens, this.typeTracker); + typeAnalyzer.analyze(); + return new Parser(tokens, typeAnalyzer, this.runner); + } +} \ No newline at end of file diff --git a/tools/p.ts b/tools/p.ts index bccc9501..427946bc 100644 --- a/tools/p.ts +++ b/tools/p.ts @@ -2,14 +2,9 @@ import { readFileSync } from "fs"; import util from "util"; import "colors.ts"; -import { TypeChecker, ValueType } from "../src/code-analysis/type-checker"; -import Lexer from "../src/code-analysis/tokenization/lexer"; -import TypeTracker from "../src/code-analysis/parser/type-tracker"; -import TypeAnalyzer from "../src/code-analysis/parser/type-analyzer"; +import type { ValueType } from "../src/code-analysis/type-checker"; +import PHost from "./classes/p-host"; import Parser from "../src/code-analysis/parser"; -import Binder from "../src/code-analysis/type-checker/binder"; -import Resolver from "../src/code-analysis/resolver"; -import Interpreter from "../src/runtime/interpreter"; import PValue from "../src/runtime/values/value"; import REPL from "./classes/repl"; import pkg = require("../package.json"); @@ -22,12 +17,7 @@ interface PExecutionOptions { } export default class P { - private typeTracker = new TypeTracker; - - public resolver = new Resolver; - public binder = new Binder; - public typeChecker = new TypeChecker; - public interpreter: Interpreter; + public host: PHost; public readonly repl = new REPL(this); public readonly version = "v" + pkg.version; public readonly executionOptions: PExecutionOptions = { @@ -37,16 +27,10 @@ export default class P { outputResult: false }; - public constructor(fileName?: string) { - this.interpreter = new Interpreter(this, this.resolver, this.binder, fileName) - } - - public createParser(source: string): Parser { - const lexer = new Lexer(source); - const tokens = lexer.tokenize(); - const typeAnalyzer = new TypeAnalyzer(tokens, this.typeTracker); - typeAnalyzer.analyze(); - return new Parser(tokens, typeAnalyzer, this); + public constructor( + private readonly fileName?: string + ) { + this.host = new PHost(this, fileName); } public doString(source: string): ValueType { @@ -58,13 +42,13 @@ export default class P { if (this.executionOptions.outputAST) console.log(ast.toString()); - this.resolver.resolve(ast); - const boundAST = this.binder.bindStatements(ast); + this.host.resolver.resolve(ast); + const boundAST = this.host.binder.bindStatements(ast); if (this.executionOptions.outputBoundAST) console.log(boundAST.toString()); - this.typeChecker.check(boundAST); - const result = this.interpreter.evaluate(ast); + this.host.typeChecker.check(boundAST); + const result = this.host.interpreter.evaluate(ast); if (this.executionOptions.outputResult) { const stringified = result instanceof PValue ? @@ -80,15 +64,15 @@ export default class P { public doFile(filePath: string): ValueType { const fileContents = readFileSync(filePath, "utf-8"); const result = this.doString(fileContents); - this.refreshResources(); + this.newHost(); return result; } - public refreshResources(): void { - this.typeTracker = new TypeTracker; - this.binder = new Binder; - this.resolver = new Resolver; - this.typeChecker = new TypeChecker; - this.interpreter = new Interpreter(this, this.resolver, this.binder, this.interpreter.fileName); + public createParser(source: string): Parser { + return this.host.createParser(source); + } + + public newHost(): void { + this.host = new PHost(this, this.fileName); } } \ No newline at end of file