Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Debugger improvements #325

Merged
merged 8 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"test:game": "mocha --parallel -r ts-node/register/transpile-only test/**/game.test.ts",
"test:dynamicDiagram": "mocha --parallel -r ts-node/register/transpile-only test/dynamicDiagram.test.ts",
"test:helpers": "mocha --parallel -r ts-node/register/transpile-only test/helpers.test.ts",
"test:interpreter": "mocha -r ts-node/register/transpile-only test/interpreter.test.ts",
"test:interpreter": "mocha --parallel -r ts-node/register/transpile-only test/interpreter.test.ts",
"test:linker": "mocha --parallel -r ts-node/register/transpile-only test/linker.test.ts",
"test:messageReporter": "mocha --parallel -r ts-node/register/transpile-only test/messageReporter.test.ts",
"test:model": "mocha --parallel -r ts-node/register/transpile-only test/model.test.ts",
Expand Down
14 changes: 8 additions & 6 deletions src/interpreter/interpreter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { linkSentenceInNode } from '../linker'
import { Entity, Environment, Import, Method, Module, Name, Node, Reference, Sentence } from '../model'
import WRENatives from '../wre/wre.natives'
import { Evaluation, Execution, ExecutionDefinition, Natives, RuntimeObject, RuntimeValue, WollokException } from './runtimeModel'
import { Evaluation, Execution, ExecutionDefinition, Frame, Natives, RuntimeObject, RuntimeValue, WollokException } from './runtimeModel'
import * as parse from '../parser'
import { notEmpty } from '../extensions'
import { WOLLOK_EXTRA_STACK_TRACE_HEADER } from '../constants'
Expand Down Expand Up @@ -116,25 +116,27 @@ export class Interpreter extends AbstractInterpreter {

}

