diff --git a/src/linker.ts b/src/linker.ts index 75dfe767..c23ac82d 100644 --- a/src/linker.ts +++ b/src/linker.ts @@ -92,7 +92,6 @@ export const assignScopes = (root: Node): void => { ? parent?.parent.scope : parent?.scope assign(node, { scope: new LocalScope(containerScope) }) - parent?.scope?.register(...scopeContribution(node)) }) @@ -116,7 +115,9 @@ export const assignScopes = (root: Node): void => { node.scope.include(new LocalScope(undefined, ...contributions)) } } + }) + root.forEach((node, _parent) => { if (node.is(Module)) { node.scope.include(...node.hierarchy.slice(1).map(supertype => supertype.scope)) } diff --git a/test/interpreter.test.ts b/test/interpreter.test.ts index a514b68c..a9d9b7e2 100644 --- a/test/interpreter.test.ts +++ b/test/interpreter.test.ts @@ -2,7 +2,7 @@ import { expect, should, use } from 'chai' import { restore } from 'sinon' import sinonChai from 'sinon-chai' import { EXCEPTION_MODULE, Evaluation, REPL, WRENatives, buildEnvironment } from '../src' -import { DirectedInterpreter, interprete, Interpreter, getStackTraceSanitized } from '../src/interpreter/interpreter' +import { DirectedInterpreter, getStackTraceSanitized, interprete, Interpreter } from '../src/interpreter/interpreter' import link from '../src/linker' import { Body, Class, Field, Literal, Method, Package, ParameterizedType, Reference, Return, Send, Singleton, SourceIndex, SourceMap } from '../src/model' import { WREEnvironment } from './utils' @@ -270,6 +270,134 @@ describe('Wollok Interpreter', () => { it('for closure', () => { checkSuccessfulResult('{1 + 2}', '{1 + 2}') }) + + it('should be able to execute sentences related to a hierarchy defined in different packages', () => { + const replEnvironment = buildEnvironment([{ + name: 'jefeDeDepartamento.wlk', content: ` + import medico.* + + class Jefe inherits Medico { + const subordinados = #{} + + override method atenderA(unaPersona) { + subordinados.anyOne().atenderA(unaPersona) + } + } + `, + }, { + name: 'medico.wlk', content: ` + import persona.* + + class Medico inherits Persona { + const dosis + + override method contraerEnfermedad(unaEnfermedad) { + super(unaEnfermedad) + self.atenderA(self) + } + method atenderA(unaPersona) { + unaPersona.recibirMedicamento(dosis) + } + + } + `, + }, { + name: 'persona.wlk', content: ` + class Persona { + const enfermedades = [] + + method contraerEnfermedad(unaEnfermedad) { + + enfermedades.add(unaEnfermedad) + } + + method saludar() = "hola" + } + `, + }, { + name: REPL, content: ` + import medico.* + + object testit { + method test() = new Medico(dosis = 200).saludar() + } + `, + }]) + interpreter = new Interpreter(Evaluation.build(replEnvironment, WRENatives)) + const { error, result } = interprete(interpreter, 'testit.test()') + expect(error).to.be.undefined + expect(result).to.equal('"hola"') + }) + + it('should be able to execute sentences related to a hierarchy defined in different packages - 2', () => { + const replEnvironment = buildEnvironment([{ + name: 'medico.wlk', content: ` + import persona.* + + class Medico inherits Persona { + const dosis + + override method contraerEnfermedad(unaEnfermedad) { + super(unaEnfermedad) + self.atenderA(self) + } + + method atenderA(unaPersona) { + unaPersona.recibirMedicamento(dosis) + } + + } + `, + }, { + name: 'pediatra.wlk', content: ` + import jefeDeDepartamento.* + + class Pediatra inherits Jefe { + const property fechaIngreso = new Date() + + method esNuevo() = fechaIngreso.year() < 2022 + } + `, + }, { + name: 'jefeDeDepartamento.wlk', content: ` + import medico.* + + class Jefe inherits Medico { + const subordinados = #{} + + override method atenderA(unaPersona) { + subordinados.anyOne().atenderA(unaPersona) + } + } + `, + }, { + name: 'persona.wlk', content: ` + class Persona { + const enfermedades = [] + + method contraerEnfermedad(unaEnfermedad) { + + enfermedades.add(unaEnfermedad) + } + + method saludar() = "hola" + } + `, + }, { + name: REPL, content: ` + import pediatra.* + + object testit { + method test() = new Pediatra(dosis = 200).saludar() + } + `, + }]) + interpreter = new Interpreter(Evaluation.build(replEnvironment, WRENatives)) + const { error, result } = interprete(interpreter, 'testit.test()') + expect(error).to.be.undefined + expect(result).to.equal('"hola"') + }) + }) describe('sanitize stack trace', () => { diff --git a/test/linker.test.ts b/test/linker.test.ts index 922da80e..c960b66e 100644 --- a/test/linker.test.ts +++ b/test/linker.test.ts @@ -2,7 +2,7 @@ import { expect, should, use } from 'chai' import { GAME_MODULE, OBJECT_MODULE } from '../src' import { getPotentiallyUninitializedLazy } from '../src/decorators' import link, { canBeReferenced, linkSentenceInNode } from '../src/linker' -import { Body, Class, Closure, Describe, Environment, Field, Import, Method, Mixin, NamedArgument, Node, Package, Parameter, ParameterizedType, Reference, Return, Sentence, Singleton, Test, Variable } from '../src/model' +import { Body, Class, Closure, Describe, Environment, Field, Import, Method, Mixin, NamedArgument, Node, Package, Parameter, ParameterizedType, Reference, Return, Sentence, Singleton, Test, Variable, Literal } from '../src/model' import * as parse from '../src/parser' import { linkerAssertions } from './assertions' import { environmentWithEntities, WREEnvironment } from './utils' @@ -464,6 +464,65 @@ describe('Wollok linker', () => { C.methods[0].sentences[0].should.target(C.fields[0]) }) + it('should target references to members inherited from superclass in different packages', () => { + const environment = link([ + new Package({ + name: 'aaa', + imports: [ + new Import({ isGeneric: true, entity: new Reference({ name: 'bbb' }) }), + ], + members: [ + new Class({ + name: 'C', + supertypes: [new ParameterizedType({ reference: new Reference({ name: 'B' }) })], + members: [ + new Method({ + name: 'm2', + body: new Body({ sentences: [new Literal({ value: '2' })] }), + }), + ], + }), + ], + }), + new Package({ + name: 'bbb', + imports: [ + new Import({ isGeneric: true, entity: new Reference({ name: 'zzz' }) }), + ], + members: [ + new Class({ + name: 'B', + supertypes: [new ParameterizedType({ reference: new Reference({ name: 'A' }) })], + members: [ + new Method({ + name: 'm', + body: new Body({ sentences: [new Reference({ name: 'x' })] }), + }), + ], + }), + ], + }), + new Package({ + name: 'zzz', + members: [ + new Class({ + name: 'A', members: [ + new Field({ name: 'x', isConstant: false }), + ], + }), + ], + }), + ], WREEnvironment) + + const C = environment.getNodeByFQN('aaa.C') + const B = environment.getNodeByFQN('bbb.B') + const A = environment.getNodeByFQN('zzz.A') + + C.supertypes[0].reference.should.target(B) + B.supertypes[0].reference.should.target(A) + B.methods[0].sentences[0].should.target(A.fields[0]) + }) + it('should target references overriden on mixins to members inherited from superclass', () => { const environment = link([ new Package({