antlr/stringtemplate4 — Issue #4: Problem with or operator in conditional
Author: parrt
Created: 2012-02-27 18:12:33+00:00
State: open

When trying to inspect a main template of this group:

main(doit = true) ::= "\"
t2() ::= "Hello"
t(x={<(t2())>}) ::= ""

ST4 throws an ArrayIndexOutOfBoundsException in STRuntimeMessage.getSourceLocation.

Interestingly removing the "|| other" let you inspect the template.

Also making the default for x = {} (i.e. use lazy evaluation) and keeping the "|| other" also works fine.

I added a test case to TestEarlyEvaluation and checked it in into Perforce.

Udo

P.S.: here the stack track

java.lang.ArrayIndexOutOfBoundsException: 17
at org.stringtemplate.v4.misc.STRuntimeMessage.getSourceLocation(STRuntimeMessage.java:70)
at org.stringtemplate.v4.misc.STRuntimeMessage.toString(STRuntimeMessage.java:81)
at javax.swing.DefaultListCellRenderer.getListCellRendererComponent(DefaultListCellRenderer.java:134)
at javax.swing.plaf.basic.BasicListUI.updateLayoutState(BasicListUI.java:1344)
at javax.swing.plaf.basic.BasicListUI.maybeUpdateLayoutState(BasicListUI.java:1294)
at javax.swing.plaf.basic.BasicListUI.getPreferredSize(BasicListUI.java:561)
at javax.swing.JComponent.getPreferredSize(JComponent.java:1634)
at javax.swing.JList.getPreferredScrollableViewportSize(JList.java:2412)
at javax.swing.ViewportLayout.preferredLayoutSize(ViewportLayout.java:75)
at java.awt.Container.preferredSize(Container.java:1599)
at java.awt.Container.getPreferredSize(Container.java:1584)
at javax.swing.JComponent.getPreferredSize(JComponent.java:1636)
at javax.swing.ScrollPaneLayout.preferredLayoutSize(ScrollPaneLayout.java:475)
at java.awt.Container.preferredSize(Container.java:1599)
at java.awt.Container.getPreferredSize(Container.java:1584)
at javax.swing.JComponent.getPreferredSize(JComponent.java:1636)
at java.awt.GridBagLayout.GetLayoutInfo(GridBagLayout.java:1092)
at java.awt.GridBagLayout.getLayoutInfo(GridBagLayout.java:893)
at java.awt.GridBagLayout.preferredLayoutSize(GridBagLayout.java:713)
at java.awt.Container.preferredSize(Container.java:1599)
at java.awt.Container.getPreferredSize(Container.java:1584)
at javax.swing.JComponent.getPreferredSize(JComponent.java:1636)
at javax.swing.JRootPane$RootLayout.preferredLayoutSize(JRootPane.java:907)
at java.awt.Container.preferredSize(Container.java:1599)
at java.awt.Container.getPreferredSize(Container.java:1584)
at javax.swing.JComponent.getPreferredSize(JComponent.java:1636)
at java.awt.BorderLayout.preferredLayoutSize(BorderLayout.java:702)
at java.awt.Container.preferredSize(Container.java:1599)
at java.awt.Container.getPreferredSize(Container.java:1584)
at java.awt.Window.pack(Window.java:706)
at org.stringtemplate.v4.gui.STViz.open(STViz.java:212)
at org.stringtemplate.v4.ST.inspect(ST.java:471)
at org.stringtemplate.v4.ST.inspect(ST.java:454)
at org.stringtemplate.v4.ST.inspect(ST.java:447)
at org.stringtemplate.v4.test.TestEarlyEvaluation.testBugArrayIndexOutOfBoundsExceptionInSTRuntimeMessage_getSourceLocation(TestEarlyEvaluation.java:138)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

_______________________________________________
stringtemplate-interest mailing list
stringtemplate-interest@antlr.org
http://www.antlr.org/mailman/listinfo/stringtemplate-interest

Also: to avoid confusion with the Java null maybe call the constant 'undefined'?

