Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

gravlax

Package Overview
Dependencies
Maintainers
1
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

gravlax - npm Package Compare versions

Comparing version 0.9.0 to 0.10.0

lib/lox-value.js

3

lib/ast-printer.js

@@ -5,2 +5,3 @@ import {

} from "./ast.js";
import { stringify } from "./interpreter.js";
const astPrinter = {

@@ -27,3 +28,3 @@ assign: (stmt) => parenthesize("assign", stmt.name.lexeme, stmt.value),

),
literal: (expr) => expr.value === null ? "nil" : String(expr.value),
literal: (expr) => stringify(expr.value),
logical: (expr) => parenthesize(expr.operator.lexeme, expr.left, expr.right),

@@ -30,0 +31,0 @@ print: (stmt) => parenthesize("print", stmt.expression),

@@ -35,4 +35,5 @@ import { RuntimeError } from "./interpreter.js";

const { lexeme } = name;
if (this.#values.has(lexeme)) {
return this.#values.get(lexeme);
const value = this.#values.get(lexeme);
if (value !== void 0) {
return value;
}

@@ -42,3 +43,7 @@ throw new RuntimeError(name, `Undefined variable '${lexeme}'.`);

getAt(distance, name) {
return this.ancestor(distance).#values.get(name);
const value = this.ancestor(distance).#values.get(name);
if (value !== void 0) {
return value;
}
throw new Error(`Resolution pass failed for ${name}`);
}

@@ -45,0 +50,0 @@ }

