diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 969ade3f..c3d28467 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -12,9 +12,9 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: webfactory/ssh-agent@v0.8.0 - with: - ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + # - uses: webfactory/ssh-agent@v0.8.0 + # with: + # ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} - name: Read .nvmrc run: echo "##[set-output name=NVMRC;]$(cat .nvmrc)" id: nvm diff --git a/scripts/fetchLanguage.ts b/scripts/fetchLanguage.ts index f4cc70c5..a5815592 100644 --- a/scripts/fetchLanguage.ts +++ b/scripts/fetchLanguage.ts @@ -2,7 +2,7 @@ import { existsSync, mkdirSync } from 'fs' import gitClient from 'simple-git' import { wollokVersion } from '../package.json' -const WOLLOK_LANGUAGE_REPO = 'git@github.com:uqbar-project/wollok-language.git' +const WOLLOK_LANGUAGE_REPO = 'https://github.com/uqbar-project/wollok-language.git' const WOLLOK_LANGUAGE_TAG = wollokVersion.includes(':') ? wollokVersion.split(':')[1] : `v${wollokVersion}` const WOLLOK_LANGUAGE_FOLDER = 'language' 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/src/validator/index.ts b/src/validator/index.ts index 24d3f2b6..a5856017 100644 --- a/src/validator/index.ts +++ b/src/validator/index.ts @@ -156,7 +156,7 @@ export const shouldOnlyInheritFromMixin = error(node => node.supertypes.e })) export const shouldUseOverrideKeyword = warning(node => - node.isOverride || !superclassMethod(node) || node.name == INITIALIZE_METHOD + node.isOverride || node.isSynthetic || !superclassMethod(node) || node.name == INITIALIZE_METHOD ) export const possiblyReturningBlock = warning(node => { diff --git a/test/interpreter.test.ts b/test/interpreter.test.ts index 1f82c996..bbe0dd40 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({