uqbar-project / wollok

Wollok Programming Language
GNU General Public License v3.0
60 stars 16 forks source link

Short-circuit fails to evaluate right part #622

Closed javierfernandes closed 8 years ago

javierfernandes commented 8 years ago

This program

            object liberarAFiona {
                var cantidadTrolls = 0
                var solicitante = ""

                method solicitante() = return solicitante
                method solicitante(_solicitante) { solicitante = _solicitante }
                method cantidadTrolls(cant) { cantidadTrolls = cant }
                method esDificil() {
                    const result = (cantidadTrolls > 3) and (cantidadTrolls < 6)
                    console.println(result)
                    return result
                }
                method puntosRecompensa() = return cantidadTrolls * 2
            }
            program a {
                liberarAFiona.cantidadTrolls(5)
                liberarAFiona.esDificil()
            }

Fails with

java.lang.AssertionError: Error evaluating line __synthetic0.wpgm:[9]: (cantidadTrolls < 6)
wollok.lang.Exception: Error evaluating line __synthetic0.wpgm:[9]: (cantidadTrolls < 6)
    at __synthetic0.liberarAFiona.esDificil() [__synthetic0.wpgm]
    at __synthetic0.liberarAFiona.esDificil() [__synthetic0.wpgm]
    at  [__synthetic0.wpgm]

    at org.junit.Assert.fail(Assert.java:88)
    at org.uqbar.project.wollok.tests.interpreter.AbstractWollokInterpreterTestCase.lambda$7(AbstractWollokInterpreterTestCase.java:173)
    at org.uqbar.project.wollok.tests.interpreter.AbstractWollokInterpreterTestCase$$Lambda$42/1103234208.accept(Unknown Source)
    at java.lang.Iterable.forEach(Iterable.java:75)
    at org.uqbar.project.wollok.tests.interpreter.AbstractWollokInterpreterTestCase.lambda$5(AbstractWollokInterpreterTestCase.java:180)
    at org.uqbar.project.wollok.tests.interpreter.AbstractWollokInterpreterTestCase$$Lambda$2/1123236701.apply(Unknown Source)
    at org.eclipse.xtext.xbase.lib.ObjectExtensions.operator_doubleArrow(ObjectExtensions.java:139)
    at org.uqbar.project.wollok.tests.interpreter.AbstractWollokInterpreterTestCase.interpret(AbstractWollokInterpreterTestCase.java:182)
    at org.uqbar.project.wollok.tests.interpreter.AbstractWollokInterpreterTestCase.interpret(AbstractWollokInterpreterTestCase.java:138)
    at org.uqbar.project.wollok.tests.interpreter.AbstractWollokInterpreterTestCase.interpret(AbstractWollokInterpreterTestCase.java:134)
    at org.uqbar.project.wollok.tests.interpreter.AbstractWollokInterpreterTestCase.interpretPropagatingErrors(AbstractWollokInterpreterTestCase.java:102)
    at org.uqbar.project.wollok.tests.interpreter.AbstractWollokInterpreterTestCase.interpretPropagatingErrors(AbstractWollokInterpreterTestCase.java:90)
    at org.uqbar.project.wollok.tests.interpreter.BooleanTestCase.andShortcircuitBug(BooleanTestCase.java:247)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.eclipse.xtext.junit4.XtextRunner$1.evaluate(XtextRunner.java:49)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
javierfernandes commented 8 years ago

This is the inner cause VM exception that is being hidden (probably by a bad exception handling)

Warning: NLS unused message: CheckGroup_DEFAULT_GROUP in: org.uqbar.project.wollok.messages
Warning: NLS unused message: CheckGroup_CODE_STYLE in: org.uqbar.project.wollok.messages
Warning: NLS unused message: CheckGroup_POTENTIAL_PROGRAMMING_PROBLEM in: org.uqbar.project.wollok.messages
org.uqbar.project.wollok.interpreter.WollokInterpreterException: Error evaluating line __synthetic0.wpgm:[9]: cantidadTrolls
    at org.uqbar.project.wollok.interpreter.WollokInterpreter.eval(WollokInterpreter.java:245)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator.eval(WollokInterpreterEvaluator.java:131)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator._evaluate(WollokInterpreterEvaluator.java:659)
    at org.uqbar.project.wollok.launch.WollokLauncherInterpreterEvaluator.evaluate(WollokLauncherInterpreterEvaluator.java:165)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator.evaluate(WollokInterpreterEvaluator.java:1)
    at org.uqbar.project.wollok.interpreter.WollokInterpreter.eval(WollokInterpreter.java:233)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator.eval(WollokInterpreterEvaluator.java:131)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator.lambda$10(WollokInterpreterEvaluator.java:670)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator$$Lambda$66/1547965072.apply(Unknown Source)
    at org.uqbar.project.wollok.interpreter.core.LazyWollokObject.eval(LazyWollokObject.java:49)
    at wollok.lang.WBoolean.apply(WBoolean.java:46)
    at wollok.lang.WBoolean.and(WBoolean.java:26)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.uqbar.project.wollok.ui.utils.XTendUtilExtensions.invokeConvertingArgs(XTendUtilExtensions.java:389)
    at org.uqbar.project.wollok.interpreter.AbstractWollokCallable._invokeNative(AbstractWollokCallable.java:115)
    at org.uqbar.project.wollok.interpreter.AbstractWollokCallable.invokeNative(AbstractWollokCallable.java:209)
    at org.uqbar.project.wollok.interpreter.AbstractWollokCallable.lambda$0(AbstractWollokCallable.java:76)
    at org.uqbar.project.wollok.interpreter.AbstractWollokCallable$$Lambda$62/225511870.apply(Unknown Source)
    at org.uqbar.project.wollok.interpreter.WollokInterpreter.performOnStack(WollokInterpreter.java:193)
    at org.uqbar.project.wollok.interpreter.AbstractWollokCallable.call(AbstractWollokCallable.java:98)
    at org.uqbar.project.wollok.interpreter.core.WollokObject.call(WollokObject.java:114)
    at org.uqbar.project.wollok.interpreter.operation.WollokDeclarativeNativeBasicOperations.andOperation(WollokDeclarativeNativeBasicOperations.java:218)
    at org.uqbar.project.wollok.interpreter.operation.WollokDeclarativeNativeBasicOperations.andPhrase(WollokDeclarativeNativeBasicOperations.java:232)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.uqbar.project.wollok.interpreter.operation.WollokDeclarativeNativeBasicOperations$2.apply(WollokDeclarativeNativeBasicOperations.java:62)
    at org.uqbar.project.wollok.interpreter.operation.WollokDeclarativeNativeBasicOperations$2.apply(WollokDeclarativeNativeBasicOperations.java:1)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator._evaluate(WollokInterpreterEvaluator.java:662)
    at org.uqbar.project.wollok.launch.WollokLauncherInterpreterEvaluator.evaluate(WollokLauncherInterpreterEvaluator.java:165)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator.evaluate(WollokInterpreterEvaluator.java:1)
    at org.uqbar.project.wollok.interpreter.WollokInterpreter.eval(WollokInterpreter.java:233)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator.eval(WollokInterpreterEvaluator.java:131)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator._evaluate(WollokInterpreterEvaluator.java:202)
    at org.uqbar.project.wollok.launch.WollokLauncherInterpreterEvaluator.evaluate(WollokLauncherInterpreterEvaluator.java:199)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator.evaluate(WollokInterpreterEvaluator.java:1)
    at org.uqbar.project.wollok.interpreter.WollokInterpreter.eval(WollokInterpreter.java:233)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator.eval(WollokInterpreterEvaluator.java:131)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator.lambda$0(WollokInterpreterEvaluator.java:136)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator$$Lambda$45/649848324.apply(Unknown Source)
    at org.eclipse.xtext.xbase.lib.IteratorExtensions.fold(IteratorExtensions.java:627)
    at org.eclipse.xtext.xbase.lib.IterableExtensions.fold(IterableExtensions.java:536)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator.evalAll(WollokInterpreterEvaluator.java:138)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator._evaluate(WollokInterpreterEvaluator.java:623)
    at org.uqbar.project.wollok.launch.WollokLauncherInterpreterEvaluator.evaluate(WollokLauncherInterpreterEvaluator.java:167)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator.evaluate(WollokInterpreterEvaluator.java:1)
    at org.uqbar.project.wollok.interpreter.WollokInterpreter.eval(WollokInterpreter.java:233)
    at org.uqbar.project.wollok.interpreter.AbstractWollokCallable.eval(AbstractWollokCallable.java:130)
    at org.uqbar.project.wollok.interpreter.AbstractWollokCallable.lambda$0(AbstractWollokCallable.java:86)
    at org.uqbar.project.wollok.interpreter.AbstractWollokCallable$$Lambda$62/225511870.apply(Unknown Source)
    at org.uqbar.project.wollok.interpreter.WollokInterpreter.performOnStack(WollokInterpreter.java:193)
    at org.uqbar.project.wollok.interpreter.AbstractWollokCallable.call(AbstractWollokCallable.java:98)
    at org.uqbar.project.wollok.interpreter.core.WollokObject.call(WollokObject.java:114)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator._evaluate(WollokInterpreterEvaluator.java:742)
    at org.uqbar.project.wollok.launch.WollokLauncherInterpreterEvaluator.evaluate(WollokLauncherInterpreterEvaluator.java:207)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator.evaluate(WollokInterpreterEvaluator.java:1)
    at org.uqbar.project.wollok.interpreter.WollokInterpreter.eval(WollokInterpreter.java:233)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator.eval(WollokInterpreterEvaluator.java:131)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator.lambda$0(WollokInterpreterEvaluator.java:136)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator$$Lambda$45/649848324.apply(Unknown Source)
    at org.eclipse.xtext.xbase.lib.IteratorExtensions.fold(IteratorExtensions.java:627)
    at org.eclipse.xtext.xbase.lib.IterableExtensions.fold(IterableExtensions.java:536)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator.evalAll(WollokInterpreterEvaluator.java:138)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator._evaluate(WollokInterpreterEvaluator.java:180)
    at org.uqbar.project.wollok.launch.WollokLauncherInterpreterEvaluator.evaluate(WollokLauncherInterpreterEvaluator.java:211)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator.evaluate(WollokInterpreterEvaluator.java:1)
    at org.uqbar.project.wollok.interpreter.WollokInterpreter.eval(WollokInterpreter.java:233)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator.eval(WollokInterpreterEvaluator.java:131)
    at org.uqbar.project.wollok.launch.WollokLauncherInterpreterEvaluator._evaluate(WollokLauncherInterpreterEvaluator.java:68)
    at org.uqbar.project.wollok.launch.WollokLauncherInterpreterEvaluator.evaluate(WollokLauncherInterpreterEvaluator.java:209)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator.evaluate(WollokInterpreterEvaluator.java:1)
    at org.uqbar.project.wollok.interpreter.WollokInterpreter.interpret(WollokInterpreter.java:149)
    at org.uqbar.project.wollok.tests.interpreter.AbstractWollokInterpreterTestCase.lambda$7(AbstractWollokInterpreterTestCase.java:160)
    at org.uqbar.project.wollok.tests.interpreter.AbstractWollokInterpreterTestCase$$Lambda$42/1147545255.accept(Unknown Source)
    at java.lang.Iterable.forEach(Iterable.java:75)
    at org.uqbar.project.wollok.tests.interpreter.AbstractWollokInterpreterTestCase.lambda$5(AbstractWollokInterpreterTestCase.java:180)
    at org.uqbar.project.wollok.tests.interpreter.AbstractWollokInterpreterTestCase$$Lambda$2/1566099239.apply(Unknown Source)
    at org.eclipse.xtext.xbase.lib.ObjectExtensions.operator_doubleArrow(ObjectExtensions.java:139)
    at org.uqbar.project.wollok.tests.interpreter.AbstractWollokInterpreterTestCase.interpret(AbstractWollokInterpreterTestCase.java:182)
    at org.uqbar.project.wollok.tests.interpreter.AbstractWollokInterpreterTestCase.interpret(AbstractWollokInterpreterTestCase.java:138)
    at org.uqbar.project.wollok.tests.interpreter.AbstractWollokInterpreterTestCase.interpret(AbstractWollokInterpreterTestCase.java:134)
    at org.uqbar.project.wollok.tests.interpreter.AbstractWollokInterpreterTestCase.interpretPropagatingErrors(AbstractWollokInterpreterTestCase.java:102)
    at org.uqbar.project.wollok.tests.interpreter.AbstractWollokInterpreterTestCase.interpretPropagatingErrors(AbstractWollokInterpreterTestCase.java:90)
    at org.uqbar.project.wollok.tests.interpreter.BooleanTestCase.andShortcircuitBug(BooleanTestCase.java:247)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.eclipse.xtext.junit4.XtextRunner$1.evaluate(XtextRunner.java:49)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: org.uqbar.project.wollok.interpreter.context.UnresolvableReference: Cannot resolve reference cantidadTrolls
    at org.uqbar.project.wollok.interpreter.core.WollokNativeLobby.resolve(WollokNativeLobby.java:74)
    at org.uqbar.project.wollok.interpreter.core.WollokNativeLobby.resolve(WollokNativeLobby.java:1)
    at org.uqbar.project.wollok.interpreter.core.WollokObject.resolve(WollokObject.java:271)
    at org.uqbar.project.wollok.interpreter.core.WollokObject.resolve(WollokObject.java:1)
    at org.uqbar.project.wollok.interpreter.context.CompositeEvaluationContext.resolve(CompositeEvaluationContext.java:60)
    at org.uqbar.project.wollok.interpreter.core.WollokObject.resolve(WollokObject.java:271)
    at org.uqbar.project.wollok.interpreter.core.WollokObject.resolve(WollokObject.java:1)
    at org.uqbar.project.wollok.interpreter.context.CompositeEvaluationContext.resolve(CompositeEvaluationContext.java:60)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator._evaluate(WollokInterpreterEvaluator.java:219)
    at org.uqbar.project.wollok.launch.WollokLauncherInterpreterEvaluator.evaluate(WollokLauncherInterpreterEvaluator.java:201)
    at org.uqbar.project.wollok.interpreter.WollokInterpreterEvaluator.evaluate(WollokInterpreterEvaluator.java:1)
    at org.uqbar.project.wollok.interpreter.WollokInterpreter.eval(WollokInterpreter.java:233)
    ... 113 more
