Comparing version 0.11.0 to 0.11.1
@@ -1,5 +0,1 @@ | ||
import { | ||
visitExpr, | ||
visitStmt | ||
} from "./ast.js"; | ||
import { LoxCallable } from "./callable.js"; | ||
@@ -12,17 +8,5 @@ import { Environment } from "./environment.js"; | ||
import { runtimeError } from "./main.js"; | ||
class ClockFn extends LoxCallable { | ||
arity() { | ||
return 0; | ||
} | ||
call() { | ||
return Date.now(); | ||
} | ||
toString() { | ||
return "<native fn>"; | ||
} | ||
} | ||
class ReturnCall extends Error { | ||
class ReturnCall { | ||
value; | ||
constructor(value) { | ||
super(); | ||
this.value = value; | ||
@@ -48,2 +32,5 @@ } | ||
} | ||
function assertUnreachable(x) { | ||
throw new Error(`Unreachable code reached! ${x}`); | ||
} | ||
class Interpreter { | ||
@@ -54,14 +41,15 @@ globals = new Environment(); | ||
constructor() { | ||
this.globals.define("clock", new ClockFn()); | ||
this.globals.define( | ||
"clock", | ||
// Can't use an object literal here because it must be instanceof LoxCallable. | ||
new class extends LoxCallable { | ||
arity = () => 0; | ||
call = () => Date.now(); | ||
toString = () => "<native fn>"; | ||
}() | ||
); | ||
} | ||
return(stmt) { | ||
const value = stmt.value && this.evaluate(stmt.value); | ||
throw new ReturnCall(value); | ||
} | ||
resolve(expr, depth) { | ||
this.#locals.set(expr, depth); | ||
} | ||
"var-expr"(expr) { | ||
return this.#lookUpVariable(expr.name, expr); | ||
} | ||
#lookUpVariable(name, expr) { | ||
@@ -74,19 +62,2 @@ const distance = this.#locals.get(expr); | ||
} | ||
"var-stmt"(stmt) { | ||
let value = null; | ||
if (stmt.initializer) { | ||
value = this.evaluate(stmt.initializer); | ||
} | ||
this.#environment.define(stmt.name.lexeme, value); | ||
} | ||
assign(expr) { | ||
const value = this.evaluate(expr.value); | ||
const distance = this.#locals.get(expr); | ||
if (distance !== void 0) { | ||
this.#environment.assignAt(distance, expr.name, value); | ||
} else { | ||
this.globals.assign(expr.name, value); | ||
} | ||
return value; | ||
} | ||
binary(expr) { | ||
@@ -145,5 +116,2 @@ const left = this.evaluate(expr.left); | ||
} | ||
block(block) { | ||
this.executeBlock(block.statements, new Environment(this.#environment)); | ||
} | ||
call(expr) { | ||
@@ -181,9 +149,111 @@ const callee = this.evaluate(expr.callee); | ||
evaluate(expr) { | ||
return visitExpr(expr, this); | ||
switch (expr.kind) { | ||
case "assign": | ||
const value = this.evaluate(expr.value); | ||
const distance = this.#locals.get(expr); | ||
if (distance !== void 0) { | ||
this.#environment.assignAt(distance, expr.name, value); | ||
} else { | ||
this.globals.assign(expr.name, value); | ||
} | ||
return value; | ||
case "binary": | ||
return this.binary(expr); | ||
case "call": | ||
return this.call(expr); | ||
case "get": { | ||
const obj = this.evaluate(expr.object); | ||
if (obj instanceof LoxInstance) { | ||
return obj.get(expr.name); | ||
} | ||
throw new RuntimeError(expr.name, "Only instances have properties."); | ||
} | ||
case "grouping": | ||
return this.evaluate(expr.expr); | ||
case "literal": | ||
return expr.value; | ||
case "logical": | ||
const left = this.evaluate(expr.left); | ||
if (expr.operator.type == "or") { | ||
if (isTruthy(left)) { | ||
return left; | ||
} | ||
} else { | ||
if (!isTruthy(left)) { | ||
return left; | ||
} | ||
} | ||
return this.evaluate(expr.right); | ||
case "set": { | ||
const obj = this.evaluate(expr.object); | ||
if (!(obj instanceof LoxInstance)) { | ||
throw new RuntimeError(expr.name, "Only instances have fields."); | ||
} | ||
const value2 = this.evaluate(expr.value); | ||
obj.set(expr.name, value2); | ||
return value2; | ||
} | ||
case "unary": | ||
const right = this.evaluate(expr.right); | ||
switch (expr.operator.type) { | ||
case "-": | ||
checkNumberOrCurrencyOperand(expr.operator, right); | ||
return applyToNumOrCurrency(right, (v) => -v); | ||
case "!": | ||
return !isTruthy(right); | ||
} | ||
throw new Error(`Unknown unary type ${expr.operator.type}`); | ||
case "this": | ||
return this.#lookUpVariable(expr.keyword, expr); | ||
case "var-expr": | ||
return this.#lookUpVariable(expr.name, expr); | ||
} | ||
} | ||
this(expr) { | ||
return this.#lookUpVariable(expr.keyword, expr); | ||
} | ||
execute(stmt) { | ||
visitStmt(stmt, this); | ||
switch (stmt.kind) { | ||
case "block": | ||
this.executeBlock(stmt.statements, new Environment(this.#environment)); | ||
break; | ||
case "class": | ||
this.class(stmt); | ||
break; | ||
case "expr": | ||
this.evaluate(stmt.expression); | ||
break; | ||
case "func": | ||
const func = new LoxFunction(stmt, this.#environment, false); | ||
this.#environment.define(stmt.name.lexeme, func); | ||
break; | ||
case "if": | ||
if (isTruthy(this.evaluate(stmt.condition))) { | ||
this.execute(stmt.thenBranch); | ||
} else if (stmt.elseBranch !== null) { | ||
this.execute(stmt.elseBranch); | ||
} | ||
break; | ||
case "print": { | ||
const value = this.evaluate(stmt.expression); | ||
console.log(stringify(value)); | ||
break; | ||
} | ||
case "return": { | ||
const value = stmt.value && this.evaluate(stmt.value); | ||
throw new ReturnCall(value); | ||
} | ||
case "var-stmt": { | ||
let value = null; | ||
if (stmt.initializer) { | ||
value = this.evaluate(stmt.initializer); | ||
} | ||
this.#environment.define(stmt.name.lexeme, value); | ||
break; | ||
} | ||
case "while": | ||
while (isTruthy(this.evaluate(stmt.condition))) { | ||
this.execute(stmt.body); | ||
} | ||
break; | ||
default: | ||
assertUnreachable(stmt); | ||
} | ||
} | ||
@@ -201,26 +271,2 @@ executeBlock(stmts, environment) { | ||
} | ||
expr(stmt) { | ||
this.evaluate(stmt.expression); | ||
} | ||
func(stmt) { | ||
const func = new LoxFunction(stmt, this.#environment, false); | ||
this.#environment.define(stmt.name.lexeme, func); | ||
} | ||
get(expr) { | ||
const obj = this.evaluate(expr.object); | ||
if (obj instanceof LoxInstance) { | ||
return obj.get(expr.name); | ||
} | ||
throw new RuntimeError(expr.name, "Only instances have properties."); | ||
} | ||
grouping(expr) { | ||
return this.evaluate(expr.expr); | ||
} | ||
if(stmt) { | ||
if (isTruthy(this.evaluate(stmt.condition))) { | ||
this.execute(stmt.thenBranch); | ||
} else if (stmt.elseBranch !== null) { | ||
this.execute(stmt.elseBranch); | ||
} | ||
} | ||
interpret(statements) { | ||
@@ -237,47 +283,2 @@ try { | ||
} | ||
literal(expr) { | ||
return expr.value; | ||
} | ||
logical(expr) { | ||
const left = this.evaluate(expr.left); | ||
if (expr.operator.type == "or") { | ||
if (isTruthy(left)) { | ||
return left; | ||
} | ||
} else { | ||
if (!isTruthy(left)) { | ||
return left; | ||
} | ||
} | ||
return this.evaluate(expr.right); | ||
} | ||
print(stmt) { | ||
const value = this.evaluate(stmt.expression); | ||
console.log(stringify(value)); | ||
} | ||
set(expr) { | ||
const obj = this.evaluate(expr.object); | ||
if (!(obj instanceof LoxInstance)) { | ||
throw new RuntimeError(expr.name, "Only instances have fields."); | ||
} | ||
const value = this.evaluate(expr.value); | ||
obj.set(expr.name, value); | ||
return value; | ||
} | ||
unary(expr) { | ||
const right = this.evaluate(expr.right); | ||
switch (expr.operator.type) { | ||
case "-": | ||
checkNumberOrCurrencyOperand(expr.operator, right); | ||
return applyToNumOrCurrency(right, (v) => -v); | ||
case "!": | ||
return !isTruthy(right); | ||
} | ||
throw new Error(`Unknown unary type ${expr.operator.type}`); | ||
} | ||
while(stmt) { | ||
while (isTruthy(this.evaluate(stmt.condition))) { | ||
this.execute(stmt.body); | ||
} | ||
} | ||
} | ||
@@ -284,0 +285,0 @@ class RuntimeError extends Error { |
{ | ||
"name": "gravlax", | ||
"version": "0.11.0", | ||
"version": "0.11.1", | ||
"description": "A Lox interpreter with tasty TypeScript seasoning", | ||
@@ -23,2 +23,3 @@ "repository": { | ||
"scripts": { | ||
"benchmark": "pnpm --silent run repl bench/fib33.lox", | ||
"build": "tsup", | ||
@@ -72,3 +73,3 @@ "coverage": "pnpm test -- --coverage --no-watch", | ||
"markdownlint": "^0.33.0", | ||
"markdownlint-cli": "^0.38.0", | ||
"markdownlint-cli": "^0.39.0", | ||
"npm-package-json-lint": "^7.1.0", | ||
@@ -75,0 +76,0 @@ "npm-package-json-lint-config-default": "^6.0.0", |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
134320
1479