Cleaned up JavaScript processing

I'm slowly trying to make the JavaScript processing and the WikiText
processing use the same conventions
This commit is contained in:
Jeremy Ruston 2012-01-04 18:31:19 +00:00
parent 5eeb45cd79
commit 3ff1d9a76c
9 changed files with 196 additions and 175 deletions

View File

@ -14,7 +14,7 @@ var WikiStore = require("./WikiStore.js").WikiStore,
tiddlerInput = require("./TiddlerInput.js"),
tiddlerOutput = require("./TiddlerOutput.js"),
WikiTextProcessor = require("./WikiTextProcessor.js").WikiTextProcessor,
Sandbox = require("./Sandbox.js").Sandbox,
JavaScriptParser = require("./JavaScriptParser.js").JavaScriptParser,
Navigators = require("./Navigators.js").Navigators,
StoryNavigator = require("./StoryNavigator.js").StoryNavigator;
@ -73,11 +73,11 @@ var App = function() {
this.store.addTiddler(new Tiddler(tiddlers[t]));
}
}
// Set up the sandbox for JavaScript parsing
// Set up the JavaScript parser
if(this.isBrowser) {
this.store.sandbox = new Sandbox(this.store.getTiddlerText("javascript.pegjs"));
this.store.jsParser = new JavaScriptParser(this.store.getTiddlerText("javascript.pegjs"));
} else {
this.store.sandbox = new Sandbox(require("fs").readFileSync("parsers/javascript.pegjs","utf8"));
this.store.jsParser = new JavaScriptParser(require("fs").readFileSync("parsers/javascript.pegjs","utf8"));
}
// Hack to install standard macros
this.store.installMacros();

135
js/JavaScriptParseTree.js Normal file
View File

@ -0,0 +1,135 @@
/*\
title: js/JavaScriptParseTree.js
JavaScript parse tree
\*/
(function(){
/*jslint node: true */
"use strict";
var utils = require("./Utils.js");
// Create a new JavaScript tree object
var JavaScriptParseTree = function(tree,processor) {
this.tree = tree;
this.processor = processor;
};
// Render the entire JavaScript tree object to JavaScript source code
JavaScriptParseTree.prototype.render = function() {
this.output = [];
this.renderSubTree(this.tree);
return this.output.join("");
};
JavaScriptParseTree.prototype.renderSubTree = function(tree) {
for(var t=0; t<tree.length; t++) {
if(t) {
this.output.push(";\n");
}
this.renderNode(tree[t]);
}
};
// Compile a javascript tree into an array of string fragments
JavaScriptParseTree.prototype.renderNode = function(node) {
var p;
switch(node.type) {
case "StringLiteral":
this.output.push(utils.stringify(node.value));
break;
case "StringLiterals":
this.output.push(utils.stringify(node.value.join("")));
break;
case "FunctionCall":
this.output.push("(");
this.renderNode(node.name);
this.output.push(")(");
for(p=0; p<node["arguments"].length; p++) {
if(p) {
this.output.push(",");
}
this.renderNode(node["arguments"][p]);
}
this.output.push(")");
break;
case "PropertyAccess":
this.renderNode(node.base);
if(typeof node.name === "string") {
this.output.push("." + node.name);
} else {
this.output.push("[");
this.renderNode(node.name);
this.output.push("]");
}
break;
case "ArrayLiteral":
this.output.push("[");
for(p=0; p<node.elements.length; p++) {
if(p) {
this.output.push(",");
}
this.renderNode(node.elements[p]);
}
this.output.push("]");
break;
case "Variable":
this.output.push(node.name);
break;
case "ObjectLiteral":
this.output.push("{");
for(p=0; p<node.properties.length; p++) {
if(p) {
this.output.push(",");
}
this.renderNode(node.properties[p]);
}
this.output.push("}");
break;
case "PropertyAssignment":
this.output.push(node.name);
this.output.push(":");
this.renderNode(node.value);
break;
case "BinaryExpression":
this.output.push("(");
this.renderNode(node.left);
this.output.push(")");
this.output.push(node.operator);
this.output.push("(");
this.renderNode(node.right);
this.output.push(")");
break;
case "NumericLiteral":
this.output.push(node.value);
break;
case "Function":
this.output.push("(function ");
if(node.name !== null) {
this.output.push(node.name);
}
this.output.push("(");
this.output.push(node.params.join(","));
this.output.push("){");
this.renderSubTree(node.elements);
this.output.push("})");
break;
case "ReturnStatement":
this.output.push("return ");
this.renderNode(node.value);
break;
case "This":
this.output.push("this");
break;
default:
console.log(node);
throw "Unknown JavaScript node type: " + node.type;
//break;
}
};
exports.JavaScriptParseTree = JavaScriptParseTree;
})();

