Mercurial > repos > tabletprog
diff jsbackend.js @ 25:4d87c38404d6
List literals, fixes to implicit self property lookup, import statement and editor improvements
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Mon, 02 Apr 2012 22:28:48 -0700 |
parents | 068d63627b16 |
children | 608eb70fe261 |
line wrap: on
line diff
--- a/jsbackend.js Tue Mar 27 00:39:32 2012 -0700 +++ b/jsbackend.js Mon Apr 02 22:28:48 2012 -0700 @@ -16,6 +16,33 @@ throw new Error("can't make val into object"); } +function importSym(obj, src, key) +{ + if(!(key in src)) { + throw new Error(key +' not found in source object for import'); + } + if(key in obj) { + throw new Error(key +' already exists in target object for import') + } + obj[key] = src[key]; +} + +function doImport(obj, src, symlist) +{ + if (symlist === undefined) { + each(src, function(key,val) { + if (key != 'parent') { + importSym(obj, src, key); + } + }); + } else { + for (var i = 0; i < symlist.length; ++i) { + importSym(obj, src, symlist[i]); + } + } + return obj; +} + op.prototype.toJS = function(isReceiver) { var ret = '(' + this.left.toJS() +' '+ (this.op == '=' ? '==' : this.op) +' '+ this.right.toJS() + ')'; if (isReceiver) { @@ -24,11 +51,8 @@ return ret; }; -symbol.prototype.toJS = function() { - var name = this.cleanName(); - if (name == 'self') { - return this.symbols.selfVar(); - } +function escapeJSName(name) +{ name = name.replace("_", "UN_").replace(":", "CN_").replace("!", "EX_").replace('?', 'QS_').replace('@', 'AT_'); var reserved = {'true': true, 'false': true, 'this': true, 'if': true, 'else': true, 'NaN': true}; if (name in reserved) { @@ -37,6 +61,27 @@ return name; } +symbol.prototype.toJS = function() { + var name = this.cleanName(); + if (name == 'self') { + return this.symbols.selfVar(); + } + var info = this.symbols.find(name); + if (!info) { + throw new Error('symbol ' + name + ' not found'); + } + var pre = ''; + if (info.type == 'self') { + pre = this.symbols.selfVar() + '.'; + } else if(info.type == 'parent') { + pre = 'this'; + for (var i = 0; i < funinfo.depth; ++i) { + pre += '.parent'; + } + } + return pre + escapeJSName(name); +} + intlit.prototype.toJS = function() { return this.val.toString(); } @@ -49,6 +94,14 @@ return '"' + this.val.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r') + '"'; } +listlit.prototype.toJS = function() { + var ret = '['; + each(this.val, function(idx, el) { + ret += (idx ? ', ' : '') + el.toJS(); + }); + return ret + ']'; +} + funcall.prototype.toJS = function() { var name = this.name[this.name.length-1] == ':' ? this.name.substr(0, this.name.length-1) : this.name; if (name == 'foreign') { @@ -73,10 +126,9 @@ } var rJS = receiver.toJS(true); if ((name[name.length-1] == '!' && args.length == 1) || (funinfo && funinfo.def instanceof setter)) { - console.log(name.substr(0, name.length-1)); - return '(' + rJS + '.' + (new symbol(name.substr(0, name.length-1), this.symbols)).toJS() + ' = ' + args[0] + ', ' + rJS + ')' + return '(' + rJS + '.' + escapeJSName(name.substr(0, name.length-1)) + ' = ' + args[0] + ', ' + rJS + ')'; } else { - var callee = rJS + '.' + (new symbol(name, this.symbols)).toJS(); + var callee = rJS + '.' + escapeJSName(name); var callCode = callee + '(' + args.join(', ') + ')'; if (args.length == 0) { return '(' + callee + ' instanceof Function ? ' + callCode + ' : ' + callee + ')'; @@ -107,19 +159,47 @@ for (var i in args) { args[i] = args[i].toJS(); } - return ret + (new symbol(name, this.symbols)).toJS() + '(' + args.join(', ') + ')'; + return ret + escapeJSName(name) + '(' + args.join(', ') + ')'; } object.prototype.toJS = function() { var messages = this.messages; - var compiled = [] + var compiled = []; + var imports = [] for (var i in messages) { - var js = messages[i].toJSObject(); - if (js) { - compiled.push(indent(js)); + if (messages[i] instanceof funcall) { + if (messages[i].name == 'import:' && messages[i].args.length == 1) { + imports.push({symbols: false, src: messages[i].args[0]}); + } else if(messages[i].name == 'import:from:' && messages[i].args.length == 2) { + var importsyms = []; + each(messages[i].args[0].val, function(i, el) { + if (!(el instanceof symbol)) { + throw new Error('Names in import:from statement must be symbols'); + } + importsyms.push(new strlit(el.name)); + }); + imports.push({symbols: new listlit(importsyms), src: messages[i].args[1]}); + } else { + throw new Error('Only import and import:from calls allowed in object context'); + } + } else { + var js = messages[i].toJSObject(); + if (js) { + compiled.push(indent(js)); + } } } - return '{\n\tparent: ' + this.symbols.parentObject() + ',\n\t' + compiled.join(',\n\t') + '\n}'; + var pre = ''; + var post = ''; + for (var i = imports.length-1; i >= 0; i--) { + pre += 'doImport('; + post += ', ' + imports[i].src.toJS(); + if (imports[i].symbols) { + post += ', ' + imports[i].symbols.toJS(); + } + post += ')'; + } + return pre+'{\n\tparent: ' + this.symbols.parentObject() + ',\n\t' + compiled.join(',\n\t') + '\n}'+post; } object.prototype.toJSModule = function() { @@ -184,5 +264,5 @@ if (val === null) { return null; } - return this.symbol.toJS() + ': ' + val; + return escapeJSName(this.symbol.name) + ': ' + val; };