export function interprete(interpreter: Interpreter, line: string): ExecutionResult {
export function interprete(interpreter: AbstractInterpreter, line: string, frame?: Frame): ExecutionResult {
try {
const sentenceOrImport = parse.Import.or(parse.Variable).or(parse.Assignment).or(parse.Expression).tryParse(line)
const error = [sentenceOrImport, ...sentenceOrImport.descendants].flatMap(_ => _.problems ?? []).find(_ => _.level === 'error')
if (error) throw error

if (sentenceOrImport.is(Sentence)) {
const environment = interpreter.evaluation.environment
linkSentenceInNode(sentenceOrImport, environment.replNode())
linkSentenceInNode(sentenceOrImport, frame ? frame.node.parentPackage! : interpreter.evaluation.environment.replNode())
PalumboN marked this conversation as resolved.
Show resolved Hide resolved
const unlinkedNode = [sentenceOrImport, ...sentenceOrImport.descendants].find(_ => _.is(Reference) && !_.target)

if (unlinkedNode) {
if (unlinkedNode.is(Reference)) {
if (!interpreter.evaluation.currentFrame.get(unlinkedNode.name))
if (!(frame ?? interpreter.evaluation.currentFrame).get(unlinkedNode.name))
return failureResult(`Unknown reference ${unlinkedNode.name}`)
} else return failureResult(`Unknown reference at ${unlinkedNode.sourceInfo}`)
}

const result = interpreter.exec(sentenceOrImport)
const result = frame ?
interpreter.do(function () { return interpreter.evaluation.exec(sentenceOrImport, frame) }) :
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

me llamó la atención ver el function ahí en lugar de la lambda

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No tiene ningun motivo de ser 😅 , en esta situacion creo que no hay diferencia entre usar lambdas o funciones anonimas.

interpreter.exec(sentenceOrImport)

const stringResult = !result || isVoid(result)
? ''
: result.showShortValue(interpreter)
Expand Down
5 changes: 3 additions & 2 deletions src/linker.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { v4 as uuid } from 'uuid'
import { divideOn, is, List } from './extensions'
import { BaseProblem, Entity, Environment, Field, Id, Import, Level, Module, Name, Node, Package, Parameter, ParameterizedType, Reference, Scope, Sentence, SourceMap, Variable } from './model'
import { REPL } from './constants'
const { assign } = Object


Expand Down Expand Up @@ -67,7 +68,7 @@ export class LocalScope implements Scope {

register(...contributions: [Name, Node][]): void {
const shouldBeOverrided = (older: Node, newer: Node) => // Override wtest files with same name than wlk
older.is(Package) && newer.is(Package) && older.isTestFile && !newer.isTestFile
older.is(Package) && newer.is(Package) && !newer.isTestFile
PalumboN marked this conversation as resolved.
Show resolved Hide resolved
for (const [name, node] of contributions) {
const alreadyRegistered = this.contributions.get(name)
if (!alreadyRegistered || shouldBeOverrided(alreadyRegistered, node)) {
Expand Down Expand Up @@ -134,7 +135,7 @@ export default (newPackages: List<Package>, baseEnvironment?: Environment): Envi
const environment = new Environment({
id: uuid(),
scope: undefined,
members: newPackages.reduce(mergePackage, baseEnvironment?.members ?? []) as List<Package>,
members: newPackages.reduce(mergePackage, baseEnvironment?.members ?? [new Package({ name: REPL })]) as List<Package>,
}).transform(node => node.copy({ id: uuid() }))

const nodeCache = new Map<Id, Node>()
Expand Down
2 changes: 1 addition & 1 deletion src/validator/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,4 @@
"shouldUseOverrideKeyword": "Method should be marked as override, since it overrides a superclass method",
"shouldUseSelfAndNotSingletonReference": "Don't use the name within the object. Use 'self' instead.",
"superclassShouldBeLastInLinearization": "Bad Linearization: superclass should be last in linearization"
}
}
2 changes: 1 addition & 1 deletion src/validator/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,4 @@
"shouldUseOverrideKeyword": "Debería marcarse el método con 'override', ya que sobrescribe el de sus superclases",
"shouldUseSelfAndNotSingletonReference": "No debe usar el nombre del objeto dentro del mismo. Use 'self'.",
"superclassShouldBeLastInLinearization": "Linearización: la superclase debería estar última en linearización"
}
}
2 changes: 1 addition & 1 deletion src/wre/game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const game: Natives = {
// Avoid to invoke method position() for optimisation reasons.
// -> If method isSynthetic then it is a getter, we can access to the field directly
const method = visual.module.lookupMethod('position', 0)!
const otherPosition = method.isSynthetic ? visual.get('position') :yield* this.invoke(method, visual)
const otherPosition = method.isSynthetic ? visual.get('position') : yield* this.invoke(method, visual)

const otherX = otherPosition?.get('x')?.innerNumber
const otherY = otherPosition?.get('y')?.innerNumber
Expand Down
4 changes: 2 additions & 2 deletions test/assertions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { join } from 'path'
import { buildEnvironment as buildEnv, print } from '../src'
import { List } from '../src/extensions'
import link from '../src/linker'
import { Environment, Environment as EnvironmentType, Name, Node, Package, Reference, SourceIndex } from '../src/model'
import { Environment as EnvironmentType, Name, Node, Package, Reference, SourceIndex } from '../src/model'
import { ParseError } from '../src/parser'
import validate, { Validation } from '../src/validator'

Expand Down Expand Up @@ -145,7 +145,7 @@ export const linkerAssertions: Chai.ChaiPlugin = ({ Assertion }) => {
Assertion.addMethod('linkedInto', function (expected: List<Package>) {
const dropLinkedFields = dropKeys('id', 'scope')
const actualEnvironment = link(this._obj)
const expectedEnvironment = new Environment({ members: expected })
const expectedEnvironment = link(expected)

new Assertion(dropLinkedFields(actualEnvironment)).to.deep.equal(dropLinkedFields(expectedEnvironment))
})
Expand Down
30 changes: 13 additions & 17 deletions test/dynamicDiagram.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { BOOLEAN_MODULE, buildEnvironment, CLOSURE_MODULE, DATE_MODULE, DICTIONA
import { DynamicDiagramElement, DynamicDiagramNode, DynamicDiagramReference } from '../src/interpreter/dynamicDiagram'
import { interprete, Interpreter } from '../src/interpreter/interpreter'
import linker from '../src/linker'
import { WREEnvironment } from './utils'
import { environmentWithREPLInitializedFile, INIT_PACKAGE_NAME, WREEnvironment } from './utils'

describe('Dynamic diagram', () => {

Expand Down Expand Up @@ -245,8 +245,7 @@ describe('Dynamic diagram', () => {
})

it('should include bidirectional relationships', () => {
const replEnvironment = buildEnvironment([{
name: REPL, content: `
const replEnvironment = environmentWithREPLInitializedFile(`
class Ave {
var property amigue = null
method tieneEnergia() = energia > 0
Expand All @@ -255,8 +254,7 @@ describe('Dynamic diagram', () => {
object pepita inherits Ave {
override method tieneEnergia() = true
}
`,
}])
`)
interpreter = new Interpreter(Evaluation.build(replEnvironment, WRENatives))
interprete(interpreter, 'const pepona = new Ave(amigue = pepita)')
interprete(interpreter, 'pepita.amigue(pepona)')
Expand All @@ -265,36 +263,34 @@ describe('Dynamic diagram', () => {
referenceLabel: 'pepona',
targetLabel: 'Ave',
targetType: 'object',
targetModule: 'REPL.Ave',
targetModule: INIT_PACKAGE_NAME + '.Ave',
})
checkConnection(elements, {
sourceLabel: 'Ave',
referenceLabel: 'amigue',
targetLabel: 'pepita',
targetType: 'object',
sourceModule: 'REPL.Ave',
targetModule: 'REPL.pepita',
sourceModule: INIT_PACKAGE_NAME + '.Ave',
targetModule: INIT_PACKAGE_NAME + '.pepita',
})
checkConnection(elements, {
sourceLabel: 'pepita',
referenceLabel: 'amigue',
targetLabel: 'Ave',
targetType: 'object',
sourceModule: 'REPL.pepita',
targetModule: 'REPL.Ave',
sourceModule: INIT_PACKAGE_NAME + '.pepita',
targetModule: INIT_PACKAGE_NAME + '.Ave',
})
checkNoConnectionToREPL(elements, 'pepita')
})

it('should include recursive relationships', () => {
const replEnvironment = buildEnvironment([{
name: REPL, content: `
const replEnvironment = environmentWithREPLInitializedFile(`
class Ave {
var property amigue = null
override method tieneEnergia() = true
}
`,
}])
`)
interpreter = new Interpreter(Evaluation.build(replEnvironment, WRENatives))
interprete(interpreter, 'const pepita = new Ave()')
interprete(interpreter, 'pepita.amigue(pepita)')
Expand All @@ -303,15 +299,15 @@ describe('Dynamic diagram', () => {
referenceLabel: 'pepita',
targetLabel: 'Ave',
targetType: 'object',
targetModule: 'REPL.Ave',
targetModule: INIT_PACKAGE_NAME + '.Ave',
})
checkConnection(elements, {
sourceLabel: 'Ave',
referenceLabel: 'amigue',
targetLabel: 'Ave',
targetType: 'object',
sourceModule: 'REPL.Ave',
targetModule: 'REPL.Ave',
sourceModule: INIT_PACKAGE_NAME + '.Ave',
targetModule: INIT_PACKAGE_NAME + '.Ave',
})

})
Expand Down
16 changes: 7 additions & 9 deletions test/helpers.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect, should, use } from 'chai'
import sinonChai from 'sinon-chai'
import { BOOLEAN_MODULE, Body, Class, Describe, Environment, Evaluation, Field, Import, Interpreter, isError, LIST_MODULE, Literal, Method, methodByFQN, NUMBER_MODULE, New, OBJECT_MODULE, Package, Parameter, Reference, STRING_MODULE, Self, Send, Singleton, Test, Variable, WRENatives, allAvailableMethods, allScopedVariables, allVariables, implicitImport, isNamedSingleton, isNotImportedIn, link, linkSentenceInNode, literalValueToClass, mayExecute, parentModule, parse, projectPackages, hasNullValue, hasBooleanValue, projectToJSON, getNodeDefinition, ParameterizedType, sendDefinitions, Super, SourceMap, isVoid, VOID_WKO, REPL, buildEnvironment, assertNotVoid, showParameter, getMethodContainer, Program, getExpressionFor, Expression, If, Return } from '../src'
import { WREEnvironment, environmentWithEntities } from './utils'
import { WREEnvironment, environmentWithEntities, environmentWithREPLInitializedFile } from './utils'
import { RuntimeObject } from '../src/interpreter/runtimeModel'

use(sinonChai)
Expand Down Expand Up @@ -131,10 +131,10 @@ describe('Wollok helpers', () => {

it('should return the right package from an environment', () => {
const environment = basicEnvironmentWithSingleClass()
const mainPackage = environment.getNodeByFQN('aves')
projectPackages(environment).should.deep.equal([mainPackage])
const mainPackage = environment.getNodeByFQN<Package>('aves')
projectPackages(environment).includes(mainPackage)
projectPackages(environment).includes(environment.replNode())
})

})

describe('isNotImportedIn', () => {
Expand Down Expand Up @@ -894,8 +894,7 @@ describe('Wollok helpers', () => {
})

describe('getExpression', () => {
const replEnvironment = buildEnvironment([{
name: REPL, content: `
const replEnvironment = environmentWithREPLInitializedFile(`
object pajarito {
energia = 100
contenta = false
Expand All @@ -916,9 +915,8 @@ describe('Wollok helpers', () => {
method bad() {
throw new Exception(message = "Do not call me!")
}
}`,
},
])
}`
)

it('should show if expression', () => {
const birdSingleton = replEnvironment.getNodeByFQN(REPL + '.pajarito') as Singleton
Expand Down
Loading
Loading