RPTools / parser

MapTool Macro Parser

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

InlineTreeFormatter fails to format expressions with logical operators

nmeier opened this issue · comments

The parser's InlineTreeFormatter fails to format expressions with logical operations, like ==, with a NPE.


new Parser().parseExpression('1 == 1').format()
java.lang.NullPointerException
	at net.rptools.parser.InlineTreeFormatter.format(InlineTreeFormatter.java:86)
	at net.rptools.parser.InlineTreeFormatter.format(InlineTreeFormatter.java:51)
	at net.rptools.parser.Expression.format(Expression.java:89)
	at net.rptools.parser.InlineTreeFormatterTest.compare(InlineTreeFormatterTest.java:85)
	at net.rptools.parser.InlineTreeFormatterTest.testLogicalOperators(InlineTreeFormatterTest.java:70)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
	at junit.framework.TestCase.runTest(TestCase.java:176)
	at junit.framework.TestCase.runBare(TestCase.java:141)
	at junit.framework.TestResult$1.protect(TestResult.java:122)
	at junit.framework.TestResult.runProtected(TestResult.java:142)
	at junit.framework.TestResult.run(TestResult.java:125)
	at junit.framework.TestCase.run(TestCase.java:129)
	at junit.framework.TestSuite.runTest(TestSuite.java:255)
	at junit.framework.TestSuite.run(TestSuite.java:250)
	at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:84)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
	at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
	at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:118)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
	at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:413)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
	at java.base/java.lang.Thread.run(Thread.java:832)

Context

This is related to RPTools/maptool#1974

If one runs this macro in Maptool

[r, if(1 == 1): "match"]

using a build of MapTool that turns off deterministic expression in dicelib (see RPTools/dicelib#43) to gain performance improvements then the NPE occurs.

When a deterministic expressions is created then 1==1 is first converted to true, then the formatting succeeds.

Excepted behavior

new Parser().parseExpression('1 == 1').format().equals('1 == 1')

(no error)

I considered not fixing parser's inline formatter as the old way of always creating deterministic expressions didn't expose logical operators failing with NPE (they are reduced away in the step to create deterministic expression before format()).

I should have simply not created a formatted detailed expressions if the deterministic expression is not needed in RPTools/dicelib#43.

But since there's a NPE here I think we can fix it for completeness of the parser lib. Then work back upwards, and get to not having to use a deterministic expression unless it's needed (with the performance hit). With this change I can turn off deterministic expressions in MapTool successfully.

So if I'm following you, we need to:

  • Make a new parser release
  • Update MapTool build.gradle to use the new parser
  • You'll update MT again to turn off deterministic expressions where appropriate

Yes, new parser release. Once we pull that into MapTool I'll commit my changes there for tests of the conditionals that were found when disabling deterministic expressions. I'll put that together before we optimize that optimistic exp step out again.