Created
August 20, 2022 18:38
-
-
Save aungmyatmoethegreat/1c5db2c86573c7cdcaa37c518ca668f7 to your computer and use it in GitHub Desktop.
Wuttyi Lang LL parsing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export default class Environment { | |
// create a variable environment (table of environment) | |
constructor(record = {}) { | |
this.record = record; | |
} | |
// set the variable to the env with the given name and value | |
define(name, value) { | |
this.record[name] = value; | |
return value; | |
} | |
// get the variable value from record | |
lookup(name) { | |
if (!this.record.hasOwnProperty(name)) { | |
throw new ReferenceError(`ReferenceError: ${name} is not defined`) | |
} | |
return this.record[name]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import assert from 'assert'; | |
import Environment from "./Environment.js"; | |
/* It evaluates a JavaScript expression and returns the result */ | |
class Wuttyi { | |
// Create the Wuttyi instance with the global environment | |
constructor(env = new Environment()) { | |
this.global = env; | |
} | |
// -------------------- Self evaluation ------------- | |
// Evaluate an expression in the given environment | |
eval(exp, env = this.global) { | |
if (isNumber(exp)) { | |
return exp; | |
} | |
if (isString(exp)) { | |
return exp.slice(1, -1) | |
} | |
// -------------- Math Operations --------------- | |
if (exp[0] === '+') { | |
return this.eval(exp[1]) + this.eval(exp[2]); | |
} | |
if (exp[0] === '-') { | |
return this.eval(exp[1]) - this.eval(exp[2]); | |
} | |
if (exp[0] === '*') { | |
return this.eval(exp[1]) * this.eval(exp[2]); | |
} | |
if (exp[0] === '/') { | |
return this.eval(exp[1]) / this.eval(exp[2]); | |
} | |
if (exp[0] === '%') { | |
return this.eval(exp[1]) % this.eval(exp[2]); | |
} | |
// ----------------- Variable declaration --------------- | |
if (exp[0] === 'var') { | |
const [_, name, value] = exp; | |
return env.define(name, this.eval(value)); | |
} | |
// ---------------- Variable Access --------------------------- | |
if (isVariableName(exp[0])) { | |
return env.lookup(exp); | |
} | |
throw `Unimplemented: ${exp.stringify()}`; | |
} | |
} | |
function isNumber(exp) { | |
return typeof exp === 'number'; | |
} | |
function isString(exp) { | |
return typeof exp === 'string' && exp.startsWith('"') && exp.endsWith('"'); | |
} | |
function isVariableName(exp) { | |
return typeof exp === 'string' && /^[a-zA-Z][a-zA-Z0-9_]*$/.test(exp); | |
} | |
// -------------------- Tests ---------------- | |
// set the predefined variable | |
const wuttyi = new Wuttyi(new Environment({ | |
true: true, | |
false: false, | |
null: null, | |
version: '1.0.0', | |
})); | |
// ----------- Math Tests ---------------------- | |
// exp ::= number | string | [+ number, number] | |
assert.strictEqual(wuttyi.eval(1), 1); | |
assert.strictEqual(wuttyi.eval('"hello"'), 'hello'); | |
assert.strictEqual(wuttyi.eval(['+', 1, 2]), 3); | |
assert.strictEqual(wuttyi.eval(['+', ['+', 6, 2], 2]), 10); | |
assert.strictEqual(wuttyi.eval(['+', ['*', 6, 2], 2]), 14); | |
assert.strictEqual(wuttyi.eval(['*', ['+', 2, 3], 5]), 25); | |
// ------------- Variable ----------------------- | |
assert.strictEqual(wuttyi.eval(['var', 'x', 10]), 10); | |
assert.strictEqual(wuttyi.eval('x'), 10); | |
// var isUser = true; | |
assert.strictEqual(wuttyi.eval(['var', 'isUser', 'true']), true); | |
assert.strictEqual(wuttyi.eval('isUser'), true); | |
assert.strictEqual(wuttyi.eval(['var', 'y', 100]), 100); | |
assert.strictEqual(wuttyi.eval('y'), 100); | |
console.log('Asserting was passed') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment