comparison 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
comparison
equal deleted inserted replaced
24:fe3533494ce9 25:4d87c38404d6
14 return mainModule.snumber(val); 14 return mainModule.snumber(val);
15 } 15 }
16 throw new Error("can't make val into object"); 16 throw new Error("can't make val into object");
17 } 17 }
18 18
19 function importSym(obj, src, key)
20 {
21 if(!(key in src)) {
22 throw new Error(key +' not found in source object for import');
23 }
24 if(key in obj) {
25 throw new Error(key +' already exists in target object for import')
26 }
27 obj[key] = src[key];
28 }
29
30 function doImport(obj, src, symlist)
31 {
32 if (symlist === undefined) {
33 each(src, function(key,val) {
34 if (key != 'parent') {
35 importSym(obj, src, key);
36 }
37 });
38 } else {
39 for (var i = 0; i < symlist.length; ++i) {
40 importSym(obj, src, symlist[i]);
41 }
42 }
43 return obj;
44 }
45
19 op.prototype.toJS = function(isReceiver) { 46 op.prototype.toJS = function(isReceiver) {
20 var ret = '(' + this.left.toJS() +' '+ (this.op == '=' ? '==' : this.op) +' '+ this.right.toJS() + ')'; 47 var ret = '(' + this.left.toJS() +' '+ (this.op == '=' ? '==' : this.op) +' '+ this.right.toJS() + ')';
21 if (isReceiver) { 48 if (isReceiver) {
22 ret = 'toobj' + ret; 49 ret = 'toobj' + ret;
23 } 50 }
24 return ret; 51 return ret;
25 }; 52 };
26 53
54 function escapeJSName(name)
55 {
56 name = name.replace("_", "UN_").replace(":", "CN_").replace("!", "EX_").replace('?', 'QS_').replace('@', 'AT_');
57 var reserved = {'true': true, 'false': true, 'this': true, 'if': true, 'else': true, 'NaN': true};
58 if (name in reserved) {
59 name = 's' + name;
60 }
61 return name;
62 }
63
27 symbol.prototype.toJS = function() { 64 symbol.prototype.toJS = function() {
28 var name = this.cleanName(); 65 var name = this.cleanName();
29 if (name == 'self') { 66 if (name == 'self') {
30 return this.symbols.selfVar(); 67 return this.symbols.selfVar();
31 } 68 }
32 name = name.replace("_", "UN_").replace(":", "CN_").replace("!", "EX_").replace('?', 'QS_').replace('@', 'AT_'); 69 var info = this.symbols.find(name);
33 var reserved = {'true': true, 'false': true, 'this': true, 'if': true, 'else': true, 'NaN': true}; 70 if (!info) {
34 if (name in reserved) { 71 throw new Error('symbol ' + name + ' not found');
35 name = 's' + name; 72 }
36 } 73 var pre = '';
37 return name; 74 if (info.type == 'self') {
75 pre = this.symbols.selfVar() + '.';
76 } else if(info.type == 'parent') {
77 pre = 'this';
78 for (var i = 0; i < funinfo.depth; ++i) {
79 pre += '.parent';
80 }
81 }
82 return pre + escapeJSName(name);
38 } 83 }
39 84
40 intlit.prototype.toJS = function() { 85 intlit.prototype.toJS = function() {
41 return this.val.toString(); 86 return this.val.toString();
42 } 87 }
45 return this.val.toString(); 90 return this.val.toString();
46 } 91 }
47 92
48 strlit.prototype.toJS = function() { 93 strlit.prototype.toJS = function() {
49 return '"' + this.val.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r') + '"'; 94 return '"' + this.val.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r') + '"';
95 }
96
97 listlit.prototype.toJS = function() {
98 var ret = '[';
99 each(this.val, function(idx, el) {
100 ret += (idx ? ', ' : '') + el.toJS();
101 });
102 return ret + ']';
50 } 103 }
51 104
52 funcall.prototype.toJS = function() { 105 funcall.prototype.toJS = function() {
53 var name = this.name[this.name.length-1] == ':' ? this.name.substr(0, this.name.length-1) : this.name; 106 var name = this.name[this.name.length-1] == ':' ? this.name.substr(0, this.name.length-1) : this.name;
54 if (name == 'foreign') { 107 if (name == 'foreign') {
71 for (var i in args) { 124 for (var i in args) {
72 args[i] = args[i].toJS(); 125 args[i] = args[i].toJS();
73 } 126 }
74 var rJS = receiver.toJS(true); 127 var rJS = receiver.toJS(true);
75 if ((name[name.length-1] == '!' && args.length == 1) || (funinfo && funinfo.def instanceof setter)) { 128 if ((name[name.length-1] == '!' && args.length == 1) || (funinfo && funinfo.def instanceof setter)) {
76 console.log(name.substr(0, name.length-1)); 129 return '(' + rJS + '.' + escapeJSName(name.substr(0, name.length-1)) + ' = ' + args[0] + ', ' + rJS + ')';
77 return '(' + rJS + '.' + (new symbol(name.substr(0, name.length-1), this.symbols)).toJS() + ' = ' + args[0] + ', ' + rJS + ')' 130 } else {
78 } else { 131 var callee = rJS + '.' + escapeJSName(name);
79 var callee = rJS + '.' + (new symbol(name, this.symbols)).toJS();
80 var callCode = callee + '(' + args.join(', ') + ')'; 132 var callCode = callee + '(' + args.join(', ') + ')';
81 if (args.length == 0) { 133 if (args.length == 0) {
82 return '(' + callee + ' instanceof Function ? ' + callCode + ' : ' + callee + ')'; 134 return '(' + callee + ' instanceof Function ? ' + callCode + ' : ' + callee + ')';
83 } else { 135 } else {
84 return callCode; 136 return callCode;
105 break; 157 break;
106 } 158 }
107 for (var i in args) { 159 for (var i in args) {
108 args[i] = args[i].toJS(); 160 args[i] = args[i].toJS();
109 } 161 }
110 return ret + (new symbol(name, this.symbols)).toJS() + '(' + args.join(', ') + ')'; 162 return ret + escapeJSName(name) + '(' + args.join(', ') + ')';
111 } 163 }
112 164
113 object.prototype.toJS = function() { 165 object.prototype.toJS = function() {
114 var messages = this.messages; 166 var messages = this.messages;
115 var compiled = [] 167 var compiled = [];
168 var imports = []
116 for (var i in messages) { 169 for (var i in messages) {
117 var js = messages[i].toJSObject(); 170 if (messages[i] instanceof funcall) {
118 if (js) { 171 if (messages[i].name == 'import:' && messages[i].args.length == 1) {
119 compiled.push(indent(js)); 172 imports.push({symbols: false, src: messages[i].args[0]});
120 } 173 } else if(messages[i].name == 'import:from:' && messages[i].args.length == 2) {
121 } 174 var importsyms = [];
122 return '{\n\tparent: ' + this.symbols.parentObject() + ',\n\t' + compiled.join(',\n\t') + '\n}'; 175 each(messages[i].args[0].val, function(i, el) {
176 if (!(el instanceof symbol)) {
177 throw new Error('Names in import:from statement must be symbols');
178 }
179 importsyms.push(new strlit(el.name));
180 });
181 imports.push({symbols: new listlit(importsyms), src: messages[i].args[1]});
182 } else {
183 throw new Error('Only import and import:from calls allowed in object context');
184 }
185 } else {
186 var js = messages[i].toJSObject();
187 if (js) {
188 compiled.push(indent(js));
189 }
190 }
191 }
192 var pre = '';
193 var post = '';
194 for (var i = imports.length-1; i >= 0; i--) {
195 pre += 'doImport(';
196 post += ', ' + imports[i].src.toJS();
197 if (imports[i].symbols) {
198 post += ', ' + imports[i].symbols.toJS();
199 }
200 post += ')';
201 }
202 return pre+'{\n\tparent: ' + this.symbols.parentObject() + ',\n\t' + compiled.join(',\n\t') + '\n}'+post;
123 } 203 }
124 204
125 object.prototype.toJSModule = function() { 205 object.prototype.toJSModule = function() {
126 this.populateSymbols(null); 206 this.populateSymbols(null);
127 return '(function () {\n\tvar module = ' + indent(this.toJS()) + ';\n\treturn module;\n})' 207 return '(function () {\n\tvar module = ' + indent(this.toJS()) + ';\n\treturn module;\n})'
182 assignment.prototype.toJSObject = function() { 262 assignment.prototype.toJSObject = function() {
183 var val = this.expression.toJS(); 263 var val = this.expression.toJS();
184 if (val === null) { 264 if (val === null) {
185 return null; 265 return null;
186 } 266 }
187 return this.symbol.toJS() + ': ' + val; 267 return escapeJSName(this.symbol.name) + ': ' + val;
188 }; 268 };