eggtended-js
Version:
A extended version of the Egg programming language from the Eloquent Javascript book.
364 lines (291 loc) • 17 kB
HTML
<html>
<head>
<meta charset="utf-8">
<base data-ice="baseUrl" href="../../../">
<title data-ice="title">lib/interp/registry.js | eggtended-js</title>
<link type="text/css" rel="stylesheet" href="css/style.css">
<link type="text/css" rel="stylesheet" href="css/prettify-tomorrow.css">
<script src="script/prettify/prettify.js"></script>
<script src="script/manual.js"></script>
<meta name="description" content="An extended version of the Egg programming language"><meta property="og:type" content="website"><meta property="og:url" content="http://my-library.org"><meta property="og:site_name" content="eggtended-js"><meta property="og:title" content="eggtended-js"><meta property="og:image" content="https://i.imgur.com/9N4qe98.png"><meta property="og:description" content="An extended version of the Egg programming language"><meta property="og:author" content="https://github.com/Dibad"><meta property="twitter:card" content="summary"><meta property="twitter:title" content="eggtended-js"><meta property="twitter:description" content="An extended version of the Egg programming language"><meta property="twitter:image" content="https://i.imgur.com/9N4qe98.png"></head>
<body class="layout-container" data-ice="rootContainer">
<header>
<a href="./">Home</a>
<a href="identifiers.html">Reference</a>
<a href="source.html">Source</a>
<a href="test.html" data-ice="testLink">Test</a>
<div class="search-box">
<span>
<img src="./image/search.png">
<span class="search-input-edge"></span><input class="search-input"><span class="search-input-edge"></span>
</span>
<ul class="search-result"></ul>
</div>
<a style="position:relative; top:3px;" href="https://github.com/Dibad/eggtended-js"><img width="20px" src="./image/github.png"></a></header>
<nav class="navigation" data-ice="nav"><div>
<ul>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-checkIterable">checkIterable</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-chunk">chunk</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getValidIndex">getValidIndex</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-ins">ins</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#interp">interp</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/interp/ast.js~Apply.html">Apply</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/interp/ast.js~Regex.html">Regex</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/interp/ast.js~Value.html">Value</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/interp/ast.js~Word.html">Word</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/interp/eggvm.js~Eggvm.html">Eggvm</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/interp/symboltable.js~SymbolTable.html">SymbolTable</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-SpecialForms">SpecialForms</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-TopEnv">TopEnv</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#parser">parser</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/parser/lexer.js~Lexer.html">Lexer</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/parser/parse.js~Parser.html">Parser</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/parser/tokenRegex.js~TokenRegex.html">TokenRegex</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-json2AST">json2AST</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-COMMA">COMMA</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-LP">LP</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-NEWLINE">NEWLINE</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-NUMBER">NUMBER</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-REGEX">REGEX</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RP">RP</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-STRING">STRING</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-WHITES">WHITES</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-WORD">WORD</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#repl">repl</a><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-eggCompleter">eggCompleter</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getPromptLine">getPromptLine</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-repl">repl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-BLUE">BLUE</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-DEFAULT">DEFAULT</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-GREEN">GREEN</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RED">RED</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-YELLOW">YELLOW</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-eggClear">eggClear</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-eggExit">eggExit</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-eggHelp">eggHelp</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-eggInfo">eggInfo</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-eggRun">eggRun</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-eggVersion">eggVersion</a></span></span></li>
</ul>
</div>
</nav>
<div class="content" data-ice="content"><h1 data-ice="title">lib/interp/registry.js</h1>
<pre class="source-code line-number raw-source-code"><code class="prettyprint linenums" data-ice="content">const xRegExp = require("xregexp");
const utils = require("../utils.js");
const { SymbolTable } = require("./symboltable.js");
// specialForms and topEnv maps
const SpecialForms = Object.create(null);
const TopEnv = Object.create(null);
SpecialForms["if"] = (args, env) => {
if (args.length !== 3) {
throw new SyntaxError("Bad number of args passed to if");
}
if (args[0].evaluate(env) === true) {
return args[1].evaluate(env);
} else {
return args[2].evaluate(env);
}
};
SpecialForms["while"] = (args, env) => {
if (args.length !== 2) {
throw new SyntaxError("Bad number of args passed to while");
}
while (args[0].evaluate(env) === true) {
args[1].evaluate(env);
}
// Egg has no undefined so we return false when there's no meaningful result
return false;
};
SpecialForms["for"] = (args, env) => {
if (args.length !== 4) {
throw new SyntaxError("Bad number of args passed to for");
}
const forEnv = Object.create(env);
forEnv["__symbol__"] = new SymbolTable();
// Variable
args[0].evaluate(forEnv);
// Condition
while (args[1].evaluate(forEnv) === true) {
// Body
args[3].evaluate(forEnv);
// Increment
args[2].evaluate(forEnv);
}
return false;
};
SpecialForms["foreach"] = (args, env) => {
if (args.length !== 3) {
throw new SyntaxError("Bad number of args passed to foreach");
}
if (args[0].type !== "word") {
throw new SyntaxError("The first argument to foreach must be a valid word");
}
const localEnv = Object.create(env);
localEnv["__symbol__"] = new SymbolTable();
const iterable = args[1].evaluate(localEnv);
for (const val of iterable) {
localEnv[args[0].name] = val;
args[2].evaluate(localEnv);
}
return false;
};
SpecialForms["do"] = (args, env) => {
let value = false;
args.forEach(arg => {
value = arg.evaluate(env);
});
return value;
};
SpecialForms["def"] = SpecialForms["define"] = SpecialForms[":="] = (args, env) => {
if (args.length !== 2) {
throw new SyntaxError("Bad use of define");
}
// Value to assign to the variable
let value = args[1].evaluate(env);
// Variable name
let valName = args[0].name;
env[valName] = value;
return value;
};
SpecialForms["fun"] = SpecialForms["->"] = (args, env) => {
if (!args.length) {
throw new SyntaxError("Functions need a body.");
}
function name(expr) {
if (expr.type !== "word") {
throw new SyntaxError("Arg names must be words");
}
return expr.name;
}
let argNames = args.slice(0, args.length - 1).map(name);
let body = args[args.length - 1];
return function() {
if (arguments.length !== argNames.length) {
throw new TypeError("Wrong number of arguments");
}
const localEnv = Object.create(env);
localEnv["__symbol__"] = new SymbolTable();
for (let i = 0; i < arguments.length; i++) {
localEnv[argNames[i]] = arguments[i];
}
return body.evaluate(localEnv);
};
};
SpecialForms["set"] = SpecialForms["="] = (args, env) => {
if (args[0].type !== "word") {
throw new SyntaxError("Bad use of set");
}
let valName = args[0].name;
let indices = args.slice(1, -1).map(arg => arg.evaluate(env));
let value = args[args.length - 1].evaluate(env);
for (let scope = env; scope; scope = Object.getPrototypeOf(scope)) {
if (scope["__symbol__"].checkAttribute("const", valName)) {
throw new ReferenceError(`Trying to change 'const' variable ${args[0].name}`);
}
// TODO: Reduce code duplication
if ("this" in scope) {
// TODO: use hasOwnProperty ?
if (Object.prototype.hasOwnProperty.call(scope["this"], valName)) {
if (indices.length === 0) {
scope["this"][valName] = value;
} else {
scope["this"][valName].setelem(value, ...indices);
}
return value;
}
}
if (Object.prototype.hasOwnProperty.call(scope, valName)) {
if (indices.length === 0) {
scope[valName] = value;
} else {
scope[valName].setelem(value, ...indices);
}
return value;
}
}
throw new ReferenceError(`Tried setting an undefined variable: ${valName}`);
};
SpecialForms["object"] = (args, env) => {
// Create a new object and a new scope
const object = {};
const objectEnv = Object.create(env);
objectEnv["__symbol__"] = new SymbolTable();
// Add the variable 'this' as a reference to the current object
objectEnv["this"] = object;
// Evaluate the arguments and add the methods/properties to the object
const evArgs = args.map(arg => arg.evaluate(objectEnv));
for (const pair of utils.chunk(evArgs, 2)) {
const name = pair[0];
const value = pair[1];
object[name] = value;
}
return object;
};
// TODO: Continue implementing class?
//
// SpecialForms['class'] = (args, env) => {
// // const evArgs = args.map((arg) => evaluate(arg, env));
//
// const newClass = function(x, y) {
// this.x = x;
// this.y = y;
// }
//
// return newClass;
// }
["+", "-", "*", "/", "==", "!=", "<", ">", ">=", "<=", "&&", "||"].forEach(op => {
TopEnv[op] = new Function("a, b", `return a ${op} b;`);
});
TopEnv["true"] = true;
TopEnv["false"] = false;
TopEnv["null"] = null;
TopEnv["print"] = value => {
console.log(value);
return value;
};
TopEnv["arr"] = TopEnv["array"] = (...args) => {
return args;
};
TopEnv["map"] = TopEnv["dict"] = (...args) => {
return new Map(utils.chunk(args, 2));
};
TopEnv["<-"] = TopEnv["[]"] = TopEnv["element"] = (object, ...indices) => {
return object.sub(...indices);
};
TopEnv["length"] = array => {
return array.length;
};
TopEnv["RegExp"] = (method, ...args) => {
return xRegExp[method](...args);
};
TopEnv["child"] = parent => {
return Object.create(parent);
};
TopEnv["__symbol__"] = new SymbolTable();
// WIP: Continue implementing class?
// TopEnv['new'] = (...args) => {
// const className = args[0];
//
// // TODO: Check for more exceptions
// if(typeof className !== "function") {
// throw new SyntaxError(`${className} must be a class with a constructor.`)
// }
//
// return new className(...args.slice(1));
//
module.exports = {
SpecialForms,
TopEnv
};
</code></pre>
</div>
<footer class="footer">
Generated by <a href="https://esdoc.org">ESDoc<span data-ice="esdocVersion">(1.1.0)</span><img src="./image/esdoc-logo-mini-black.png"></a>
</footer>
<script src="script/search_index.js"></script>
<script src="script/search.js"></script>
<script src="script/pretty-print.js"></script>
<script src="script/inherited-summary.js"></script>
<script src="script/test-summary.js"></script>
<script src="script/inner-link.js"></script>
<script src="script/patch-for-local.js"></script>
</body>
</html>