yukigo 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/.mocharc.json +3 -3
  2. package/CHANGELOG.md +26 -0
  3. package/README.md +193 -199
  4. package/dist/analyzer/GraphBuilder.d.ts +29 -0
  5. package/dist/analyzer/GraphBuilder.js +99 -0
  6. package/dist/analyzer/index.d.ts +11 -23
  7. package/dist/analyzer/index.js +100 -58
  8. package/dist/analyzer/inspections/functional/functional.d.ts +44 -0
  9. package/dist/analyzer/inspections/functional/functional.js +149 -0
  10. package/dist/analyzer/inspections/functional/smells.d.ts +16 -0
  11. package/dist/analyzer/inspections/functional/smells.js +98 -0
  12. package/dist/analyzer/inspections/{generic.d.ts → generic/generic.d.ts} +70 -43
  13. package/dist/analyzer/inspections/generic/generic.js +604 -0
  14. package/dist/analyzer/inspections/generic/smells.d.ts +61 -0
  15. package/dist/analyzer/inspections/generic/smells.js +349 -0
  16. package/dist/analyzer/inspections/imperative/imperative.d.ts +35 -0
  17. package/dist/analyzer/inspections/imperative/imperative.js +109 -0
  18. package/dist/analyzer/inspections/imperative/smells.d.ts +16 -0
  19. package/dist/analyzer/inspections/imperative/smells.js +58 -0
  20. package/dist/analyzer/inspections/logic/logic.d.ts +32 -0
  21. package/dist/analyzer/inspections/logic/logic.js +96 -0
  22. package/dist/analyzer/inspections/logic/smells.d.ts +15 -0
  23. package/dist/analyzer/inspections/logic/smells.js +60 -0
  24. package/dist/analyzer/inspections/object/object.d.ts +88 -0
  25. package/dist/analyzer/inspections/object/object.js +319 -0
  26. package/dist/analyzer/inspections/object/smells.d.ts +30 -0
  27. package/dist/analyzer/inspections/object/smells.js +135 -0
  28. package/dist/analyzer/utils.d.ts +26 -4
  29. package/dist/analyzer/utils.js +71 -13
  30. package/dist/index.d.ts +1 -0
  31. package/dist/index.js +1 -0
  32. package/dist/interpreter/components/EnvBuilder.d.ts +9 -5
  33. package/dist/interpreter/components/EnvBuilder.js +100 -30
  34. package/dist/interpreter/components/Operations.d.ts +4 -4
  35. package/dist/interpreter/components/Operations.js +17 -2
  36. package/dist/interpreter/components/PatternMatcher.d.ts +47 -17
  37. package/dist/interpreter/components/PatternMatcher.js +264 -119
  38. package/dist/interpreter/components/RuntimeContext.d.ts +35 -0
  39. package/dist/interpreter/components/RuntimeContext.js +93 -0
  40. package/dist/interpreter/components/TestRunner.d.ts +18 -0
  41. package/dist/interpreter/components/TestRunner.js +103 -0
  42. package/dist/interpreter/components/Visitor.d.ts +63 -57
  43. package/dist/interpreter/components/Visitor.js +508 -173
  44. package/dist/interpreter/components/logic/LogicEngine.d.ts +29 -0
  45. package/dist/interpreter/components/logic/LogicEngine.js +259 -0
  46. package/dist/interpreter/components/logic/LogicResolver.d.ts +53 -0
  47. package/dist/interpreter/components/logic/LogicResolver.js +471 -0
  48. package/dist/interpreter/components/logic/LogicTranslator.d.ts +14 -0
  49. package/dist/interpreter/components/logic/LogicTranslator.js +99 -0
  50. package/dist/interpreter/components/runtimes/FunctionRuntime.d.ts +12 -0
  51. package/dist/interpreter/components/runtimes/FunctionRuntime.js +147 -0
  52. package/dist/interpreter/components/runtimes/LazyRuntime.d.ts +19 -0
  53. package/dist/interpreter/components/runtimes/LazyRuntime.js +269 -0
  54. package/dist/interpreter/components/runtimes/ObjectRuntime.d.ts +35 -0
  55. package/dist/interpreter/components/runtimes/ObjectRuntime.js +126 -0
  56. package/dist/interpreter/entities.d.ts +105 -0
  57. package/dist/interpreter/entities.js +96 -0
  58. package/dist/interpreter/errors.d.ts +1 -1
  59. package/dist/interpreter/index.d.ts +4 -12
  60. package/dist/interpreter/index.js +10 -13
  61. package/dist/interpreter/trampoline.d.ts +17 -0
  62. package/dist/interpreter/trampoline.js +38 -0
  63. package/dist/interpreter/utils.d.ts +4 -7
  64. package/dist/interpreter/utils.js +25 -17
  65. package/dist/tester/index.d.ts +25 -0
  66. package/dist/tester/index.js +108 -0
  67. package/dist/utils/helpers.d.ts +0 -4
  68. package/dist/utils/helpers.js +20 -24
  69. package/package.json +2 -2
  70. package/src/analyzer/GraphBuilder.ts +142 -0
  71. package/src/analyzer/index.ts +185 -132
  72. package/src/analyzer/inspections/functional/functional.ts +121 -0
  73. package/src/analyzer/inspections/functional/smells.ts +102 -0
  74. package/src/analyzer/inspections/{generic.ts → generic/generic.ts} +581 -499
  75. package/src/analyzer/inspections/generic/smells.ts +365 -0
  76. package/src/analyzer/inspections/imperative/imperative.ts +101 -0
  77. package/src/analyzer/inspections/imperative/smells.ts +54 -0
  78. package/src/analyzer/inspections/logic/logic.ts +90 -0
  79. package/src/analyzer/inspections/logic/smells.ts +54 -0
  80. package/src/analyzer/inspections/{object.ts → object/object.ts} +264 -282
  81. package/src/analyzer/inspections/object/smells.ts +144 -0
  82. package/src/analyzer/utils.ts +109 -26
  83. package/src/index.ts +3 -2
  84. package/src/interpreter/components/EnvBuilder.ts +202 -97
  85. package/src/interpreter/components/Operations.ts +99 -81
  86. package/src/interpreter/components/PatternMatcher.ts +475 -254
  87. package/src/interpreter/components/RuntimeContext.ts +119 -0
  88. package/src/interpreter/components/TestRunner.ts +151 -0
  89. package/src/interpreter/components/Visitor.ts +1065 -493
  90. package/src/interpreter/components/logic/LogicEngine.ts +519 -0
  91. package/src/interpreter/components/logic/LogicResolver.ts +858 -0
  92. package/src/interpreter/components/logic/LogicTranslator.ts +149 -0
  93. package/src/interpreter/components/runtimes/FunctionRuntime.ts +227 -0
  94. package/src/interpreter/components/runtimes/LazyRuntime.ts +334 -0
  95. package/src/interpreter/components/runtimes/ObjectRuntime.ts +224 -0
  96. package/src/interpreter/errors.ts +47 -47
  97. package/src/interpreter/index.ts +52 -59
  98. package/src/interpreter/trampoline.ts +71 -0
  99. package/src/interpreter/utils.ts +84 -79
  100. package/src/tester/index.ts +128 -0
  101. package/src/utils/helpers.ts +67 -73
  102. package/tests/analyzer/functional.spec.ts +207 -221
  103. package/tests/analyzer/generic.spec.ts +178 -100
  104. package/tests/analyzer/helpers.spec.ts +83 -83
  105. package/tests/analyzer/logic.spec.ts +237 -292
  106. package/tests/analyzer/oop.spec.ts +323 -338
  107. package/tests/analyzer/transitive.spec.ts +166 -0
  108. package/tests/interpreter/EnvBuilder.spec.ts +183 -178
  109. package/tests/interpreter/FunctionRuntime.spec.ts +223 -234
  110. package/tests/interpreter/LazyRuntime.spec.ts +225 -190
  111. package/tests/interpreter/LogicEngine.spec.ts +327 -194
  112. package/tests/interpreter/LogicSubstitution.spec.ts +80 -0
  113. package/tests/interpreter/ObjectRuntime.spec.ts +606 -0
  114. package/tests/interpreter/Operations.spec.ts +220 -220
  115. package/tests/interpreter/PatternSystem.spec.ts +213 -189
  116. package/tests/interpreter/Tests.spec.ts +122 -0
  117. package/tests/interpreter/interpreter.spec.ts +991 -937
  118. package/tests/tester/Tester.spec.ts +153 -0
  119. package/tsconfig.build.json +15 -7
  120. package/tsconfig.json +25 -17
  121. package/dist/analyzer/inspections/functional.d.ts +0 -46
  122. package/dist/analyzer/inspections/functional.js +0 -123
  123. package/dist/analyzer/inspections/generic.js +0 -427
  124. package/dist/analyzer/inspections/imperative.d.ts +0 -37
  125. package/dist/analyzer/inspections/imperative.js +0 -105
  126. package/dist/analyzer/inspections/logic.d.ts +0 -49
  127. package/dist/analyzer/inspections/logic.js +0 -140
  128. package/dist/analyzer/inspections/object.d.ts +0 -83
  129. package/dist/analyzer/inspections/object.js +0 -235
  130. package/dist/interpreter/components/FunctionRuntime.d.ts +0 -8
  131. package/dist/interpreter/components/FunctionRuntime.js +0 -52
  132. package/dist/interpreter/components/LazyRuntime.d.ts +0 -7
  133. package/dist/interpreter/components/LazyRuntime.js +0 -75
  134. package/dist/interpreter/components/LogicEngine.d.ts +0 -21
  135. package/dist/interpreter/components/LogicEngine.js +0 -152
  136. package/dist/interpreter/components/LogicResolver.d.ts +0 -11
  137. package/dist/interpreter/components/LogicResolver.js +0 -87
  138. package/src/analyzer/inspections/functional.ts +0 -159
  139. package/src/analyzer/inspections/imperative.ts +0 -129
  140. package/src/analyzer/inspections/logic.ts +0 -166
  141. package/src/interpreter/components/FunctionRuntime.ts +0 -79
  142. package/src/interpreter/components/LazyRuntime.ts +0 -97
  143. package/src/interpreter/components/LogicEngine.ts +0 -227
  144. package/src/interpreter/components/LogicResolver.ts +0 -130
