Mercurial > repos > tabletprog
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']; |