javierfernandes commented 8 years ago

Ok, this is heavy. Basically the problem is in the way I've implemented the shortcirtuit. Shortcircuit means that the second part of the binary operator ("and" or "or") in this case, needs to have a special treatment , like a lazy expression. We don't have that in any other place in the language, so it was implemented "not in the best way" let say.

Basically there's an indirection to evaluate the second part of the operation. And if needed then it gets intepreted.

The problem is that when the interpreter interprets the second part of the operation the current stack context is not context of the method where the "and" expression was declared, instead the current context is the boolean object, result of applying the first part of the operation. Since "and" and "or" are just messages in the "true" / "false" objects.

Therefore it cannot resolve references.

Example:

object Pepe {
 var edad

 method blah() {    return (1>0) and (edad > 10) }
}

In this case the first part evaluates to true (1>0), the object "true". Then we send the message "and" to the object "true". Sending a message means executing a method. Executing a method means changing the current stack peak. Now the current context is the object "true". Then "and" implementation tries to evaluate the second part (edad > 10) so it tries to access the variable "edad" on the "true" object, and not on "pepe". Then it fails.

I need to think of a way to solve this :S

javierfernandes commented 8 years ago

Eventually we could do a refactor to model booleans as WKO's like this

    object true inherits Boolean {
        override method and(lazy other) = other
        override method or(lazy other) = this

        method toString() { 'true' }
        method negate() = false
    }

    object false inherits Boolean {
        override method and(lazy other) = this
        override method or(lazy other) = other

        override method toString() { 'false' }
        override method negate() = true
    }

This needs a new feature at syntax level to specify that a given parameter is lazy. Then this is transparent for the method implementation code. The interpreter will evaluate the parameter once it is needed on the first time (this could be part of the evaluation context logic and not on every lazy method implementation.

Now this needs a not-so-trivial refactor. I would see if there is a way to workaround it for the moment

javierfernandes commented 8 years ago

Fixed in 1.4.1