I was kind of thinking that it should be null because it has the same semantics as passing all in to add().

Actually this is not the case as you can see in the following test case. That's why I thought mixing "null" und "undefined" isn't such a good idea.

BTW: in the implementation the "undefined" literal should probably get the value ST.EMPTY_ATTR rather than null.

public class UndefinedOrNullTest extends BaseTest {
@Test
public void testUndefinedParameter() throws Exception {
writeFile(tmpdir, "t.stg", "t(s=\"world\") ::= <<\nHello \n>>");
String path = tmpdir + "t.stg";

STGroup group = new STGroupFile(tmpdir + "/t.stg");
ST st = group.getInstanceOf("t");
String s = st.render();
Assert.assertEquals("Hello world", s);
}

@Test
public void testNullParameter() throws Exception {
writeFile(tmpdir, "t.stg", "t(s=\"world\") ::= <<\nHello \n>>");
String path = tmpdir + "t.stg";

STGroup group = new STGroupFile(tmpdir + "/t.stg");
ST st = group.getInstanceOf("t");
st.add("s", null);
String s = st.render();
Assert.assertEquals("Hello ", s);
}
}

Udo

On 01.08.2011, at 21:33, Terence Parr wrote:

On Aug 1, 2011, at 7:10 AM, Udo Borkowski wrote:

Not sure about the semantic of null.

E.g. assume you have this template

t(s="world") ::= "Hello "

What will

render?

a) "Hello " (i.e. same as )
b) "Hello world" (i.e. same as )

I would assume it would render this one since the parameters missing.

c) "Hello null"
d) something else?

Also: to avoid confusion with the Java null maybe call the constant 'undefined'?

I was kind of thinking that it should be null because it has the same semantics as passing all in to add().

Ter
_______________________________________________
stringtemplate-interest mailing list
stringtemplate-interest@antlr.org
http://www.antlr.org/mailman/listinfo/stringtemplate-interest

_______________________________________________
stringtemplate-interest mailing list
stringtemplate-interest@antlr.org
http://www.antlr.org/mailman/listinfo/stringtemplate-interest

Begin forwarded message:

From: Udo Borkowski
Subject: [stringtemplate-interest] ST4: Pass Thru (...) support for indirect includes
Date: August 7, 2011 12:42:43 AM PDT
To: stringtemplate-interest List

Is there a reason why indirect includes don't support Pass Thru (…)?

E.g.

t1(x) ::= ""
main(x="hello",t="t1") ::= "<(t)(...)>"

will emit the following error:

t.stg 2:34: mismatched input '...' expecting RPAREN

However explicitly passing the parameter (x) with the indirect include, like in this example:

t1(x) ::= ""
main(x="hello",t="t1") ::= "<(t)(x)>"

works fine.

If there is no real reason for this restriction I suggest to add "Pass Thru" support for indirect calls into the next release of ST4.

Udo

P.S.: Possibly the same applies for "named arguments" and indirect includes.

P.P.S.: here the test case:

@Test
public void testIndirectCallWithPassThru() throws Exception {
String path = tmpdir + "t.stg";

// indirectly call t1, with explicit parameter passing
writeFile(tmpdir, "t.stg",
"t1(x) ::= \"\"\nmain(x=\"hello\",t=\"t1\") ::= <<\n<(t)(x)>\n>>");
STGroup group = new STGroupFile(tmpdir + "/t.stg");
ST st = group.getInstanceOf("main");
String s = st.render();
Assert.assertEquals("hello", s);

// indirectly call t1, with "pass thru" (...) parameter passing
// (used to fail with:
// "t.stg 2:21: mismatched input '...' expecting RPAREN")
writeFile(tmpdir, "t.stg",
"t1(x) ::= \"\"\nmain(x=\"hello\",t=\"t1\") ::= <<\n<(t)(...)>\n>>");
group = new STGroupFile(tmpdir + "/t.stg");
st = group.getInstanceOf("main");
s = st.render();
Assert.assertEquals("hello", s);
}