29
js/JavaScriptParser.js Normal file
View File

@ -0,0 +1,29 @@
/*\
title: js/JavaScriptParser.js
JavaScript processing
\*/
(function(){
/*jslint node: true */
"use strict";
var JavaScriptParseTree = require("./JavaScriptParseTree.js").JavaScriptParseTree,
pegjs = require("pegjs");
var JavaScriptParser = function(parserText) {
this.parser = pegjs.buildParser(parserText);
};
JavaScriptParser.prototype.parse = function(code) {
return new JavaScriptParseTree(this.parser.parse(code),this);
};
JavaScriptParser.prototype.createTree = function(tree) {
return new JavaScriptParseTree(tree,this);
};
exports.JavaScriptParser = JavaScriptParser;
})();

View File

@ -1,24 +0,0 @@
/*\
title: js/Sandbox.js
Execute a fragment of JavaScript in a sandbox
\*/
(function(){
/*jslint evil: true, node: true */
"use strict";
var pegjs = require("pegjs");
var Sandbox = function(parserText) {
this.parser = pegjs.buildParser(parserText);
};
Sandbox.prototype.parse = function(code) {
return this.parser.parse(code);
};
exports.Sandbox = Sandbox;
})();

View File

@ -307,8 +307,8 @@ WikiStore.prototype.installMacros = function() {
text: {byPos: 0, type: "text", optional: false}
},
code: {
"text/html": this.sandbox.parse("return utils.htmlEncode(params.text);"),
"text/plain": this.sandbox.parse("return params.text;")
"text/html": this.jsParser.parse("return utils.htmlEncode(params.text);"),
"text/plain": this.jsParser.parse("return params.text;")
}
},
view: {
@ -318,8 +318,8 @@ WikiStore.prototype.installMacros = function() {
template: {byPos: 2, type: "text", optional: true}
},
code: {
"text/html": this.sandbox.parse("return store.getFormattedTiddlerField(tiddler.fields.title,params.field,params.format,params.template);"),
"text/plain": this.sandbox.parse("return store.getFormattedTiddlerField(tiddler.fields.title,params.field,params.format,params.template);")
"text/html": this.jsParser.parse("return store.getFormattedTiddlerField(tiddler.fields.title,params.field,params.format,params.template);"),
"text/plain": this.jsParser.parse("return store.getFormattedTiddlerField(tiddler.fields.title,params.field,params.format,params.template);")
}
},
list: {
@ -329,26 +329,26 @@ WikiStore.prototype.installMacros = function() {
emptyMessage: {byName: true, type: "text", optional: true}
},
code: {
"text/html": this.sandbox.parse("return store.listTiddlers(params.type,params.template,params.emptyMessage);"),
"text/plain": this.sandbox.parse("return store.listTiddlers(params.type,params.template,params.emptyMessage);")
"text/html": this.jsParser.parse("return store.listTiddlers(params.type,params.template,params.emptyMessage);"),
"text/plain": this.jsParser.parse("return store.listTiddlers(params.type,params.template,params.emptyMessage);")
}
},
version: {
params: {
},
code: {
"text/html": this.sandbox.parse("return '5.0.0';"),
"text/plain": this.sandbox.parse("return '5.0.0';")
"text/html": this.jsParser.parse("return '5.0.0';"),
"text/plain": this.jsParser.parse("return '5.0.0';")
}
},
tiddler: {
params: {
target: {byName: "default", type: "tiddler", optional: false},
with: {byName: true, type: "text", optional: true, cascade: true}
"with": {byName: true, type: "text", optional: true, cascade: true}
},
code: {
"text/html": this.sandbox.parse("return store.renderTiddler('text/html',params.target);"),
"text/plain": this.sandbox.parse("return store.renderTiddler('text/plain',params.target);")
"text/html": this.jsParser.parse("return store.renderTiddler('text/html',params.target);"),
"text/plain": this.jsParser.parse("return store.renderTiddler('text/plain',params.target);")
}
}
};

