aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--lib/binops.js33
-rw-r--r--lib/doml.js220
-rw-r--r--lib/readability.js38
-rw-r--r--lib/run.js20
-rw-r--r--lib/statements.js74
-rw-r--r--lib/types.js22
-rw-r--r--lib/util.js13
-rw-r--r--prog/euclideanAlgorithm.html10
-rw-r--r--prog/simpleWhileLoop.html10
10 files changed, 229 insertions, 213 deletions
diff --git a/README.md b/README.md
index f3d15e5..2e0534b 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ After cloning the repository, open up any of the files found in the `prog` direc
## About the language
-At this point, it is extremely simple and undocumented. All statements are executed in a global context, and are implemented in `./lib/statements.js`. Binary operators are implemented in `./lib/binops.js`. A rudimentary type system currently consisting of `string`, `number`, and `boolean` are mapped to native JavaScript types for evaluation.
+At this point, it is extremely simple and undocumented. All statements are executed in a global context. A rudimentary type system currently consisting of `string`, `number`, and `boolean` are mapped to native JavaScript types for evaluation.
## Online Example
diff --git a/lib/binops.js b/lib/binops.js
deleted file mode 100644
index a709097..0000000
--- a/lib/binops.js
+++ /dev/null
@@ -1,33 +0,0 @@
-var binaryOperators = {
- '!=': function(a, b) {
- return a != b;
- },
-
- '<': function(a, b) {
- return a < b;
- },
-
- '>': function(a, b) {
- return a > b;
- },
-
- '-': function(a, b) {
- return a - b;
- },
-
- '+': function(a, b) {
- return a + b;
- },
-
- '==': function(a, b) {
- return a == b;
- },
-
- '<=': function(a, b) {
- return a <= b;
- },
-
- '>=': function(a, b) {
- return a >= b;
- }
-};
diff --git a/lib/doml.js b/lib/doml.js
new file mode 100644
index 0000000..332a17e
--- /dev/null
+++ b/lib/doml.js
@@ -0,0 +1,220 @@
+(function() {
+ var listFromHtmlCollection = function(collection) {
+ var lst = [];
+ for (var idx = 0; idx < collection.length; idx++) {
+ lst.push(collection[idx]);
+ }
+ return lst;
+ };
+
+ var DomlEvaluator = function() {
+ var me = this;
+
+ // members of the Types object are functions that take a string and return
+ // an appropriate value as a native type
+ me.Types = {
+ 'number': function(val) {
+ if (val.indexOf('.')) {
+ return parseFloat(val);
+ } else {
+ return parseInt(val, 10);
+ }
+ },
+
+ 'string': function(val) {
+ return val;
+ },
+
+ 'boolean': function(val) {
+ if (val === 'true') {
+ return true;
+ }
+ if (val === 'false') {
+ return false;
+ }
+ throw new Error('Invalid boolean value ' + val);
+ }
+ };
+
+ // members of the BinaryOperators object are functions that take two arguments
+ // and return the result of that operation
+ me.BinaryOperators = {
+ '!=': function(a, b) {
+ return a != b;
+ },
+
+ '<': function(a, b) {
+ return a < b;
+ },
+
+ '>': function(a, b) {
+ return a > b;
+ },
+
+ '-': function(a, b) {
+ return a - b;
+ },
+
+ '+': function(a, b) {
+ return a + b;
+ },
+
+ '==': function(a, b) {
+ return a == b;
+ },
+
+ '<=': function(a, b) {
+ return a <= b;
+ },
+
+ '>=': function(a, b) {
+ return a >= b;
+ }
+ };
+
+ // members of the Statements object are functions that take a dataset, children, and context
+ // and return the result of the statement
+ me.Statements = {
+ 'statement-sequence': function(dataset, children, context) {
+ var retval = null;
+ children.forEach(function(child) {
+ retval = me.evaluate(child, context);
+ });
+ return retval;
+ },
+
+ 'while': function(dataset, children, context) {
+ var condition = children[0];
+ var body = children[1];
+ while (me.evaluate(condition, context)) {
+ me.evaluate(body, context);
+ }
+ },
+
+ 'compare': function(dataset, children, context) {
+ var operator = me.BinaryOperators[dataset.op];
+ var lhs = me.evaluate(children[0], context);
+ var rhs = me.evaluate(children[1], context);
+ var result = operator(lhs, rhs);
+ return result;
+ },
+
+ 'variable': function(dataset, children, context) {
+ return context[dataset.name];
+ },
+
+ 'constant': function(dataset, children, context) {
+ return me.Types[dataset.type](dataset.val);
+ },
+
+ 'branch': function(dataset, children, context) {
+ if (me.evaluate(children[0], context)) {
+ return me.evaluate(children[1], context);
+ } else if (children.length > 2) {
+ return me.evaluate(children[2], context);
+ }
+ },
+
+ 'assign': function(dataset, children, context) {
+ context[dataset.name] = me.evaluate(children[0], context);
+ return context[dataset.name];
+ },
+
+ 'bin-op': function(dataset, children, context) {
+ var operator = me.BinaryOperators[dataset.op];
+ var lhs = me.evaluate(children[0], context);
+ var rhs = me.evaluate(children[1], context);
+ return operator(lhs, rhs);
+ },
+
+ 'return': function(dataset, children, context) {
+ return me.evaluate(children[0], context);
+ },
+
+ 'print': function(dataset, children, context) {
+ var args = children.map(function(child) {
+ return me.evaluate(child, context);
+ });
+ console.log.apply(this, args);
+ }
+ };
+
+ // members of the Readability object are functions which take an element
+ // and return an array of additional text nodes which should be added
+ // to enhance readability
+ me.Decorators = {
+ 'assign': function(e) {
+ return [ e.dataset.name ];
+ },
+
+ 'variable': function(e) {
+ return [ e.dataset.name ];
+ },
+
+ 'constant': function(e) {
+ return [ e.dataset.type + '(' + e.dataset.val + ')' ];
+ },
+
+ 'compare': function(e) {
+ return [ e.dataset.op ];
+ },
+
+ 'bin-op': function(e) {
+ return [ e.dataset.op ];
+ }
+ };
+
+ me.evaluate = function(node, context) {
+ if (typeof context === 'undefined') {
+ context = {};
+ }
+ var value = me.Statements[node.className](node.dataset, listFromHtmlCollection(node.children), context);
+ return value;
+ };
+
+ me.appendText = function(node, text) {
+ var n = document.createElement('var');
+ n.innerText = text;
+ node.appendChild(n);
+ };
+
+ me.decorate = function(root) {
+ var classes = Object.keys(me.Decorators);
+ for (var idx = 0; idx < classes.length; idx++) {
+ var klass = classes[idx];
+ var els = listFromHtmlCollection(root.getElementsByClassName(klass));
+ els.forEach(function(el) {
+ me.Decorators[klass](el).forEach(function(text) {
+ me.appendText(el, text);
+ });
+ });
+ }
+ };
+
+ me.run = function(root) {
+ var t0 = performance.now();
+ me.evaluate(root);
+ var t1 = performance.now();
+ me.decorate(root);
+ console.debug('Evaluated DOML program in ' + (t1 - t0) + 'ms');
+ }
+ };
+
+ var Doml = {
+ Evaluator: DomlEvaluator,
+ runOnLoad: function(root) {
+ document.addEventListener('DOMContentLoaded', function() {
+ (new DomlEvaluator()).run(document.body.children[0]);
+ });
+ }
+ };
+
+ if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
+ module.exports = Doml;
+ } else if (typeof window !== 'undefined') {
+ window.Doml = Doml;
+ } else {
+ throw new Error('Unable to register Doml');
+ }
+})();
+
diff --git a/lib/readability.js b/lib/readability.js
deleted file mode 100644
index 06eb4ad..0000000
--- a/lib/readability.js
+++ /dev/null
@@ -1,38 +0,0 @@
-var appendText = function(node, text) {
- var n = document.createElement('var');
- n.innerText = text;
- node.appendChild(n);
-};
-
-var readability = {
- 'assign': function(e) {
- return e.dataset.name;
- },
-
- 'variable': function(e) {
- return e.dataset.name;
- },
-
- 'constant': function(e) {
- return e.dataset.type + '(' + e.dataset.val + ')';
- },
-
- 'compare': function(e) {
- return e.dataset.op;
- },
-
- 'bin-op': function(e) {
- return e.dataset.op;
- }
-};
-
-var makeReadable = function(root) {
- var classes = Object.keys(readability);
- for (var idx = 0; idx < classes.length; idx++) {
- var klass = classes[idx];
- var els = root.getElementsByClassName(klass);
- els.forEach(function(el) {
- appendText(el, readability[klass](el));
- });
- }
-};
diff --git a/lib/run.js b/lib/run.js
deleted file mode 100644
index 92441a2..0000000
--- a/lib/run.js
+++ /dev/null
@@ -1,20 +0,0 @@
-(function() {
- var evaluate = function(node, context) {
- if (typeof context === 'undefined') {
- context = {};
- }
- return statementEvaluators[node.className](node.dataset, node.children, context);
- };
-
- var statementEvaluators = getStatementEvaluators(evaluate);
-
- document.addEventListener('DOMContentLoaded', function() {
- var t0 = performance.now();
- evaluate(document.body.children[0]);
- var t1 = performance.now();
- makeReadable(document.body);
- var t2 = performance.now();
- console.debug('Evaluated in ' + (t1 - t0) + 'ms');
- console.debug('Rendered in ' + (t2 - t1) + 'ms');
- });
-})();
diff --git a/lib/statements.js b/lib/statements.js
deleted file mode 100644
index b59c08f..0000000
--- a/lib/statements.js
+++ /dev/null
@@ -1,74 +0,0 @@
-var getStatementEvaluators = function(evaluate) {
- return {
- 'statement-sequence': function(dataset, children, context) {
- var retval = null;
- children.forEach(function(child) {
- retval = evaluate(child, context);
- });
- return retval;
- },
-
- 'while': function(dataset, children, context) {
- var condition = children[0];
- var body = children[1];
- while (evaluate(condition, context)) {
- evaluate(body, context);
- }
- },
-
- 'compare': function(dataset, children, context) {
- var operator = binaryOperators[dataset.op];
- var lhs = evaluate(children[0], context);
- var rhs = evaluate(children[1], context);
- var result = operator(lhs, rhs);
- return result;
- },
-
- 'variable': function(dataset, children, context) {
- return context[dataset.name];
- },
-
- 'constant': function(dataset, children, context) {
- return stringToType(dataset.val, dataset.type);
- },
-
- 'branch': function(dataset, children, context) {
- var condition = children[0];
- var ifBody = children[1];
-
- // else is optional
- if (children.length > 2) {
- var elseBody = children[2];
- }
-
- if (evaluate(condition, context)) {
- return evaluate(ifBody, context);
- } else if (elseBody) {
- return evaluate(elseBody, context);
- }
- },
-
- 'assign': function(dataset, children, context) {
- context[dataset.name] = evaluate(children[0], context);
- return context[dataset.name];
- },
-
- 'bin-op': function(dataset, children, context) {
- var operator = binaryOperators[dataset.op];
- var lhs = evaluate(children[0], context);
- var rhs = evaluate(children[1], context);
- return operator(lhs, rhs);
- },
-
- 'return': function(dataset, children, context) {
- return evaluate(children[0], context);
- },
-
- 'print': function(dataset, children, context) {
- var args = children.map(function(child) {
- return evaluate(child, context);
- });
- console.log.apply(this, args);
- }
- };
-};
diff --git a/lib/types.js b/lib/types.js
deleted file mode 100644
index 38e2b60..0000000
--- a/lib/types.js
+++ /dev/null
@@ -1,22 +0,0 @@
-var stringToType = function(str, type) {
- switch (type) {
- case 'number':
- if (str.indexOf('.')) {
- return parseFloat(str);
- } else {
- return parseInt(str, 10);
- }
- case 'string':
- return str;
- case 'boolean':
- if (str === 'true') {
- return true;
- } else if (str === 'false') {
- return false;
- } else {
- throw new Error('Invalid boolean value ' + str);
- }
- default:
- throw new Error('type', type, 'is not defined');
- }
-};
diff --git a/lib/util.js b/lib/util.js
deleted file mode 100644
index 3c6857c..0000000
--- a/lib/util.js
+++ /dev/null
@@ -1,13 +0,0 @@
-HTMLCollection.prototype.map = function(fn) {
- var results = [];
- for (var idx = 0; idx < this.length; idx++) {
- results.push(fn(this.item(idx)));
- }
- return results;
-};
-
-HTMLCollection.prototype.forEach = function(fn) {
- for (var idx = 0; idx < this.length; idx++) {
- fn(this.item(idx));
- }
-};
diff --git a/prog/euclideanAlgorithm.html b/prog/euclideanAlgorithm.html
index 338ca46..79f9b12 100644
--- a/prog/euclideanAlgorithm.html
+++ b/prog/euclideanAlgorithm.html
@@ -1,12 +1,10 @@
<!doctype html>
<html>
<head>
- <script type="text/javascript" src="../lib/util.js"></script>
- <script type="text/javascript" src="../lib/types.js"></script>
- <script type="text/javascript" src="../lib/binops.js"></script>
- <script type="text/javascript" src="../lib/statements.js"></script>
- <script type="text/javascript" src="../lib/readability.js"></script>
- <script type="text/javascript" src="../lib/run.js"></script>
+ <script type="text/javascript" src="../lib/doml.js"></script>
+ <script>
+ Doml.runOnLoad();
+ </script>
<link rel="stylesheet" href="../lib/style.css">
</head>
<body>
diff --git a/prog/simpleWhileLoop.html b/prog/simpleWhileLoop.html
index f37511f..67bcaed 100644
--- a/prog/simpleWhileLoop.html
+++ b/prog/simpleWhileLoop.html
@@ -1,12 +1,10 @@
<!doctype html>
<html>
<head>
- <script type="text/javascript" src="../lib/util.js"></script>
- <script type="text/javascript" src="../lib/types.js"></script>
- <script type="text/javascript" src="../lib/binops.js"></script>
- <script type="text/javascript" src="../lib/statements.js"></script>
- <script type="text/javascript" src="../lib/readability.js"></script>
- <script type="text/javascript" src="../lib/run.js"></script>
+ <script type="text/javascript" src="../lib/doml.js"></script>
+ <script>
+ Doml.runOnLoad();
+ </script>
<link rel="stylesheet" href="../lib/style.css">
</head>
<body>