comparison types.js @ 100:9db0e3533b23

Some work on parameterized types
author Mike Pavone <pavone@retrodev.com>
date Wed, 08 Aug 2012 09:19:14 -0700
parents b58b19c455ec
children 5d15b91e738a
comparison
equal deleted inserted replaced
99:b58b19c455ec 100:9db0e3533b23
62 } 62 }
63 //temporarily set cache entry to true to prevent infinite recursion 63 //temporarily set cache entry to true to prevent infinite recursion
64 this.satisfies_cache[type.id] = true; 64 this.satisfies_cache[type.id] = true;
65 var ret = true; 65 var ret = true;
66 if (type.messages === undefined) { 66 if (type.messages === undefined) {
67 print('type has no messages');
67 ret = false; 68 ret = false;
68 } 69 }
69 if (ret) { 70 if (ret) {
70 for (var msgname in this.messages) { 71 for (var msgname in this.messages) {
71 if (!(msgname in type.messages) || !this.messages[msgname].satisfiedBy(type.messages[msgname])) { 72 if (!(msgname in type.messages) || !this.messages[msgname].satisfiedBy(type.messages[msgname])) {
73 print(msgname, 'missing in type');
72 ret = false; 74 ret = false;
73 break; 75 break;
74 } 76 }
75 } 77 }
76 } 78 }
93 } 95 }
94 return ret + indent + '}\n'; 96 return ret + indent + '}\n';
95 }; 97 };
96 98
97 objecttype.prototype.replaceParams = function(paramtypes, visited) { 99 objecttype.prototype.replaceParams = function(paramtypes, visited) {
98 if (visisted === undefined) { 100 if (visited === undefined) {
99 visited = {}; 101 visited = {};
100 } 102 }
101 if (this.id in visited) { 103 if (this.id in visited) {
102 return visited[this.id]; 104 return visited[this.id];
103 } 105 }
154 } 156 }
155 //temporarily set cache entry to true to prevent infinite recursion 157 //temporarily set cache entry to true to prevent infinite recursion
156 this.satisfies_cache[type.id] = true; 158 this.satisfies_cache[type.id] = true;
157 var ret = true; 159 var ret = true;
158 if (!(type.callable) || this.params.length != type.params.length) { 160 if (!(type.callable) || this.params.length != type.params.length) {
161 print('type is not callable or param length mismatch');
159 ret = false; 162 ret = false;
160 } 163 }
161 if (ret) { 164 if (ret) {
162 for (var i in this.params) { 165 for (var i in this.params) {
163 if (i >= type.params.length || !this.params[i].satisfiedBy(type.params[i])) { 166 if (i >= type.params.length || !this.params[i].satisfiedBy(type.params[i])) {
167 print('param ', i, ' is not satisfied');
164 ret = false; 168 ret = false;
165 break; 169 break;
166 } 170 }
167 } 171 }
168 } 172 }
169 if (ret) { 173 if (ret) {
170 for (var msgname in this.messages) { 174 for (var msgname in this.messages) {
171 if (!(msgname in type.messages) || !this.messages[msgname].satisfiedBy(type.messages[msgname])) { 175 if (!(msgname in type.messages) || !this.messages[msgname].satisfiedBy(type.messages[msgname])) {
176 print('message', msgname, 'is not satisfied');
172 ret = false; 177 ret = false;
173 break; 178 break;
174 } 179 }
175 } 180 }
176 } 181 }
199 } 204 }
200 return ret + indent + '}\n'; 205 return ret + indent + '}\n';
201 }; 206 };
202 207
203 lambdatype.prototype.replaceParams = function(paramtypes, visited) { 208 lambdatype.prototype.replaceParams = function(paramtypes, visited) {
204 if (visisted === undefined) { 209 if (visited === undefined) {
205 visited = {}; 210 visited = {};
206 } 211 }
207 if (this.id in visited) { 212 if (this.id in visited) {
208 return visited[this.id]; 213 return visited[this.id];
209 } 214 }
233 this.id = nexttypeid++; 238 this.id = nexttypeid++;
234 this.satisfies_cache = null; 239 this.satisfies_cache = null;
235 } 240 }
236 241
237 uniontype.prototype.lazyinit = function() { 242 uniontype.prototype.lazyinit = function() {
238 if (this.satisfies_cache = null) { 243 if (this.satisfies_cache == null) {
239 this.satisfies_cache = {}; 244 this.satisfies_cache = {};
240 this.satisfies_cache[this.id] = true; 245 this.satisfies_cache[this.id] = true;
241 this.messages = {}; 246 this.messages = {};
242 if (a.messages !== undefined && b.messages !== undefined) { 247 if (this.a.messages !== undefined && this.b.messages !== undefined) {
243 for (var msgname in a.messages) { 248 for (var msgname in this.a.messages) {
244 if (msgname in b.messages) { 249 if (msgname in this.b.messages) {
245 this.messages[msgname] = mkunion(a.messages[msgname], b.messages[msgname]); 250 this.messages[msgname] = mkunion(this.a.messages[msgname], this.b.messages[msgname]);
246 } 251 }
247 } 252 }
248 } 253 }
249 this.callable = false; 254 this.callable = false;
250 if (a.callable && b.callable && a.params.length == b.params.length) { 255 if (this.a.callable && this.b.callable && this.a.params.length == this.b.params.length) {
251 this.callable = true; 256 this.callable = true;
252 this.params = []; 257 this.params = [];
253 for (var i = 0; i < a.params.length; i++) { 258 for (var i = 0; i < this.a.params.length; i++) {
254 this.params.push(mkunion(a.params[i], b.params[i])); 259 this.params.push(mkunion(this.a.params[i], this.b.params[i]));
255 } 260 }
256 this.returntype = mkunion(a.returntype, b.returntype); 261 this.returntype = mkunion(this.a.returntype, this.b.returntype);
257 } 262 }
258 } 263 }
259 }; 264 };
260 265
261 uniontype.prototype.satisfiedBy = function(type) 266 uniontype.prototype.satisfiedBy = function(type)
276 indent = ''; 281 indent = '';
277 } 282 }
278 if (indent.length > 6) { 283 if (indent.length > 6) {
279 return 'max depth reached\n'; 284 return 'max depth reached\n';
280 } 285 }
281 return indent + 'Union {\n\t' + indent + this.a.str() + '\t' + indent + this.b.str() + indent + '}\n'; 286 return indent + 'Union {\n\t' + indent + this.a.str(indent+'\t') + '\t' + indent + this.b.str(indent+'\t') + indent + '}\n';
282 }; 287 };
283 288
284 uniontype.prototype.replaceParams = function(paramtypes, visited) { 289 uniontype.prototype.replaceParams = function(paramtypes, visited) {
285 if (visisted === undefined) { 290 if (visited === undefined) {
286 visited = {}; 291 visited = {};
287 } 292 }
288 if (this.id in visited) { 293 if (this.id in visited) {
289 return visited[this.id]; 294 return visited[this.id];
290 } 295 }
314 319
315 function withtparams(type, params) 320 function withtparams(type, params)
316 { 321 {
317 this.type = type; 322 this.type = type;
318 this.params = params; 323 this.params = params;
319 } 324 this.replaced = false;
320 325 }
321 withtparams.prototype.satisfiedBy = function(type) { 326
322 return this.type.satisfiedBy(type); 327 withtparams.prototype = {
323 }; 328 satisfiedBy: function(type) {
324 329 this.lazyinit();
325 withtparams.prototype.str = function(indent) { 330 return this.type.satisfiedBy(type);
326 return this.type.str(indent) + indent + '<' + this.params.map(function(p) { return p.str(indent); }).join(', ') + '>'; 331 },
327 }; 332 str: function(indent) {
328 333 if (indent === undefined) {
329 withtparams.prototype.replaceParams = function(paramtypes) { 334 indent = '';
330 var replaced = false; 335 }
331 for (var i in this.params) { 336 if (indent.length > 6) {
332 var newp = this.params[i].replaceParams(paramtypes); 337 return 'max depth reached\n';
333 if (newp != this.params[i]) { 338 }
334 replaced = true; 339 return this.type.str(indent) + indent + '<' + this.params.map(function(p) { return p.str(indent); }).join(', ') + '>';
335 this.params[i] = newp; 340 },
336 } 341 replaceParams: function(paramtypes) {
337 } 342 var replaced = false;
338 if (replaced) { 343 for (var i in this.params) {
339 var childptypes = {}; 344 var newp = this.params[i].replaceParams(paramtypes);
340 for (var i in this.type.typeparams) { 345 if (newp != this.params[i]) {
341 childptypes[this.type.typeparams[i]] = this.params[i] 346 replaced = true;
342 } 347 this.params[i] = newp;
343 this.type = this.type.replaceParams(childptypes, {}); 348 }
344 } 349 }
345 return this; 350 return this;
351 },
352 lazyinit: function() {
353 if (!this.replaced) {
354 var childptypes = {};
355 for (var i in this.type.typeparams) {
356 print(this.type.typeparams[i], 'is', this.params[i].str());
357 childptypes[this.type.typeparams[i]] = this.params[i]
358 }
359 this.type = this.type.replaceParams(childptypes, {});
360 this.replaced = true;
361 }
362 },
363 get messages() {
364 this.lazyinit();
365 return this.type.messages;
366 }
346 }; 367 };
347 368
348 function typetest() 369 function typetest()
349 { 370 {
350 var foo = new objecttype(); 371 var foo = new objecttype();
371 var tlnode = new objecttype(); 392 var tlnode = new objecttype();
372 tlnode.typeparams = ['T']; 393 tlnode.typeparams = ['T'];
373 var t = new typeparam('T', any); 394 var t = new typeparam('T', any);
374 var q = new typeparam('Q', any); 395 var q = new typeparam('Q', any);
375 var head = new lambdatype(); 396 var head = new lambdatype();
376 head.returnType = t; 397 head.returntype = t;
377 tlnode.addMessage('head', head); 398 tlnode.addMessage('head', head);
378 var tail = new lambdatype(); 399 var tail = new lambdatype();
379 var econs = new lambdatype(); 400 var econs = new lambdatype();
380 econs.addParam('val'); 401 econs.addParam('val');
381 econs.typeparams = ['Q']; 402 econs.typeparams = ['Q'];