View File

@ -8,6 +8,7 @@ title: js/WikiTextCompiler.js
"use strict";
var ArgParser = require("./ArgParser.js").ArgParser,
JavaScriptParseTree = require("./JavaScriptParseTree.js").JavaScriptParseTree,
utils = require("./Utils.js"),
util = require("util");
@ -17,121 +18,6 @@ var WikiTextCompiler = function(store,title,parser) {
this.title = title;
};
// Compile a javascript tree into an array of string fragments
var compileJavaScript = function(tree) {
var output = [],
compileJavaScriptTree,
compileJavaScriptNode = function(node) {
var p;
switch(node.type) {
case "StringLiteral":
output.push(utils.stringify(node.value));
break;
case "StringLiterals":
output.push(utils.stringify(node.value.join("")));
break;
case "FunctionCall":
output.push("(");
compileJavaScriptNode(node.name);
output.push(")");
output.push("(");
for(p=0; p<node["arguments"].length; p++) {
if(p) {
output.push(",");
}
compileJavaScriptNode(node["arguments"][p]);
}
output.push(")");
break;
case "PropertyAccess":
compileJavaScriptNode(node.base);
if(typeof node.name === "string") {
output.push("." + node.name);
} else {
output.push("[");
compileJavaScriptNode(node.name);
output.push("]");
}
break;
case "ArrayLiteral":
output.push("[");
for(p=0; p<node.elements.length; p++) {
if(p) {
output.push(",");
}
compileJavaScriptNode(node.elements[p]);
}
output.push("]");
break;
case "Variable":
output.push(node.name);
break;
case "ObjectLiteral":
output.push("{");
for(p=0; p<node.properties.length; p++) {
if(p) {
output.push(",");
}
compileJavaScriptNode(node.properties[p]);
}
output.push("}");
break;
case "PropertyAssignment":
output.push(node.name);
output.push(":");
compileJavaScriptNode(node.value);
break;
case "BinaryExpression":
output.push("(");
compileJavaScriptNode(node.left);
output.push(")");
output.push(node.operator);
output.push("(");
compileJavaScriptNode(node.right);
output.push(")");
break;
case "NumericLiteral":
output.push(node.value);
break;
case "Function":
output.push("(");
output.push("function ");
if(node.name !== null) {
output.push(node.name);
}
output.push("(");
output.push(node.params.join(","));
output.push(")");
output.push("{");
compileJavaScriptTree(node.elements);
output.push("}");
output.push(")");
break;
case "ReturnStatement":
output.push("return ");
compileJavaScriptNode(node.value);
break;
case "This":
output.push("this");
break;
default:
console.log(node);
throw "Unknown JavaScript node type: " + node.type;
//break;
}
};
compileJavaScriptTree = function(tree) {
for(var t=0; t<tree.length; t++) {
if(t) {
output.push(";\n");
}
compileJavaScriptNode(tree[t]);
}
};
compileJavaScriptTree(tree);
return output;
};
WikiTextCompiler.prototype.compile = function(type,treenode) {
if(type === "text/html") {
return this.compileAsHtml(treenode);
@ -193,8 +79,8 @@ WikiTextCompiler.prototype.compileAsHtml = function(treenode) {
paramsProps = {};
var insertParam = function(name,arg) {
if(arg.evaluated) {
var prog = me.store.sandbox.parse(arg.string);
paramsProps[name] = prog.elements[0];
var prog = me.store.jsParser.parse(arg.string);
paramsProps[name] = prog.tree.elements[0];
} else {
paramsProps[name] = {type: "StringLiteral", value: arg.string};
}
@ -225,7 +111,7 @@ WikiTextCompiler.prototype.compileAsHtml = function(treenode) {
properties: []
}]
};
macroCall.name.elements = macro.code["text/html"].elements;
macroCall.name.elements = macro.code["text/html"].tree.elements;
for(m in paramsProps) {
macroCall["arguments"][0].properties.push({
type: "PropertyAssignment",
@ -281,7 +167,7 @@ WikiTextCompiler.prototype.compileAsHtml = function(treenode) {
// Compile the wiki parse tree into a javascript parse tree
compileSubTree(treenode);
// And then render the javascript parse tree back into JavaScript code
return compileJavaScript(
var parseTree = this.store.jsParser.createTree(
[
{
type: "Function",
@ -309,8 +195,8 @@ WikiTextCompiler.prototype.compileAsHtml = function(treenode) {
}
]
}
]
).join("");
]);
return parseTree.render();
};
WikiTextCompiler.prototype.compileAsText = function(treenode) {
@ -343,8 +229,8 @@ WikiTextCompiler.prototype.compileAsText = function(treenode) {
paramsProps = {};
var insertParam = function(name,arg) {
if(arg.evaluated) {
var prog = me.store.sandbox.parse(arg.string);
paramsProps[name] = prog.elements[0];
var prog = me.store.jsParser.parse(arg.string);
paramsProps[name] = prog.tree.elements[0];
} else {
paramsProps[name] = {type: "StringLiteral", value: arg.string};
}
@ -375,7 +261,7 @@ WikiTextCompiler.prototype.compileAsText = function(treenode) {
properties: []
}]
};
macroCall.name.elements = macro.code["text/plain"].elements;
macroCall.name.elements = macro.code["text/plain"].tree.elements;
for(m in paramsProps) {
macroCall["arguments"][0].properties.push({
type: "PropertyAssignment",
@ -421,7 +307,7 @@ WikiTextCompiler.prototype.compileAsText = function(treenode) {
// Compile the wiki parse tree into a javascript parse tree
compileSubTree(treenode);
// And then render the javascript parse tree back into JavaScript code
return compileJavaScript(
var parseTree = this.store.jsParser.createTree(
[
{
type: "Function",
@ -449,8 +335,8 @@ WikiTextCompiler.prototype.compileAsText = function(treenode) {
}
]
}
]
).join("");
]);
return parseTree.render();
};
exports.WikiTextCompiler = WikiTextCompiler;

View File

@ -9,8 +9,7 @@ Parses a block of tiddlywiki-format wiki text into a parse tree object.
/*jslint node: true */
"use strict";
var WikiTextRenderer = require("./WikiTextRenderer.js").WikiTextRenderer,
WikiTextCompiler = require("./WikiTextCompiler.js").WikiTextCompiler,
var WikiTextCompiler = require("./WikiTextCompiler.js").WikiTextCompiler,
utils = require("./Utils.js"),
util = require("util");
@ -139,11 +138,6 @@ WikiTextParser.prototype.render = function(type,treenode,store,title) {
return fn(tiddler,store,utils);
};
WikiTextParser.prototype.compile = function(type,treenode,store,title) {
var compiler = new WikiTextCompiler(store,title,this);
return compiler.compile(type,treenode);
};
exports.WikiTextParser = WikiTextParser;
})();

View File

@ -135,7 +135,7 @@ WikiTextRenderer.prototype.executeMacro = function(macroNode,title) {
globals: {
title: title
},
sandbox: this.store.sandbox
sandbox: this.store.jsProcessor
};
for(var g in macroInfo.argOptions) {
argOptions[g] = macroInfo.argOptions[g];

View File

@ -7,7 +7,8 @@ recipe: ../parsers/split.recipe
jslib: ../test/tiddlywiki.2.6.5/source/tiddlywiki/jquery/jquery.js
jsmodule: ../js/Sandbox.js
jsmodule: ../js/JavaScriptParser.js
jsmodule: ../js/JavaScriptParseTree.js
jsmodule: ../js/ArgParser.js
jsmodule: ../js/FileRetriever.js
jsmodule: ../js/Utils.js