@@ -8,2 +8,3 @@ import {

import { LoxFunction } from "./lox-function.js";
import { isCurrency } from "./lox-value.js";
import { runtimeError } from "./main.js";

@@ -28,2 +29,19 @@ class ClockFn extends LoxCallable {

}
function applyOperatorToPair(pair, op) {
if (typeof pair.left === "number") {
return op(pair.left, pair.right);
} else {
const value = op(pair.left.value, pair.right.value);
if (typeof value === "number") {
return { currency: pair.left.currency, value };
}
return value;
}
}
function applyToNumOrCurrency(val, fn) {
if (isCurrency(val)) {
return { currency: val.currency, value: fn(val.value) };
}
return fn(val);
}
class Interpreter {

@@ -59,3 +77,2 @@ globals = new Environment();

this.#environment.define(stmt.name.lexeme, value);
return null;
}

@@ -76,41 +93,44 @@ assign(expr) {

const { operator } = expr;
const pair = { left, right };
switch (operator.type) {
case "-":
checkNumberOperand(operator, left);
checkNumberOperand(operator, right);
return left - right;
checkSameNumberOperands(operator, pair);
return applyOperatorToPair(pair, (a, b) => a - b);
case "/":
checkNumberOperand(operator, left);
checkNumberOrCurrencyOperand(operator, left);
checkNumberOperand(operator, right);
return left / right;
return applyToNumOrCurrency(left, (v) => v / right);
case "*":
checkNumberOperand(operator, left);
checkNumberOrCurrencyOperand(operator, left);
checkNumberOperand(operator, right);
return left * right;
return applyToNumOrCurrency(left, (v) => v * right);
case "+":
if (typeof left === "number" && typeof right === "number") {
if (typeof left === "string" && typeof right === "string") {
return left + right;
} else if (typeof left === "string" && typeof right === "string") {
return left + right;
} else {
try {
checkSameNumberOperands(operator, pair);
} catch (e) {
if (e instanceof MixedCurrencyError) {
throw e;
}
throw new RuntimeError(
operator,
`Operands must be two numbers/currencies or two strings.`
);
}
return applyOperatorToPair(pair, (a, b) => a + b);
}
throw new RuntimeError(
operator,
"Operands must be two numbers or two strings."
);
case ">":
checkNumberOperand(operator, left);
checkNumberOperand(operator, right);
return left > right;
checkSameNumberOperands(operator, pair);
return applyOperatorToPair(pair, (a, b) => a > b);
case ">=":
checkNumberOperand(operator, left);
checkNumberOperand(operator, right);
return left >= right;
checkSameNumberOperands(operator, pair);
return applyOperatorToPair(pair, (a, b) => a >= b);
case "<":
checkNumberOperand(operator, left);
checkNumberOperand(operator, right);
return left < right;
checkSameNumberOperands(operator, pair);
return applyOperatorToPair(pair, (a, b) => a < b);
case "<=":
checkNumberOperand(operator, left);
checkNumberOperand(operator, right);
return left <= right;
checkSameNumberOperands(operator, pair);
return applyOperatorToPair(pair, (a, b) => a <= b);
case "==":

@@ -212,7 +232,8 @@ return isEqual(left, right);

case "-":
checkNumberOperand(expr.operator, right);
return -right;
checkNumberOrCurrencyOperand(expr.operator, right);
return applyToNumOrCurrency(right, (v) => -v);
case "!":
return !isTruthy(right);
}
throw new Error(`Unknown unary type ${expr.operator.type}`);
}

@@ -232,2 +253,4 @@ while(stmt) {

}
class MixedCurrencyError extends RuntimeError {
}
function checkNumberOperand(operator, operand) {

@@ -239,2 +262,26 @@ if (typeof operand === "number") {

}
function checkNumberOrCurrencyOperand(operator, operand) {
if (typeof operand === "number" || isCurrency(operand)) {
return;
}
throw new RuntimeError(operator, "Operand must be a number or currency.");
}
function checkSameNumberOperands(operator, pair) {
const { left, right } = pair;
if (typeof left === "number" && typeof right === "number") {
return;
} else if (isCurrency(left) && isCurrency(right)) {
if (left.currency == right.currency) {
return;
}
throw new MixedCurrencyError(
operator,
"Operands must be the same currency."
);
}
throw new RuntimeError(
operator,
"Operands must both be numbers or currencies."
);
}
function isTruthy(val) {

@@ -250,3 +297,3 @@ if (val === null) {

function isEqual(a, b) {
return a === b;
return a === b || isCurrency(a) && isCurrency(b) && a.value === b.value && a.currency === b.currency;
}

@@ -256,5 +303,9 @@ function stringify(val) {

return "nil";
} else if (val === void 0) {
}
if (val === void 0) {
throw new Error(`undefined is not a valid Lox value`);
}
if (isCurrency(val)) {
return `${val.currency}${val.value.toLocaleString()}`;
}
return String(val);

@@ -264,2 +315,3 @@ }

Interpreter,
MixedCurrencyError,
ReturnCall,

@@ -266,0 +318,0 @@ RuntimeError,

@@ -15,2 +15,3 @@ import { LoxCallable } from "./callable.js";

}
// Why, oh why, do I need type annotations here?
call(interpreter, args) {

@@ -17,0 +18,0 @@ const env = new Environment(this.closure);

@@ -26,3 +26,3 @@ import { error } from "./main.js";

}
#addToken(type, literal, isCurrency) {
#addToken(type, literal) {
const lexeme = this.source.slice(this.start, this.current);

@@ -33,4 +33,3 @@ this.tokens.push({

literal,
type,
...isCurrency && { isCurrency }
type
});

@@ -65,3 +64,4 @@ }

#number() {
const isCurrency = this.source[this.start] === "$";
const char = this.source[this.start];
const currency = char === "$" || char === "\u20AC" ? char : null;
while (isDigit(this.#peek()) || // a trailing comma might be part of an argument list.

@@ -77,4 +77,5 @@ this.#peek() === "," && isDigit(this.#peekNext())) {

}
const numText = this.source.slice(this.start, this.current).replace(/[$,]/g, "");
this.#addToken("number", Number(numText), isCurrency);
const numText = this.source.slice(this.start, this.current).replace(/[$€,]/g, "");
const value = Number(numText);
this.#addToken("number", currency ? { currency, value } : value);
}

@@ -134,3 +135,3 @@ #peek() {

default:
if (isDigit(c) || c === "$") {
if (isDigit(c) || c === "$" || c === "\u20AC") {
this.#number();

@@ -137,0 +138,0 @@ } else if (isAlpha(c)) {

@@ -0,3 +1,6 @@

import { isCurrency } from "./lox-value.js";
function tokenToString(token) {
return `'${token.lexeme}': ${token.type}` + (token.literal !== null ? `: ${token.isCurrency ? "$" : ""}${token.literal}` : "");
const { lexeme, literal, type } = token;
const str = isCurrency(literal) ? `${literal.currency}${literal.value}` : String(literal);
return `'${lexeme}': ${type}` + (literal !== null ? `: ${str}` : "");
}

@@ -4,0 +7,0 @@ export {

{
"name": "gravlax",
"version": "0.9.0",
"version": "0.10.0",
"description": "A Lox interpreter with tasty TypeScript seasoning",

@@ -5,0 +5,0 @@ "repository": {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc