Skip to content

Commit

Permalink
Merge pull request #313 from uqbar-project/fix-#302-assertion-errors
Browse files Browse the repository at this point in the history
Stack trace ante un error no reconoce el body de un método o test
  • Loading branch information
PalumboN authored Nov 26, 2024
2 parents 25de9db + 9d9a306 commit 5cfb448
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 35 deletions.
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 --parallel -r ts-node/register/transpile-only test/interpreter.test.ts",
"test:interpreter": "mocha -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
33 changes: 17 additions & 16 deletions src/interpreter/interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,47 +33,47 @@ abstract class AbstractInterpreter {
exec(node: Sentence): InterpreterResult<this, RuntimeValue>
exec(node: Node): InterpreterResult<this, void>
exec(node: Node): InterpreterResult<this, RuntimeValue | void> {
return this.do(function*() { return yield* this.exec(node) })
return this.do(function* () { return yield* this.exec(node) })
}

run(programOrTestFQN: Name): InterpreterResult<this, void> {
return this.exec(this.evaluation.environment.getNodeByFQN<Entity>(programOrTestFQN)) as any // TODO: avoid cast
}

send(message: Name, receiver: RuntimeObject, ...args: RuntimeObject[]): InterpreterResult<this, RuntimeValue> {
return this.do(function*() { return yield* this.send(message, receiver, ...args) })
return this.do(function* () { return yield* this.send(message, receiver, ...args) })
}

invoke(method: Method, receiver: RuntimeObject, ...args: RuntimeObject[]): InterpreterResult<this, RuntimeValue> {
return this.do(function*() { return yield* this.invoke(method, receiver, ...args) })
return this.do(function* () { return yield* this.invoke(method, receiver, ...args) })
}

reify(value: boolean | number | string | null): InterpreterResult<this, RuntimeObject> {
return this.do(function*() { return yield* this.reify(value) })
return this.do(function* () { return yield* this.reify(value) })
}

list(...value: RuntimeObject[]): InterpreterResult<this, RuntimeObject> {
return this.do(function*() { return yield* this.list(...value) })
return this.do(function* () { return yield* this.list(...value) })
}

set(...value: RuntimeObject[]): InterpreterResult<this, RuntimeObject> {
return this.do(function*() { return yield* this.set(...value) })
return this.do(function* () { return yield* this.set(...value) })
}

error(moduleOrFQN: Module | Name, locals?: Record<Name, RuntimeObject>, error?: Error): InterpreterResult<this, RuntimeObject> {
return this.do(function*() { return yield* this.error(moduleOrFQN, locals, error) })
return this.do(function* () { return yield* this.error(moduleOrFQN, locals, error) })
}

instantiate(moduleOrFQN: Module | Name, locals: Record<Name, RuntimeObject> = {}): InterpreterResult<this, RuntimeObject> {
return this.do(function*() { return yield* this.instantiate(moduleOrFQN, locals) })
return this.do(function* () { return yield* this.instantiate(moduleOrFQN, locals) })
}

}

export type ExecutionResult = {
result: string;
error?: Error;
errored: boolean;
result: string
error?: Error
errored: boolean
}

const failureResult = (message: string, error?: Error): ExecutionResult => ({
Expand All @@ -92,6 +92,7 @@ export const getStackTraceSanitized = (e?: Error): string[] => {
const fullStack = e?.stack?.slice(0, indexOfTsStack ?? -1) ?? ''

return fullStack
.replaceAll('\r', '')
.replaceAll('\t', ' ')
.replaceAll(' ', ' ')
.replaceAll(' ', ' ')
Expand All @@ -109,7 +110,7 @@ export class Interpreter extends AbstractInterpreter {
override do<T>(executionDefinition: ExecutionDefinition<T>): T {
const execution = executionDefinition.call(this.evaluation)
let next = execution.next()
while(!next.done) next = execution.next()
while (!next.done) next = execution.next()
return next.value as InterpreterResult<this, T>
}

Expand Down Expand Up @@ -204,17 +205,17 @@ export class ExecutionDirector<T> {
this.breakpoints.push(...nextBreakpoints)
}

finish(): ExecutionState<T> & {done: true} {
finish(): ExecutionState<T> & { done: true } {
let result = this.resume()
while(!result.done) result = this.resume()
while (!result.done) result = this.resume()
return result
}

resume(shouldHalt: (next: Node, evaluation: Evaluation) => boolean = () => false): ExecutionState<T> {
try {
let next = this.execution.next()
while(!next.done) {
if(this.breakpoints.includes(next.value) || shouldHalt(next.value, this.evaluation))
while (!next.done) {
if (this.breakpoints.includes(next.value) || shouldHalt(next.value, this.evaluation))
return { done: false, next: next.value }

next = this.execution.next()
Expand Down
7 changes: 3 additions & 4 deletions src/interpreter/runtimeModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,18 +138,17 @@ export class Frame extends Context {
[Entity, (node: Entity) => `${node.fullyQualifiedName}`],
// TODO: Add fqn to method
when(Method)(node => `${node.parent.fullyQualifiedName}.${node.name}(${node.parameters.map(parameter => parameter.name).join(', ')})`),
when(Send)(node => `${node.message}/${node.args.length}`),
when(Catch)(node => `catch(${node.parameter.name}: ${node.parameterType.name})`),
when(Environment)(() => 'root'),
otherwise((node: Node) => `${node.kind}`),
)
}

// TODO: On error report, this tells the node line, but not the actual error line.
// For example, an error on a test would say the test start line, not the line where the error occurred.
get sourceInfo(): string {
const target = this.node.is(Method) && this.node.name === CLOSURE_EVALUATE_METHOD
? this.node.parent
: this.node
? this.currentNode.parent
: this.currentNode
return target.sourceInfo
}

Expand Down
2 changes: 1 addition & 1 deletion test/game.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ describe('Wollok Game', () => {
interpreter.run('actions.genericError')
logs.should.be.deep.eq([
'wollok.lang.Exception: ERROR',
'\tat actions.genericError [actions.wpgm:33]'])
'\tat actions.genericError [actions.wpgm:37]'])
})

it('with file name game (devil test)', () => {
Expand Down
24 changes: 11 additions & 13 deletions test/interpreter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ describe('Wollok Interpreter', () => {
it('should be able to execute unlinked sentences', () => {
const environment = link([
new Package({
name:'p',
name: 'p',
members: [
new Singleton({
name: 'o',
Expand Down Expand Up @@ -81,7 +81,7 @@ describe('Wollok Interpreter', () => {
it('should fail if there is an uninitialized field in a singleton', () => {
const environment = link([
new Package({
name:'p',
name: 'p',
members: [
new Singleton({
name: 'o',
Expand All @@ -102,7 +102,7 @@ describe('Wollok Interpreter', () => {
it('should not fail if there is an explicit null initialization for a field in a singleton', () => {
const environment = link([
new Package({
name:'p',
name: 'p',
members: [
new Singleton({
name: 'o',
Expand Down Expand Up @@ -140,12 +140,10 @@ describe('Wollok Interpreter', () => {
describe('interpret API function', () => {
let interpreter: Interpreter

const expectError = (command: string, errorMessage: string) => {
const expectError = (command: string, ...errorMessage: string[]) => {
const { error } = interprete(interpreter, command)
assertBasicError(error)
expect(getStackTraceSanitized(error)).to.deep.equal([
errorMessage,
])
expect(getStackTraceSanitized(error)).to.deep.equal(errorMessage)
}

const checkSuccessfulResult = (expression: string, expectedResult: string) => {
Expand Down Expand Up @@ -479,7 +477,7 @@ describe('Wollok Interpreter', () => {
expect(getStackTraceSanitized(error)).to.deep.equal(
[
'wollok.lang.EvaluationError: RangeError: super call for message fly/1: parameter #1 produces no value, cannot use it',
' at REPL.MockingBird.fly(minutes) [REPL:10]',
' at REPL.MockingBird.fly(minutes) [REPL:11]',
]
)
})
Expand All @@ -503,7 +501,7 @@ describe('Wollok Interpreter', () => {
expect(getStackTraceSanitized(error)).to.deep.equal(
[
'wollok.lang.EvaluationError: RangeError: Message fly - if condition produces no value, cannot use it',
' at REPL.Bird.fly(minutes) [REPL:4]',
' at REPL.Bird.fly(minutes) [REPL:5]',
]
)
})
Expand Down Expand Up @@ -579,9 +577,9 @@ describe('Wollok Interpreter', () => {
assertBasicError(error)
expect(getStackTraceSanitized(error)).to.deep.equal([
'wollok.lang.EvaluationError: TypeError: Message plusDays: parameter "wollok.lang.Date" should be a number',
' at REPL.comun.despegar() [REPL:7]',
' at REPL.comun.volar() [REPL:3]',
' at REPL.Ave.volar() [REPL:16]',
' at REPL.comun.despegar() [REPL:8]',
' at REPL.comun.volar() [REPL:4]',
' at REPL.Ave.volar() [REPL:17]',
])
})

Expand All @@ -600,7 +598,7 @@ describe('Wollok Interpreter', () => {
assertBasicError(error)
expect(getStackTraceSanitized(error)).to.deep.equal([
'wollok.lang.EvaluationError: RangeError: Cannot send message +, receiver is an expression that produces no value.',
' at REPL.pepita.unMetodo() [REPL:3]',
' at REPL.pepita.unMetodo() [REPL:4]',
])
})

Expand Down

0 comments on commit 5cfb448

Please sign in to comment.