@@ -0,0 +1,606 @@
1
+ import { expect } from "chai";
2
+ import {
3
+ PrimitiveValue,
4
+ RuntimeFunction,
5
+ UnguardedBody,
6
+ Sequence,
7
+ Return,
8
+ SymbolPrimitive,
9
+ NumberPrimitive,
10
+ VariablePattern,
11
+ RuntimeObject,
12
+ RuntimeClass,
13
+ StringPrimitive,
14
+ Primitive,
15
+ Super,
16
+ ArithmeticBinaryOperation,
17
+ EnvStack,
18
+ } from "yukigo-ast";
19
+ import { createGlobalEnv } from "../../src/interpreter/utils.js";
20
+ import {
21
+ Continuation,
22
+ idContinuation,
23
+ Thunk,
24
+ trampoline,
25
+ } from "../../src/interpreter/trampoline.js";
26
+ import { RuntimeContext } from "../../src/interpreter/components/RuntimeContext.js";
27
+
28
+ const createEmptyEnv = () => ({ head: new Map(), tail: null });
29
+
30
+ const createMethodMap = (
31
+ methods: RuntimeFunction[],
32
+ ): Map<string, RuntimeFunction> =>
33
+ new Map(methods.map((m) => [m.identifier, m]));
34
+ const createMethod = (name: string, returnVal: Primitive): RuntimeFunction => {
35
+ return {
36
+ type: "Function",
37
+ identifier: name,
38
+ arity: 0,
39
+ pendingArgs: [],
40
+ equations: [
41
+ {
42
+ patterns: [],
43
+ body: new UnguardedBody(new Sequence([new Return(returnVal)])),
44
+ },
45
+ ],
46
+ };
47
+ };
48
+
49
+ const createClass = (
50
+ name: string,
51
+ superclass?: string,
52
+ methodDefs: Map<string, RuntimeFunction> = new Map(),
53
+ mixins: string[] = [],
54
+ ): RuntimeClass => {
55
+ return {
56
+ type: "Class",
57
+ identifier: name,
58
+ fields: new Map(),
59
+ methods: methodDefs,
60
+ superclass,
61
+ mixins,
62
+ };
63
+ };
64
+
65
+ describe("ctx.objRuntime", () => {
66
+ let objectInstance: RuntimeObject;
67
+ const className = "TestClass";
68
+ const initialFields = new Map<string, PrimitiveValue>([
69
+ ["count", 10],
70
+ ["name", "Yukigo"],
71
+ ]);
72
+ const methods = new Map<string, RuntimeFunction>();
73
+ const classDef: RuntimeClass = {
74
+ type: "Class",
75
+ identifier: className,
76
+ fields: initialFields,
77
+ methods,
78
+ mixins: [],
79
+ superclass: undefined,
80
+ };
81
+ const env: EnvStack = createGlobalEnv();
82
+ env.head.set(className, classDef);
83
+ const ctx = new RuntimeContext();
84
+ ctx.setEnv(env);
85
+ beforeEach(() => {
86
+ objectInstance = ctx.objRuntime.instantiate(
87
+ className,
88
+ "obj",
89
+ initialFields,
90
+ methods,
91
+ );
92
+ });
93
+
94
+ describe("instantiate()", () => {
95
+ it("debe crear un objeto con la estructura correcta", () => {
96
+ expect(objectInstance.type).to.equal("Object");
97
+ expect(objectInstance.className).to.equal(className);
98
+ });
99
+
100
+ it("debe clonar el mapa de campos (no usar la referencia original)", () => {
101
+ const fieldsDef = new Map([["x", 1]]);
102
+ const obj = ctx.objRuntime.instantiate("A", "objA", fieldsDef, new Map());
103
+
104
+ fieldsDef.set("x", 2);
105
+
106
+ expect(obj.fields.get("x")).to.equal(1);
107
+ });
108
+ });
109
+
110
+ describe("Field Access (Get/Set)", () => {
111
+ it("getField debe devolver el valor de un campo existente", () => {
112
+ const val = ctx.objRuntime.getField(objectInstance, "count");
113
+ expect(val).to.equal(10);
114
+ });
115
+
116
+ it("getField debe lanzar error si el campo no existe", () => {
117
+ expect(() => {
118
+ ctx.objRuntime.getField(objectInstance, "non_existent");
119
+ }).to.throw(/Field 'non_existent' not found/);
120
+ });
121
+
122
+ it("getField debe lanzar error si el target no es un objeto", () => {
123
+ expect(() => {
124
+ ctx.objRuntime.getField(123 as any, "count");
125
+ }).to.throw(/Target is not an object/);
126
+ });
127
+
128
+ it("setField debe actualizar el valor de un campo existente", () => {
129
+ ctx.objRuntime.setField(objectInstance, "count", 20);
130
+ expect(objectInstance.fields.get("count")).to.equal(20);
131
+ });
132
+
133
+ it("setField debe lanzar error si intentas crear un campo nuevo (strict mode)", () => {
134
+ expect(() => {
135
+ ctx.objRuntime.setField(objectInstance, "newProp", 99);
136
+ }).to.throw(/Cannot set unknown field/);
137
+ });
138
+ });
139
+
140
+ describe("dispatch()", () => {
141
+ it("debe ejecutar un método que accede a 'self' (campos del objeto)", () => {
142
+ const getCountMethod: RuntimeFunction = {
143
+ type: "Function",
144
+ identifier: "getCount",
145
+ arity: 0,
146
+ pendingArgs: [],
147
+ equations: [
148
+ {
149
+ patterns: [],
150
+ body: new UnguardedBody(
151
+ new Sequence([new Return(new SymbolPrimitive("count"))]),
152
+ ),
153
+ },
154
+ ],
155
+ };
156
+
157
+ objectInstance.methods.set("getCount", getCountMethod);
158
+
159
+ const result = trampoline(
160
+ ctx.objRuntime.dispatch(
161
+ objectInstance,
162
+ "getCount",
163
+ [],
164
+ env,
165
+
166
+ idContinuation,
167
+ ),
168
+ );
169
+
170
+ expect(result).to.equal(10);
171
+ });
172
+
173
+ it("debe fallar si el método no existe", () => {
174
+ expect(() => {
175
+ trampoline(
176
+ ctx.objRuntime.dispatch(
177
+ objectInstance,
178
+ "unknownMethod",
179
+ [],
180
+ env,
181
+
182
+ idContinuation,
183
+ ),
184
+ );
185
+ }).to.throw(/does not understand 'unknownMethod'/);
186
+ });
187
+
188
+ it("debe fallar si el receiver no es un objeto", () => {
189
+ expect(() => {
190
+ trampoline(
191
+ ctx.objRuntime.dispatch(
192
+ "soy un string" as any,
193
+ "toString",
194
+ [],
195
+ createEmptyEnv() as any,
196
+
197
+ idContinuation,
198
+ ),
199
+ );
200
+ }).to.throw(/is not an object/);
201
+ });
202
+
203
+ it("debe permitir argumentos en el método", () => {
204
+ const returnArgAST = new Return(new SymbolPrimitive("val"));
205
+ const addMethod: RuntimeFunction = {
206
+ type: "Function",
207
+ identifier: "echo",
208
+ arity: 1,
209
+ pendingArgs: [],
210
+ equations: [
211
+ {
212
+ patterns: [new VariablePattern(new SymbolPrimitive("val"))],
213
+ body: new UnguardedBody(new Sequence([returnArgAST])),
214
+ },
215
+ ],
216
+ };
217
+
218
+ objectInstance.methods.set("echo", addMethod);
219
+
220
+ const result = trampoline(
221
+ ctx.objRuntime.dispatch(
222
+ objectInstance,
223
+ "echo",
224
+ [999],
225
+ env,
226
+
227
+ idContinuation,
228
+ ),
229
+ );
230
+
231
+ expect(result).to.equal(999);
232
+ });
233
+ });
234
+ describe("Method Lookup", () => {
235
+ it("debe delegar a la superclase si el método no está en la instancia ni en la clase", () => {
236
+ env.head.set(
237
+ "Animal",
238
+ createClass(
239
+ "Animal",
240
+ undefined,
241
+ createMethodMap([createMethod("speak", new StringPrimitive("Guau"))]),
242
+ ),
243
+ );
244
+ env.head.set("Perro", createClass("Perro", "Animal"));
245
+
246
+ const perro = ctx.objRuntime.instantiate(
247
+ "Perro",
248
+ "dogObj",
249
+ new Map(),
250
+ new Map(),
251
+ );
252
+
253
+ const res = trampoline(
254
+ ctx.objRuntime.dispatch(
255
+ perro,
256
+ "speak",
257
+ [],
258
+ env,
259
+
260
+ idContinuation,
261
+ ),
262
+ );
263
+ expect(res).to.equal("Guau");
264
+ });
265
+
266
+ it("debe subir múltiples niveles en la jerarquía (Abuelo -> Padre -> Hijo)", () => {
267
+ env.head.set(
268
+ "A",
269
+ createClass(
270
+ "A",
271
+ undefined,
272
+ createMethodMap([createMethod("id", new NumberPrimitive(1))]),
273
+ ),
274
+ );
275
+ env.head.set("B", createClass("B", "A"));
276
+ env.head.set("C", createClass("C", "B"));
277
+
278
+ const objC = ctx.objRuntime.instantiate(
279
+ "C",
280
+ "objC",
281
+ new Map(),
282
+ new Map(),
283
+ );
284
+ expect(
285
+ trampoline(
286
+ ctx.objRuntime.dispatch(
287
+ objC,
288
+ "id",
289
+ [],
290
+ env,
291
+
292
+ idContinuation,
293
+ ),
294
+ ),
295
+ ).to.equal(1);
296
+ });
297
+
298
+ it("debe encontrar métodos definidos en un Mixin", () => {
299
+ env.head.set(
300
+ "Volador",
301
+ createClass(
302
+ "Volador",
303
+ undefined,
304
+ createMethodMap([createMethod("volar", new StringPrimitive("Wosh"))]),
305
+ ),
306
+ );
307
+ env.head.set(
308
+ "Ave",
309
+ createClass("Ave", undefined, undefined, ["Volador"]),
310
+ );
311
+
312
+ const pepita = ctx.objRuntime.instantiate(
313
+ "Ave",
314
+ "birdObj",
315
+ new Map(),
316
+ new Map(),
317
+ );
318
+ expect(
319
+ trampoline(
320
+ ctx.objRuntime.dispatch(
321
+ pepita,
322
+ "volar",
323
+ [],
324
+ env,
325
+
326
+ idContinuation,
327
+ ),
328
+ ),
329
+ ).to.equal("Wosh");
330
+ });
331
+
332
+ it("debe soportar Mixines recursivos (Mixin incluye otro Mixin)", () => {
333
+ env.head.set(
334
+ "HabilidadA",
335
+ createClass(
336
+ "HabilidadA",
337
+ undefined,
338
+ createMethodMap([createMethod("skill", new StringPrimitive("Fire"))]),
339
+ ),
340
+ );
341
+ env.head.set(
342
+ "HabilidadB",
343
+ createClass("HabilidadB", undefined, undefined, ["HabilidadA"]),
344
+ );
345
+ env.head.set(
346
+ "Heroe",
347
+ createClass("Heroe", undefined, undefined, ["HabilidadB"]),
348
+ );
349
+
350
+ const heroe = ctx.objRuntime.instantiate(
351
+ "Heroe",
352
+ "heroObj",
353
+ new Map(),
354
+ new Map(),
355
+ );
356
+ expect(
357
+ trampoline(
358
+ ctx.objRuntime.dispatch(
359
+ heroe,
360
+ "skill",
361
+ [],
362
+ env,
363
+
364
+ idContinuation,
365
+ ),
366
+ ),
367
+ ).to.equal("Fire");
368
+ });
369
+
370
+ it("Prioridad: La Clase Propia gana a Mixines y Superclase", () => {
371
+ env.head.set(
372
+ "Super",
373
+ createClass(
374
+ "Super",
375
+ undefined,
376
+ createMethodMap([createMethod("val", new NumberPrimitive(1))]),
377
+ ),
378
+ );
379
+ env.head.set(
380
+ "Mixin",
381
+ createClass(
382
+ "Mixin",
383
+ undefined,
384
+ createMethodMap([createMethod("val", new NumberPrimitive(2))]),
385
+ ),
386
+ );
387
+
388
+ env.head.set(
389
+ "Child",
390
+ createClass(
391
+ "Child",
392
+ "Super",
393
+ createMethodMap([createMethod("val", new NumberPrimitive(3))]),
394
+ ["Mixin"],
395
+ ),
396
+ );
397
+
398
+ const child = ctx.objRuntime.instantiate(
399
+ "Child",
400
+ "childObj",
401
+ new Map(),
402
+ new Map(),
403
+ );
404
+ expect(
405
+ trampoline(
406
+ ctx.objRuntime.dispatch(
407
+ child,
408
+ "val",
409
+ [],
410
+ env,
411
+
412
+ idContinuation,
413
+ ),
414
+ ),
415
+ ).to.equal(3);
416
+ });
417
+
418
+ it("Prioridad: El Mixin gana a la Superclase", () => {
419
+ env.head.set(
420
+ "Super",
421
+ createClass(
422
+ "Super",
423
+ undefined,
424
+ createMethodMap([createMethod("val", new NumberPrimitive(1))]),
425
+ ),
426
+ );
427
+ env.head.set(
428
+ "Mixin",
429
+ createClass(
430
+ "Mixin",
431
+ undefined,
432
+ createMethodMap([createMethod("val", new NumberPrimitive(2))]),
433
+ ),
434
+ );
435
+ env.head.set(
436
+ "Child",
437
+ createClass("Child", "Super", undefined, ["Mixin"]),
438
+ );
439
+
440
+ const child = ctx.objRuntime.instantiate(
441
+ "Child",
442
+ "childObj",
443
+ new Map(),
444
+ new Map(),
445
+ );
446
+ expect(
447
+ trampoline(
448
+ ctx.objRuntime.dispatch(
449
+ child,
450
+ "val",
451
+ [],
452
+ env,
453
+
454
+ idContinuation,
455
+ ),
456
+ ),
457
+ ).to.equal(2);
458
+ });
459
+
460
+ it("Prioridad: El último Mixin de la lista gana (Shadowing de derecha a izquierda)", () => {
461
+ env.head.set(
462
+ "MixinA",
463
+ createClass(
464
+ "MixinA",
465
+ undefined,
466
+ createMethodMap([createMethod("val", new NumberPrimitive(10))]),
467
+ ),
468
+ );
469
+ env.head.set(
470
+ "MixinB",
471
+ createClass(
472
+ "MixinB",
473
+ undefined,
474
+ createMethodMap([createMethod("val", new NumberPrimitive(20))]),
475
+ ),
476
+ );
477
+
478
+ env.head.set(
479
+ "Clase",
480
+ createClass("Clase", undefined, undefined, ["MixinA", "MixinB"]),
481
+ );
482
+
483
+ const obj = ctx.objRuntime.instantiate(
484
+ "Clase",
485
+ "objC",
486
+ new Map(),
487
+ new Map(),
488
+ );
489
+ expect(
490
+ trampoline(
491
+ ctx.objRuntime.dispatch(
492
+ obj,
493
+ "val",
494
+ [],
495
+ env,
496
+
497
+ idContinuation,
498
+ ),
499
+ ),
500
+ ).to.equal(20);
501
+ });
502
+
503
+ it("Prioridad: Orden inverso de Mixines", () => {
504
+ env.head.set(
505
+ "MixinA",
506
+ createClass(
507
+ "MixinA",
508
+ undefined,
509
+ createMethodMap([createMethod("val", new NumberPrimitive(10))]),
510
+ ),
511
+ );
512
+ env.head.set(
513
+ "MixinB",
514
+ createClass(
515
+ "MixinB",
516
+ undefined,
517
+ createMethodMap([createMethod("val", new NumberPrimitive(20))]),
518
+ ),
519
+ );
520
+
521
+ env.head.set(
522
+ "Clase",
523
+ createClass("Clase", undefined, undefined, ["MixinB", "MixinA"]),
524
+ );
525
+
526
+ const obj = ctx.objRuntime.instantiate(
527
+ "Clase",
528
+ "obj",
529
+ new Map(),
530
+ new Map(),
531
+ );
532
+ expect(
533
+ trampoline(
534
+ ctx.objRuntime.dispatch(
535
+ obj,
536
+ "val",
537
+ [],
538
+ env,
539
+
540
+ idContinuation,
541
+ ),
542
+ ),
543
+ ).to.equal(10);
544
+ });
545
+ });
546
+ describe("Super", () => {
547
+ it("debe invocar al método de la superclase y operar con el resultado", () => {
548
+ env.head.set(
549
+ "Base",
550
+ createClass(
551
+ "Base",
552
+ undefined,
553
+ createMethodMap([createMethod("calc", new NumberPrimitive(10))]),
554
+ ),
555
+ );
556
+
557
+ const astBody = new UnguardedBody(
558
+ new Sequence([
559
+ new Return(
560
+ new ArithmeticBinaryOperation(
561
+ "Plus",
562
+ new Super([]),
563
+ new NumberPrimitive(5),
564
+ ),
565
+ ),
566
+ ]),
567
+ );
568
+
569
+ const methodHijo: RuntimeFunction = {
570
+ type: "Function",
571
+ identifier: "calc",
572
+ arity: 0,
573
+ pendingArgs: [],
574
+ equations: [
575
+ {
576
+ patterns: [],
577
+ body: astBody,
578
+ },
579
+ ],
580
+ };
581
+
582
+ const Hijo: RuntimeClass = {
583
+ type: "Class",
584
+ identifier: "Hijo",
585
+ fields: new Map(),
586
+ methods: new Map([["calc", methodHijo]]),
587
+ superclass: "Base",
588
+ mixins: [],
589
+ };
590
+ env.head.set("Hijo", Hijo);
591
+
592
+ const hijoInstance = ctx.objRuntime.instantiate(
593
+ "Hijo",
594
+ "childObj",
595
+ new Map(),
596
+ new Map(),
597
+ );
598
+
599
+ const result = trampoline(
600
+ ctx.objRuntime.dispatch(hijoInstance, "calc", [], env, idContinuation),
601
+ );
602
+
603
+ expect(result).to.equal(15);
604
+ });
605
+ });
606
+ });