Skip to content

Commit

Permalink
Prototyping JavaScript generation from LISP
Browse files Browse the repository at this point in the history
Refs: #3
  • Loading branch information
tshemsedinov committed Dec 6, 2024
1 parent 7df5187 commit 3963531
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 19 deletions.
40 changes: 38 additions & 2 deletions lib/expressions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ class NumberExpression {
interpret() {
return this.value;
}

toExpression() {
return this.value;
}

toJavaScript() {
return `() => ${this.value}`;
}
}

class VariableExpression {
Expand All @@ -23,22 +31,50 @@ class VariableExpression {
}
return context[this.name];
}

toExpression() {
return this.name;
}

toJavaScript() {
return `(${this.name}) => ${this.name}`;
}
}

class OperationExpression {
constructor(operator, operands) {
this.identifiers = new Set();
this.operator = operator;
this.operands = operands;
for (const operand of operands) {
if (operand instanceof VariableExpression) {
this.identifiers.add(operand.name);
} else if (operand instanceof OperationExpression) {
for (const name of operand.identifiers.values()) {
this.identifiers.add(name);
}
}
}
}

interpret(context) {
const toValues = (operand) => operand.interpret(context);
const args = this.operands.map((x) => toValues(x));
const args = this.operands.map((x) => x.interpret(context));
const operator = OPERATORS[this.operator];
if (!operator) throw new Error(`Unknown operator: ${operator}`);
if (this.operator.length > 1) return operator(...args);
return args.reduce(operator);
}

toExpression() {
const list = this.operands.map((x) => x.toExpression());
return '(' + list.join(this.operator) + ')';
}

toJavaScript() {
const parameters = Array.from(this.identifiers);
const header = '(' + parameters.join(', ') + ')';
return header + ' => ' + this.toExpression();
}
}

module.exports = { NumberExpression, VariableExpression, OperationExpression };
50 changes: 34 additions & 16 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"eslint-config-metarhia": "^9.1.1",
"metatests": "^0.9.0",
"prettier": "^3.4.1",
"typescript": "^5.7.2"
"typescript": "^5.7.2",
"metavm": "^1.4.2"
}
}
18 changes: 18 additions & 0 deletions test/translate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use strict';

const assert = require('node:assert');
const test = require('node:test');
const metavm = require('metavm');
const { tokenize, parse } = require('..');

test('Translate LISP to JavaScript', () => {
const program = '(+ 2 (* x 5) (- y 2))';
const tokens = tokenize(program);
const src = parse(tokens).toJavaScript();
const ms = metavm.createScript('Function', src);
const f = ms.exports;
assert.strictEqual(f.toString(), '(x, y) => (2+(x*5)+(y-2))');
const result = f(3, 7);
const expected = 22;
assert.strictEqual(result, expected);
});

0 comments on commit 3963531

Please sign in to comment.