98 lines
3.3 KiB
JavaScript
98 lines
3.3 KiB
JavaScript
/* Parser for Splash, an attempt at a programming language for kids.
|
|
*
|
|
* @Author: Ryan McGrath
|
|
* @Requires:
|
|
* Node.js (Run latest for safety ;P)
|
|
* line_reader.js (custom, supplied in libraries)
|
|
* wrench.js (custom, supplied in libraries)
|
|
*
|
|
* @Note: This is just a compiler/parser. Core Splash takes place inside the browser - no need
|
|
* to muck around in DOM logic here when it's readily available over there. ;P
|
|
*/
|
|
|
|
/* If no file was passed in, instruct them to do so. */
|
|
if(!process.ARGV[2]) sys.puts('\nPlease provide a filename as an argument!\n');
|
|
|
|
var sys = require('sys'),
|
|
fs = require('fs'),
|
|
wrench = require('./libraries/wrench'),
|
|
line = require('./libraries/line_reader'),
|
|
definitions = require('./libraries/definitions'), /* Mapping of splash ~> JS commands */
|
|
expr = new line.reader(process.ARGV[2]),
|
|
creatingBlock = false,
|
|
stripper = /explain|noun|verb/,
|
|
whitespace = /^\s+|\s+$|/g,
|
|
block = {},
|
|
finalRep = [];
|
|
|
|
var determineAttrName = function(str) { return str.replace(whitespace, '').split(':')[0]; };
|
|
var determineVal = function(str) { return str.replace(whitespace, '').split(':')[1]; };
|
|
|
|
/* Aptly, returns a variable type from parsing a string.
|
|
*
|
|
* e.g, given "verb b:", this will return "verb"
|
|
*/
|
|
var getType = function(str) {
|
|
if(/verb/.test(str)) return "verb";
|
|
|
|
/* Nouns are essentially a generic fallback type. */
|
|
return "noun";
|
|
};
|
|
|
|
exports.writeApp = function(text) {
|
|
/* This gets passed to Splash and evaluated in the browser, since we want the DOM. */
|
|
var finalJSON = "[" + finalRep.join(',') + "]",
|
|
appName = process.ARGV[2].replace(".splash", ""),
|
|
currPath = process.cwd();
|
|
|
|
/* Very messy for the time being, as I'm just doing a proof of concept. Requires you to be
|
|
* one directory up from this file for execution.
|
|
*/
|
|
wrench.copyDirSyncRecursive(currPath + '/lib/app_base', currPath + '/' + appName);
|
|
fs.writeFileSync(currPath + "/" + appName + "/scripts/compiled.js", "function main() { splash.game_on(" + finalJSON + "); };", encoding="utf8");
|
|
};
|
|
|
|
/* In Splash, explanations are essentially variable declarations,
|
|
* but formulated like simple vocabulary definitions for kids.
|
|
*
|
|
* Note: This could also prove useful in teaching people English.
|
|
*
|
|
* e.g:
|
|
* verb run:
|
|
* who: daniel
|
|
* action: move
|
|
* direction: left
|
|
* end
|
|
*
|
|
* @Note: This parse is currently very "top down", and not as forgiving as it should be.
|
|
*/
|
|
while(expr.hasNextLine()) {
|
|
var currLine = expr.getNextLine(),
|
|
isBeginning = stripper.test(currLine); /* Tests to see if we make a declaration. */
|
|
|
|
if(creatingBlock || isBeginning) {
|
|
creatingBlock = /end/.test(currLine) ? false : true;
|
|
|
|
/* type = verb/noun/etc
|
|
* name = name of the variable (e.g, verb run, name = run)
|
|
*/
|
|
if(isBeginning) block["type"] = getType(currLine);
|
|
if(isBeginning) block["name"] = currLine.replace(stripper, '').replace(whitespace, '');
|
|
else block[determineAttrName(currLine)] = determineVal(currLine);
|
|
|
|
/* If this is false, we're done building up a new block/JSON structure, so we can
|
|
* push it onto the stack for the browser to get down the road. We also reset the
|
|
* block here, so subsequent operations have a blank slate to work with.
|
|
*/
|
|
if(!creatingBlock) {
|
|
finalRep.push(JSON.stringify(block));
|
|
block = {};
|
|
}
|
|
}
|
|
}
|
|
|
|
try {
|
|
this.writeApp();
|
|
} catch(error) {
|
|
sys.puts(error);
|
|
}
|