pax_global_header00006660000000000000000000000064123142673130014514gustar00rootroot0000000000000052 comment=f6d8a529e00f3dd79c7ea459a685775b84621989 stringtemplate4-4.0.8/000077500000000000000000000000001231426731300146535ustar00rootroot00000000000000stringtemplate4-4.0.8/.gitignore000066400000000000000000000003701231426731300166430ustar00rootroot00000000000000# Maven build folders /target/ # Ant build folders /build/ /dist/ /lib/ user.build.properties # NetBeans user configuration nbactions*.xml # IntelliJ project files *.iml *.ipr *.iws .idea/ # Eclipse project files .project .classpath .settings/ stringtemplate4-4.0.8/CHANGES.txt000066400000000000000000000414311231426731300164670ustar00rootroot00000000000000ST 4.0.8-Dev Release Terence Parr, parrt at cs usfca edu ANTLR project lead and supreme dictator for life University of San Francisco CHANGES January 30, 2013 * Require EOF in Group.g (rule group) * Minor cleanup and documentation tweaks * Improve ObjectModelAdaptor caching performance, eliminate chance of deadlock January 4, 2013 -- Release 4.0.7 * Fixed README for release January 1, 2013 * Tweaked escapes in <<...>>. Do NOT replace if it's <\\>. Escapes: >\> means >> inside of <<...>>. Escapes: \>> means >> inside of <<...>> unless at end like <<...\>>>>. In that case, use <%..>>%> instead. * Added warning about: "Missing newline after newline escape <\\>" * Actually: %\> is the escape to avoid end of string * Several STViz updates: * Highlight template subexpressions and literal text responsible for output * Gray out hidden (inherited+aliased) attributes * Highlight user-instanced templates in bold December 31, 2012 * Reversing decision to use >\> and %\> as the escapes now for >> and %>. Simply allowing >>> is the best, such as <>>. It will strip off the >> and leave > as the appropriate end of expression. Added testTripleAngleOnEnds. Even <<>> works now. There is no escape for %>. December 26, 2012 * Allow [] as a dictionary value, resolves antlr/stringtemplate4#33 December 25, 2012 * Fix issues with bytecode to source mapping * Fix several STViz bugs * Improved error location reporting * Fix several unit tests * Explicit InstanceScope tracking in the interpreter December 15, 2012 * throw exceptionWhen the attribute name is no to be consistent with the other check for '.' in the name. December 13, 2012 * Allow [] as a default value for formal arguments (fixes antlr/stringtemplate4#20) * Add method STViz.waitForClose() * Specify -Dtest.interactive to have STViz tests leave the window open for the user * Code cleanup December 11, 2012 * Don't cache the STNoSuchPropertyException and STNoSuchAttributeException instances. * Add ErrorType.NO_SUCH_ATTRIBUTE_PASS_THROUGH, reported on where foo contains a parameter with no default value and no matching attribute exists in the surrounding scope. * Improved message when reporting ErrorType.NO_SUCH_PROPERTY. December 10, 2012 * DateRenderer and StringRenderer now use the provided locale (fixes antlr/stringtemplate4#11) * Fixes for handling of arrays (fixes antlr/stringtemplate4#12 and other unreported issues) * Try to load template file (.st) if group file (.stg) failed with IOException (fixes antlr/stringtemplate4#14) * Add STGroup.GROUP_FILE_EXTENSION and STGroup.TEMPLATE_FILE_EXTENSION * Updated documentation, code cleanup December 9, 2012 * >\> and %\> are the escapes now for >> and %> Fixes antlr/stringtemplate4#17 December 3, 2012 -- Release 4.0.7-rc-1 December 1, 2012 * Missing ANT target for STParser.g in build September 26, 2012 -- Release 4.0.6 * STRawGroupDir problem and ST("template") issue. When there are no formal args for template t and you map t across some values, t implicitly gets arg "it". E.g., "$names:bold()$" and bold as "$it$". August 13, 2012 * Fixed https://github.com/antlr/stringtemplate4/issues/5 May 21, 2012 * Made fields in the error messages public February 8, 2012 -- 4.0.5 release December 25, 2011 * STLexer.tokens missing from src build * Added STRawGroupDir that expects pure templates in .st files not template defs with headers. So use $name$ not foo(name) ::= "$name" December 4, 2011 * synchronized object model adaptor * import illegal in group files embedded in STGroupDirs July 19, 2011 (Udo) * Fixed Misc.newline issue in test code (Udo) July 18, 2011 -- Release 4.0.4 * Added delimiters "<", ">" notation to group file. July 5, 2011 * added "get import list" method. * added methods to allow deep vs shallow setting of renderers; interp always asks native group defining template for the renderer. * STGroup.getInstanceOf was not auto-adding "/" to front if none was present June 30, 2011 * Updated javadoc on getAttributeRenderer() * Updated javadoc on unload/importTemplates in STGroup() (ub) * Added test case for unload of groups specified in group file imports. (ub) June 24, 2011 * STGroup.unload() now removes imports that were specified in the group file, but only calls unload() on templates that were explicitly added in the program. Resolves both Sam's and Udo's concerns. :) June 22, 2011 * subtemplates {...} in subdirectories didn't work. June 21, 2011 -- Release 4.0.3 * {} wasn't allowed as a template June 16, 2011 * Major overhaul of template names: ** '/' allowed as starting ID letter like ** getInstanceOf names must be fully qualified. If you don't put / on front, one is added for you. ** template refs in expr are relative to location of surrounding template unless prefixed with /. In that case they are relative to root of group. ** import statement no longer allows fully qualified file name. ** Changed all unit tests to use fully qualified names and see results that way. June 15, 2011 * STGroup.unload() calls unload() on each group in the imports list instead of clearing the list. (Thanks to Sam...wait, did Udo already try this?) June 14, 2011 * STRuntimeMessage got NPE upon ST.impl == null * ctor ST() is protected; not for users. bad users! June 11, 2011 (Udo) * Removed warning (access static member through instance) June 4, 2011 (Udo) * Fixed and added tests May 29, 2011 (Udo) * Fixed test case for <\n> to handle different line.separator sizes May 28, 2011 (Udo) * BUG: On Windows wrapped lines are separated with \r\r\n * made tests run on Windows and non-US locales May 20, 2011 (Udo) * STGroupDir.load(String name) no longer checks for (parent) group file when name specifies no parent (no '/') May 18, 2011 (Udo) * unload in STGroup now also unloads the import relationships * Fixed test testRendererWithPredefinedFormat2 to also work in non-PDT timezones * Fixed tests testArg1, testArg2 in TestGroupSyntaxErrors * Fixed "URI is not hierarchical" issue when STGroupFile is imported from jar file May 17, 2011 (Udo) * Added getTemplateNames to STGroup May 14, 2011 * passthru() didn't watch for empty formal args May 10-15, 2011 (Udo) * fixed bug raising a NullPointerException when a formalArg's default value has a syntax error. Example: main(a={(<"")>}) ::= "" * STGroupFile.getName() returns group name also for imported groups (was null before). 4.0.2 -- May 3, 2011 * Backing out change from 4/17; don't want Serializable implementation. * Improved error msg for out of order required parameters (after optional ones) April 26, 2011 * rest() stripped nulls, which it shouldn't. Was inconsistent with trunc(), etc... April 21, 2011 * Made STGroup.iterateAcrossValues an instance variable not static. That needed a change to convertAnythingIteratableToIterator, etc.. to non-static. * Removed STDump as unneeded; Use STViz. April 17, 2011 * Added implements Serializable to ST, STGroup. April 16, 2011 * Made compatible with Java 1.5; removed Arrays.copyOf() ref. * Updated ANT build to ref ant lib dir not /usr/local/lib/ April 11, 2011 * Dictionaries weren't inherited. Added unit test. 4.0.1 -- April 10, 2011 * Added STNoSuchAttributeException to distinguish from no such property. * Pass through didn't handle case properly of empty or nonexistent attributes. We only pass through nonempty values. Further, it makes no sense to set values for parameter x if x has no definition above. That is the same as having no value. This is required to get default attributes to work with passthru in all cases. Added unit tests. * Oops. That is not quite correct. If no value exists or the attribute itself does not exist, we must set the parameter to null ifthere is no default parameter. otherwise the interpreter will complain about a missing argument value. * Was missing alreadyLoaded = true; in STGroupString. * Bug fix for <@super.r()> exprs; it tried to doubly-define region. Code generator didn't generate mangled name either; fixed and then updated http://www.antlr.org/wiki/display/ST4/Template+to+Bytecode+mapping * Improved error msg when referencing implicit attributes like 'i'. April 9, 2011 * Sam pointed out that regions didn't work with <% %> * Cleaned up STViz. * STViz expands template attribute view when you click in output * STViz template and attribute tree views now grouped. * default arguments were not evaluated in context of invoked template; couldn't see other args. * Added '...' pass through arg back in. Only allowed with named arg lists or as sole arg. Not allowed in <(name)()> indirect includes. Inserts new passthru bytecode to set any unset args. * AST pane not updated upon new ST selection * Scroll output pane when ST selected * Added STGroup.iterateAcrossValues static boolean for v3 compatibility v3 iterates across values not keys like v4. But to convert ANTLR templates, it's too hard to find without static typing in templates. * Cleaned up ST.locals[] creation; centralized in Interpreter. * MapModelAdaptor made copy of STs unnecessarily and w/o copying locals[] April 8, 2011 * Added scope tree showing all inherited attributes (dynamic scoping) in lower left "attributes" pane. * Undid some bugs I introduced concerning selecting templates. Tried to move the cursor in output window which triggered multiple / wrong update events. April 6, 2011 * Ignore indentation in <% .. %> templates but keep white space between elements * Added better error msg for internal errors during template evaluation. context [outputFile parser genericParser rule ruleBlockSingleAlt alt element ruleRefAndListLabel ruleRef] 1:1 internal error caused by: java.lang.NullPointerException at org.stringtemplate.v4.ST.rawSetAttribute(ST.java:294) at org.stringtemplate.v4.Interpreter.storeArgs(Interpreter.java:576) at org.stringtemplate.v4.Interpreter.super_new(Interpreter.java:495) ... April 4, 2011 * in TestSubtemplates.java there was an extra (bad) import * fixed a couple of unit tests that failed. * removed .class files from depot * added t() ::= <% ... %> template that ignores all newlines inside template. This allows arbitrary formatting within a template that does not result in new lines in the output. This is useful when you have a really complicated template with IFs and such that needs to generate output all on the same line. Currently, this can be quite challenging. There's no way to read a huge template on one line. April 3, 2011 * ST.getAttribute() only looks in that template now. Can't look up since it doesn't know what interp is executing. It's just to get an attr out of a template now. Moved dynamically scope getAttribute() to Interpreter. * STRuntimeMessage takes an Interpreter interp arg now. * ST dropped some weight. No need for enclosingInstance ptr now. That is properly done in interpreter as a stack of scopes. Now, there is no side-effect whatsoever in ST instances for execution. THREAD SAFE eval now. * Added <<<...>>> template that ignores all \n inside; use <\n> to get one. * Interpreter interp added to ModelAdaptor. BREAKING CHANGE IF YOU'VE BUILT a model adaptor (rare) * Internal clean up so stack of template evaluation scopes has debug info. Required changes across lots of files. Started referring to scopes so entire path to root is available and with debugging info if debug on for that interpreter. Extracted InstanceScope from inner class. March 30 - April 2, 2011 * ST.inspect() now returns an STViz, which has all the goodies and gives you access to the GUI stuff. * added aggr.{prop1, prop2} for ST.add(). Too useful. (Was in v3). Use ST.addAggr("aggr.{p1,p2}", a1, a2); * refactored to fold DebugST into ST; adds one object ptr to every ST instance but worth reduction in complexity. "new ST(...)" calls didn't work (not DebugST objects) in inspector. ST.inspect() for any ST now. * Fixed bug in STViz. Didn't highlight entire output when you click topmost template. * STGroup.debug no longer there nor static. It's an instance var of Interpreter. ST.inspect() tells interp to debug. STGroup.trackCreationEvents says to record where in code an ST was created and where code added attributes. * Gutted tree model for STViz, refactored debugging/event tracking code. * creation events had wrong location (launch of interp location); only tracks now for externally/injected created templates. March 29, 2011 * Fixed bug where escaped quotes in template defs were not unescaped for use by compiler. 4.0 -- March 27, 2011 * ST.add() returns self now so we can chain. t.add("x", 1).add("y", "hi"); * import from files in jar didn't work. * removed field tokens from STGroupString * improved imports lookup * made fields of events public final. * augmented debug event toString and fixed start/stop issue with eval events. renamed fields to be more clear. * Added IndentEvent for dbg * ^(INDENT expr-sub-tree) is now ^(INDENTED_EXPR INDENT expr-sub-tree) with changes to grammars. More consistent with subtree root being operator. STViz now highlights indentation properly in template pane. * Altered CodeGenerator.g to pass AST node for indentation not just string. This way we get INDENT operations into the sourceMap for indent debug events. 4.0b5 -- March 6, 2011 BIG THANKS to Sam Harwell and, again, to Udo Borkowski for debugging help and suggestions. Sam is doing the C# implementation. Benjamin Niemann is doing the Python port. Alan Condit is doing Objective-C. * true/false were only allowed as default args; now allowed as template arg expressions in templates. Works as dictionary value too. * couldn't have anonymous templates inside a region. * parentheses were a bit weird in conditions. Now, conditions cannot use parentheses to mean "early evaluation" except as obj.(propName) * nativeGroup of all implicit templates was STGroup.defaultGroup. * removed all writes of the enclosingInstance at evaluation time; fixed issue for STViz. * comments on line by themselves don't emit \n to output * STViz tried to highlight AST pane even when we switched ASTs * combined load_str, write into write_str single op. minor optimizations too. Seems a tiny bit faster per benchmarks. * Added ST.VERSION auto-updated by ANT. * added STGroupString * Added support for this in group.g: oldStyleHeader // ignore but lets us use this parser in AW for both v3 and v4 : 'group' ID ( ':' ID )? ( 'implements' ID (',' ID)* )? ';' ; * IndexOutOfBounds Exception when using "cap" format on empty string * @t.() ::= "" caused NPE * Region redefinition caused NPE. "<@r>a<@end><@r()>" * STViz couldn't see first subtemplate when computing template range in output. * Was incorrectly computing filename to load template .st files from group dir. * Listener was not notified upon "no such template" in group dir. * Redid how ST found imported files, dir, etc.. Can now import a template file even. Can be absolute path or relative path. If relative, it looks in dir of .stg file with import then CLASSPATH. * The listener of import groups is now set to that of group that imports them. * Regions behave like tags now. Indent respected if <@r>...<@end> on indented single line. Indent/newlines ignored after those tags if on separate lines. 4.0b4 -- February 5, 2011 BIG THANKS to Udo Borkowski for his help debugging these betas and his suggestions. * added write to file methods * had infinite loop for expr: " using new STWriter derived from type of current STWriter. e.g., AutoIndentWriter. * didn't detect nonterminated comment. * added two literals "true" and "false" to the template argument syntax; e.g., stat(name,x=true,y=false) ::= "..." * it was treating "..." default arg as a template not string. * throws STException now upon not finding group file or group dir instead of sending err to listener. * default args couldn't have subtemplates t(x,y={}>}) ::= "..." * Added a new benchmark from Oliver Zeigermann. 4.0b3 -- January 28, 2011 * exception in lexer blew out of parsing * missing '}' in {...} caused infinite loop * NPE in storeArgs if empty arg list * removed debugging prints. * x={<(...)>} default arg was hardcoded to <...> not $..$ or whatever. * The grammar needed to match and ignore an optional INDENT before region @end * when redefining a region (template) the newline before the >> was kept. * WS not ignored in front of STRING token in expressions. * closing STViz doesn't exit vm now. * throws exception if registering renderer or model adaptor for primitive 4.0b2 -- January 22, 2011 * Order of static init issue; an error mgr was null. * Fixed some unit testing the Windows friendly * Fix bug in triple if-elseif-elseif-elseif; added unit tests * bug where I did not say current_ip when calling exec() from writeObject * Updated README to include install information 4.0b1 -- January 14, 2011 stringtemplate4-4.0.8/LICENSE.txt000066400000000000000000000026201231426731300164760ustar00rootroot00000000000000[The "BSD license"] Copyright (c) 2011-2013 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. stringtemplate4-4.0.8/README.txt000066400000000000000000000100101231426731300163410ustar00rootroot00000000000000StringTemplate 4.0.7 January 4, 2013 Terence Parr, parrt at cs usfca edu ANTLR project lead and supreme dictator for life University of San Francisco ST (StringTemplate) is a java template engine (with ports for C#, Python, and Objective-C coming) for generating source code, web pages, emails, or any other formatted text output. ST is particularly good at multi-targeted code generators, multiple site skins, and internationalization / localization. It evolved over years of effort developing jGuru.com and then ANTLR v3. The main website is: http://www.stringtemplate.org Its distinguishing characteristic is that it strictly enforces model-view separation, unlike other engines. See: http://www.cs.usfca.edu/~parrt/papers/mvc.templates.pdf The documentation is in the wiki: http://www.antlr.org/wiki/display/ST4/StringTemplate+4+Documentation Per the BSD license in LICENSE.txt, this software is not guaranteed to work and might even destroy all life on this planet. See the CHANGES.txt file. INSTALLATION All you need to do is get the StringTemplate jar into your CLASSPATH as well as its dependent ANTLR jar. Download the following and put into your favorite lib directory such as /usr/local/lib on UNIX: * antlr-3.5-complete.jar; http://www.antlr3.org/download/antlr-3.5-complete.jar * ST.jar; see http://www.stringtemplate.org/download/ST-4.0.7.jar Add to your CLASSPATH. On UNIX that looks like $ export CLASSPATH="/usr/local/lib/antlr-3.5-complete.jar:/usr/local/lib/ST-4.0.7.jar:$CLASSPATH" Java will now see all the libraries necessary to execute ST stuff. BUILDING FROM SOURCE The source is at github.com: https://github.com/antlr/stringtemplate4 If you would like to make changes to ST and build it yourself, just set build.properties to the appropriate version of this: version=4.0.7 antlr3.jar=/usr/local/lib/antlr-3.5-rc-2-complete.jar build.sysclasspath=ignore and then run "ant" from the main directory. Then, once you're set up with the ant task, go for it. Looks like this: $ cd /usr/local/ST-4.0.7 $ ant Buildfile: /Users/parrt/antlr/code/stringtemplate4/build.xml clean: [delete] Deleting directory /Users/parrt/antlr/code/stringtemplate4/build init: [mkdir] Created dir: /Users/parrt/antlr/code/stringtemplate4/build/generated-sources/antlr3 [mkdir] Created dir: /Users/parrt/antlr/code/stringtemplate4/build/classes antlr: [echo] Run ANTLR on grammars [java] ANTLR Parser Generator Version 3.x [java] Output file /Users/parrt/antlr/code/stringtemplate4/build/generated-sources/antlr3/org/stringtemplate/v4/compiler/STParser.java does not exist: must build /Users/parrt/antlr/code/stringtemplate4/src/org/stringtemplate/v4/compiler/STParser.g [java] STParser.g [java] Output file /Users/parrt/antlr/code/stringtemplate4/build/generated-sources/antlr3/org/stringtemplate/v4/compiler/GroupParser.java does not exist: must build /Users/parrt/antlr/code/stringtemplate4/src/org/stringtemplate/v4/compiler/Group.g [java] Group.g [java] Output file /Users/parrt/antlr/code/stringtemplate4/build/generated-sources/antlr3/org/stringtemplate/v4/compiler/CodeGenerator.java does not exist: must build /Users/parrt/antlr/code/stringtemplate4/src/org/stringtemplate/v4/compiler/CodeGenerator.g [java] CodeGenerator.g compile: [javac] Compiling 61 source files to /Users/parrt/antlr/code/stringtemplate4/build/classes zip-source: [mkdir] Created dir: /Users/parrt/antlr/code/stringtemplate4/dist/ST-4.0.7 [mkdir] Created dir: /Users/parrt/antlr/code/stringtemplate4/dist/ST-4.0.7/src [copy] Copying 68 files to /Users/parrt/antlr/code/stringtemplate4/dist/ST-4.0.7/src [copy] Copying 5 files to /Users/parrt/antlr/code/stringtemplate4/dist/ST-4.0.7 [copy] Copying 1 file to /Users/parrt/antlr/code/stringtemplate4/dist/ST-4.0.7/lib [zip] Building zip: /Users/parrt/antlr/code/stringtemplate4/dist/ST-4.0.7-src.zip build-jar: [jar] Building jar: /Users/parrt/antlr/code/stringtemplate4/dist/ST-4.0.7.jar distribute: BUILD SUCCESSFUL Total time: 4 seconds stringtemplate4-4.0.8/benchmark/000077500000000000000000000000001231426731300166055ustar00rootroot00000000000000stringtemplate4-4.0.8/benchmark/org/000077500000000000000000000000001231426731300173745ustar00rootroot00000000000000stringtemplate4-4.0.8/benchmark/org/stringtemplate/000077500000000000000000000000001231426731300224365ustar00rootroot00000000000000stringtemplate4-4.0.8/benchmark/org/stringtemplate/v4/000077500000000000000000000000001231426731300227675ustar00rootroot00000000000000stringtemplate4-4.0.8/benchmark/org/stringtemplate/v4/benchmark/000077500000000000000000000000001231426731300247215ustar00rootroot00000000000000stringtemplate4-4.0.8/benchmark/org/stringtemplate/v4/benchmark/Attributes.java000066400000000000000000000104441231426731300277150ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.benchmark; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroupFile; public class Attributes { public static class User { public int id; public String name; public User(int id, String name) { this.id = id; this.name = name; } public String getName() { return name; } } public static final String tmpdir = System.getProperty("java.io.tmpdir"); public void time2Args(int reps) { String templates = "t(x,y) ::= \"\"\n"; Misc.writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST st = group.getInstanceOf("t"); st.add("x", 1); st.add("y", 2); for (int i = 0; i < reps; i++) { st.render(); } } public void timeLotsOfArgs(int reps) { String templates = "t(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z) ::=" + " \",,,,,,,,,,,,,,,

,,,,,,,,,,\"\n"; Misc.writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST st = group.getInstanceOf("t"); st.add("x", 1); st.add("y", 2); for (int i = 0; i < reps; i++) { st.render(); } } public void timeSimplePropsOfArgs(int reps) { String templates = "t(x) ::= \"\"\n"; Misc.writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST st = group.getInstanceOf("t"); st.add("x", new User(32,"parrt")); for (int i = 0; i < reps; i++) { st.render(); } } public void timeDynamicAttributeLookup(int reps) { String templates = "t(x,y) ::= \"\"\n"+ "u() ::= \"\"\n"; Misc.writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST st = group.getInstanceOf("t"); st.add("x", 1); st.add("y", 2); for (int i = 0; i < reps; i++) { st.render(); } } public void timeDeepDynamicLookup(int reps) { String templates = "t(x,y) ::= \"\"\n"+ "u1(a) ::= \"\"\n"+ "u2(a) ::= \"\"\n"+ "u3(a) ::= \"\"\n"+ "u4(a) ::= \"\"\n"+ "u5(a) ::= \"\"\n"+ "u6(a) ::= \"\"\n"+ "u7(a) ::= \"\"\n"+ "u8(a) ::= \"\"\n"+ "u9(a) ::= \"\"\n"+ "u10(a) ::= \"\"\n"+ "u11(a) ::= \"\"\n"+ "u12(a) ::= \"\"\n"+ "u13(a) ::= \"\"\n"+ "u14(a) ::= \"\"\n"+ "u15(a) ::= \"\"\n"+ "u16(a) ::= \"\"\n"+ "z(a) ::= \"\"\n"; Misc.writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST st = group.getInstanceOf("t"); st.add("x", 1); st.add("y", 2); for (int i = 0; i < reps; i++) { st.render(); } } } stringtemplate4-4.0.8/benchmark/org/stringtemplate/v4/benchmark/Benchmark.java000066400000000000000000000146241231426731300274650ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.benchmark; import org.stringtemplate.v4.misc.MultiMap; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.InetAddress; import java.net.UnknownHostException; import java.text.DateFormat; import java.util.*; /** A Java benchmark tool inspired by Caliper from google. This isn't nearly * as good but probably ok for my needs. * * Use -XX:+PrintCompilation to see if compilation happens during trials * java -XX:+PrintCompilation org.stringtemplate.v4.benchmark.Benchmark MyTest */ public class Benchmark { private static final int WARMUP_REPS = 10000; // HotSpot needs this to warm up public static final int MIN_BENCHMARK_TIME_IN_MS = 350; public static final double MAX_ERROR_IN_WORK_PER_MS = 0.05; public static void main(String[] args) throws Exception { DateFormat df = DateFormat.getDateTimeInstance(); System.err.print("# Env "); System.err.print("Host "+ InetAddress.getLocalHost().getHostName()); System.err.print(", "+df.format(new GregorianCalendar().getTime())); System.err.print(", Java " + System.getProperty("java.runtime.version")); System.err.print(", "+System.getProperty("os.name")+" "+System.getProperty("os.version")); System.err.print(" on " + System.getProperty("os.arch")); System.err.println(); for (int i = 0; i < args.length; i++) { String benchmarkClassName = args[i]; run(benchmarkClassName); } //Interpreter.dumpOpcodeFreq(); } // keep run as one big method so it all gets compiled. public static void run(String benchmarkClassName) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnknownHostException, InvocationTargetException { Class c = Class.forName(benchmarkClassName); Object suite = c.newInstance(); Method[] methods = c.getDeclaredMethods(); List benchmarks = new ArrayList(); for (Method m : methods) { if ( m.getName().startsWith("time") ) benchmarks.add(m); } // TODO: grab interpreted time to check for compiler removing // dead code and giving inside speedups? // warm everybody up to ensure they are compiled. // must run them all since loading later test can force recompilation System.err.println("# HotSpot warmup"); for (Method m : benchmarks) m.invoke(suite,WARMUP_REPS); System.err.println("# Computing number of reps per trial"); // Compute a reps num that kicks each benchmark over MIN_BENCHMARK_TIME_IN_MS Map min_reps = new HashMap(); for (Method m : benchmarks) { int r = 10; while (true) { long start = System.nanoTime(); m.invoke(suite,r); long stop = System.nanoTime(); long duration_in_ns = (stop - start); // System.out.println(r+" r cost "+duration_in_ns+"ns"); if ( duration_in_ns > MIN_BENCHMARK_TIME_IN_MS*1000000 ) break; double reps_per_ns = (double)r / duration_in_ns; // System.out.println("r/ns="+reps_per_ns); r = (int)(reps_per_ns * MIN_BENCHMARK_TIME_IN_MS*1000000 * 1.10); // 10% fudgefactor // System.out.println("trying "+r+" reps"); min_reps.put(m, r); } } // System.err.println("min_reps="+min_reps); MultiMap duration = new MultiMap(); // run all benchmarks in same order, recording duration for (Method m : benchmarks) { System.err.println("# "+m.getName()+" benchmarking"); // show progress List reps = getReps(min_reps, m); for (int r : reps) { System.gc(); long start = System.nanoTime(); m.invoke(suite,r); long stop = System.nanoTime(); duration.map(m, stop - start); } } // System.err.printf("%-30s: ", "repetitions"); // for (int r : min_reps.get(benchmarks.get(0)) ) System.err.printf("%8d", r); // System.err.println(); MultiMap avgs = new MultiMap(); for (Method m : duration.keySet()) { System.err.printf("%-30s: ", m.getName()); List d = duration.get(m); List reps = getReps(min_reps, m); double avg_across = 0.0; for (int i=0; i a = avgs.get(m); if ( a.get(0) < a.get(a.size() - 1) ) ratio = a.get(0) / a.get(a.size() - 1); else ratio = a.get(a.size() - 1) / a.get(0); if ( (1-ratio) > MAX_ERROR_IN_WORK_PER_MS ) { System.err.print(" warning: variable average work"); } System.err.println(); } } protected static List getReps(Map min_reps, Method m) { List reps = new ArrayList(); reps.add(min_reps.get(m)); reps.add(min_reps.get(m)*2); reps.add(min_reps.get(m)*4); reps.add(min_reps.get(m)*8); reps.add(min_reps.get(m)*16); return reps; } } stringtemplate4-4.0.8/benchmark/org/stringtemplate/v4/benchmark/Misc.java000066400000000000000000000041161231426731300264610ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.benchmark; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; public class Misc { public static void writeFile(String dir, String fileName, String content) { try { File f = new File(dir, fileName); if ( !f.getParentFile().exists() ) f.getParentFile().mkdirs(); FileWriter w = new FileWriter(f); BufferedWriter bw = new BufferedWriter(w); bw.write(content); bw.close(); w.close(); } catch (IOException ioe) { System.err.println("can't write file"); ioe.printStackTrace(System.err); } } } stringtemplate4-4.0.8/benchmark/org/stringtemplate/v4/benchmark/OliverTest.java000066400000000000000000000070471231426731300276740ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** Borrowed from Oliver Zeigermann */ package org.stringtemplate.v4.benchmark; import org.stringtemplate.v4.*; import org.stringtemplate.v4.benchmark.oliver.Helper; import java.io.IOException; import java.io.StringWriter; import java.math.BigDecimal; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.NumberFormat; import java.util.Date; import java.util.Locale; /** Adapted from Oliver Zeigermann benchmarking */ public class OliverTest { static STGroup test = new STGroupFile("email.stg"); public void timeEmail(int reps) { ST st = test.getInstanceOf("email"); st.add("order", Helper.order); st.add("separator", "----------------"); for (int i = 0; i < reps; i++) { st.render(); } } public void timeEmailWriteToStringBuffer(int reps) { ST st = test.getInstanceOf("email"); st.add("order", Helper.order); st.add("separator", "----------------"); for (int i = 0; i < reps; i++) { StringWriter sw = new StringWriter(); AutoIndentWriter w = new AutoIndentWriter(sw); try {st.write(w);} catch (IOException ioe) {;} } } public void timeEmailWithRenderers(int reps) { STGroup test = new STGroupFile("email.stg"); test.registerRenderer(Date.class, new DateRenderer()); test.registerRenderer(BigDecimal.class, new BigDecimalRenderer()); ST st = test.getInstanceOf("email"); st.add("order", Helper.order); st.add("separator", "----------------"); for (int i = 0; i < reps; i++) { st.render(); } } public static class BigDecimalRenderer implements AttributeRenderer { private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat( "##,##0.00", DecimalFormatSymbols.getInstance(Locale.GERMANY)); private static final String EURO_CHARACTER = "\u20AC"; public String toString(Object o, String formatString, Locale locale) { if (formatString.equals("currency")) { if (o instanceof BigDecimal) { NumberFormat numberFormat = DECIMAL_FORMAT; String formatted = numberFormat.format(o) + " " + EURO_CHARACTER; return formatted; } } return o.toString(); } } } stringtemplate4-4.0.8/benchmark/org/stringtemplate/v4/benchmark/WriteFixedTemplates.java000066400000000000000000000041161231426731300315170ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.benchmark; import org.stringtemplate.v4.ST; public class WriteFixedTemplates { String bigTemplate; public WriteFixedTemplates() { StringBuilder buf = new StringBuilder(); for (int i=1; i<=1000; i++) buf.append("some text"); bigTemplate = buf.toString(); } public void timeSingle(int reps) { String template = "A smallish string to write out"; ST st = new ST(template); for (int i = 0; i < reps; i++) { st.render(); } } public void timeSingleBigger(int reps) { ST st = new ST(bigTemplate); for (int i = 0; i < reps; i++) { st.render(); } } } stringtemplate4-4.0.8/benchmark/org/stringtemplate/v4/benchmark/email.stg000066400000000000000000000012161231426731300265270ustar00rootroot00000000000000email(order,separator) ::= << Hello, dear customer! On we received the following order: Shipping address: x à = };separator="\n"> plus shipping = Total = Thank you for ordering! >> stringtemplate4-4.0.8/benchmark/org/stringtemplate/v4/benchmark/home.benchmark.txt000066400000000000000000000022571231426731300303510ustar00rootroot00000000000000# Env Host terence.local, Dec 26, 2010 11:57:52 AM, Java 1.6.0_22-b04-307-10M3261, Mac OS X 10.6.5 on x86_64 # HotSpot warmup # Computing number of reps per trial # time2Args benchmarking # timeLotsOfArgs benchmarking # timeSimplePropsOfArgs benchmarking # timeDynamicAttributeLookup benchmarking # timeDeepDynamicLookup benchmarking timeSimplePropsOfArgs : 386.81 392.62 393.54 396.98 398.90 = 393.77 units of work / ms timeDeepDynamicLookup : 72.32 73.84 74.28 75.82 75.80 = 74.41 units of work / ms timeDynamicAttributeLookup : 775.80 775.18 786.06 785.49 788.14 = 782.13 units of work / ms time2Args : 685.35 692.77 735.37 877.76 873.88 = 773.03 units of work / ms warning: variable average work timeLotsOfArgs : 132.92 135.32 134.53 136.08 136.27 = 135.02 units of work / ms # HotSpot warmup # Computing number of reps per trial # timeSingle benchmarking # timeSingleBigger benchmarking timeSingleBigger : 9.20 9.20 9.21 9.24 9.22 = 9.22 units of work / ms timeSingle : 840.15 848.22 857.10 856.69 854.94 = 851.42 units of work / ms stringtemplate4-4.0.8/benchmark/org/stringtemplate/v4/benchmark/maniac.benchmark.txt000066400000000000000000000113641231426731300306500ustar00rootroot00000000000000/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/bin/java -Dfile.encoding=MacRoman -classpath /System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/lib/deploy.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/lib/dt.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/lib/javaws.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/lib/jce.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/lib/management-agent.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/lib/plugin.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/lib/sa-jdi.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/../Classes/charsets.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/../Classes/classes.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/../Classes/dt.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/../Classes/jce.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/../Classes/jconsole.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/../Classes/jsse.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/../Classes/management-agent.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/../Classes/ui.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/lib/ext/apple_provider.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/lib/ext/dnsns.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/lib/ext/localedata.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/lib/ext/sunjce_provider.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/lib/ext/sunpkcs11.jar:/Users/parrt/antlr/code/ST4/java/main/src:/Users/parrt/antlr/code/antlr/main/target:/Users/parrt/antlr/code/antlr/main/tool/src/main/resources:/Applications/IntelliJ IDEA 10.app/lib/junit-4.7.jar org.stringtemplate.v4.benchmark.Benchmark org.stringtemplate.v4.benchmark.Attributes org.stringtemplate.v4.benchmark.WriteFixedTemplates # Env Host maniac.cs.usfca.edu, Feb 10, 2011 5:17:01 PM, Java 1.6.0_22-b04-307-10M3261, Mac OS X 10.6.6 on x86_64 # HotSpot warmup # Computing number of reps per trial # time2Args benchmarking # timeLotsOfArgs benchmarking # timeSimplePropsOfArgs benchmarking # timeDynamicAttributeLookup benchmarking # timeDeepDynamicLookup benchmarking timeSimplePropsOfArgs : 443.62 437.98 453.93 451.99 451.00 = 447.70 units of work / ms timeDeepDynamicLookup : 85.18 85.02 85.48 85.73 85.99 = 85.48 units of work / ms timeDynamicAttributeLookup : 792.29 803.28 803.91 806.45 805.94 = 802.37 units of work / ms time2Args : 957.50 965.75 966.73 971.06 975.66 = 967.34 units of work / ms timeLotsOfArgs : 187.92 190.13 191.14 191.24 191.72 = 190.43 units of work / ms # HotSpot warmup # Computing number of reps per trial # timeSingle benchmarking # timeSingleBigger benchmarking timeSingleBigger : 7.16 7.16 7.15 7.12 7.09 = 7.14 units of work / ms timeSingle : 765.39 767.33 771.64 772.59 767.47 = 768.88 units of work / ms timeEmail : 48.90 49.12 49.50 49.43 49.45 = 49.28 units of work / ms timeEmailWriteToStringBuffer : 49.95 50.44 50.40 50.28 50.41 = 50.30 units of work / ms timeEmailWithRenderers : 32.31 32.60 32.73 32.71 32.79 = 32.63 units of work / ms Then after removing some method calls, caching renders, I get: (INSTR_WRITE_STR didn't make much diff, surprisingly) # Env Host maniac.cs.usfca.edu, Feb 10, 2011 6:31:59 PM, Java 1.6.0_22-b04-307-10M3261, Mac OS X 10.6.6 on x86_64 # HotSpot warmup # Computing number of reps per trial # time2Args benchmarking # timeLotsOfArgs benchmarking # timeSimplePropsOfArgs benchmarking # timeDynamicAttributeLookup benchmarking # timeDeepDynamicLookup benchmarking timeSimplePropsOfArgs : 448.97 455.70 455.14 454.80 456.39 = 454.20 units of work / ms timeDeepDynamicLookup : 111.64 112.48 111.27 113.22 112.56 = 112.23 units of work / ms timeDynamicAttributeLookup : 793.56 797.05 799.26 804.29 790.15 = 796.86 units of work / ms time2Args : 935.16 918.62 942.11 938.97 944.40 = 935.85 units of work / ms timeLotsOfArgs : 216.54 221.41 222.00 222.48 223.00 = 221.08 units of work / ms timeEmail : 50.92 51.54 51.50 51.46 51.25 = 51.33 units of work / ms timeEmailWriteToStringBuffer : 51.99 51.98 52.17 52.05 51.97 = 52.03 units of work / ms timeEmailWithRenderers : 32.36 33.77 33.67 33.57 33.86 = 33.45 units of work / ms stringtemplate4-4.0.8/benchmark/org/stringtemplate/v4/benchmark/oliver/000077500000000000000000000000001231426731300262215ustar00rootroot00000000000000stringtemplate4-4.0.8/benchmark/org/stringtemplate/v4/benchmark/oliver/Article.java000066400000000000000000000040371231426731300304530ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** Borrowed from Oliver Zeigermann */ package org.stringtemplate.v4.benchmark.oliver; import java.math.BigDecimal; public class Article { public final String name; public final BigDecimal price; public Article(String name, BigDecimal price) { super(); this.name = name; this.price = price; } // all getters created for freemarker as it can not access the fields // directly (JMTE and ST can) public String getName() { return name; } public BigDecimal getPrice() { return price; } } stringtemplate4-4.0.8/benchmark/org/stringtemplate/v4/benchmark/oliver/Customer.java000066400000000000000000000042261231426731300306710ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** Borrowed from Oliver Zeigermann */ package org.stringtemplate.v4.benchmark.oliver; public class Customer { public final String firstName; public final String lastName; public final String address; public Customer(String firstName, String lastName, String address) { this.firstName = firstName; this.lastName = lastName; this.address = address; } // all getters created for freemarker as it can not access the fields directly (JMTE and ST can) public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public String getAddress() { return address; } } stringtemplate4-4.0.8/benchmark/org/stringtemplate/v4/benchmark/oliver/Helper.java000066400000000000000000000052201231426731300303020ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** Borrowed from Oliver Zeigermann */ package org.stringtemplate.v4.benchmark.oliver; import java.math.BigDecimal; import java.util.*; public class Helper { public static String unifyNewlines(String source) { final String regex = "\\r?\\n"; final String clearedSource = source.replaceAll(regex, "\n"); return clearedSource; } public static Order order; static { Calendar instance = GregorianCalendar.getInstance(Locale.GERMAN); instance.set(2011, Calendar.JANUARY, 28); Date orderDate = instance.getTime(); Customer customer = new Customer("Oliver", "Zeigermann", "Gaußstraße 180\n" + "22765 Hamburg\n" + "GERMANY"); order = new Order(customer, orderDate); Article article1 = new Article("How to become famous", new BigDecimal( "17.80")); order.getItems().add(new Item(1, article1)); Article article2 = new Article("Cool stuff", new BigDecimal("1.00")); order.getItems().add(new Item(2, article2)); } public static Map model = new HashMap(); static { model.put("order", Helper.order); model.put("separator", "----------------"); } } stringtemplate4-4.0.8/benchmark/org/stringtemplate/v4/benchmark/oliver/Item.java000066400000000000000000000042031231426731300277610ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** Borrowed from Oliver Zeigermann */ package org.stringtemplate.v4.benchmark.oliver; import java.math.BigDecimal; public class Item { public final int amount; public final Article article; public Item(int amount, Article article) { super(); this.amount = amount; this.article = article; } public BigDecimal getSubTotal() { return article.price.multiply(new BigDecimal(amount)); } // all getters created for freemarker as it can not access the fields // directly (JMTE and ST can) public int getAmount() { return amount; } public Article getArticle() { return article; } } stringtemplate4-4.0.8/benchmark/org/stringtemplate/v4/benchmark/oliver/Order.java000066400000000000000000000056771231426731300301560ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** Borrowed from Oliver Zeigermann */ package org.stringtemplate.v4.benchmark.oliver; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; import java.util.List; public class Order { public final static BigDecimal FREE_SHIPPING_THRESHOLD = new BigDecimal("20.00"); public final static BigDecimal SHIPPING_COSTS = new BigDecimal("3.00"); private final Customer customer; private final Date orderDate; private final List items = new ArrayList(); public Order(Customer customer, Date orderDate) { super(); this.customer = customer; this.orderDate = orderDate; } public Customer getCustomer() { return customer; } public Date getOrderDate() { return orderDate; } public List getItems() { return items; } public BigDecimal getTotal() { return getTotalWithoutShipping().add(getShippingCost()); } public BigDecimal getShippingCost() { if (isFreeShipping()) { return new BigDecimal("0"); } else { return SHIPPING_COSTS; } } public BigDecimal getTotalWithoutShipping() { BigDecimal total = new BigDecimal(0); for (Item item : items) { BigDecimal part = item.getSubTotal(); total = total.add(part); } return total; } // introduced for st3 and st4 as they can not compare values public boolean isFreeShipping() { return getTotalWithoutShipping().compareTo(FREE_SHIPPING_THRESHOLD) == 1; } } stringtemplate4-4.0.8/build.xml000066400000000000000000000142271231426731300165020ustar00rootroot00000000000000 stringtemplate4-4.0.8/contributors.txt000066400000000000000000000050751231426731300201600ustar00rootroot00000000000000ANTLR Project Contributors Certification of Origin and Rights All contributors to StringTemplate v4 must formally agree to abide by this certificate of origin by signing on the bottom with their github userid, full name, email address (you can obscure your e-mail, but it must be computable by human), and date. By signing this agreement, you are warranting and representing that you have the right to release code contributions or other content free of any obligations to third parties and are granting Terence Parr and ANTLR project contributors, henceforth referred to as The ANTLR Project, a license to incorporate it into The ANTLR Project tools (such as ANTLRWorks and StringTemplate) or related works under the BSD license. You understand that The ANTLR Project may or may not incorporate your contribution and you warrant and represent the following: 1. I am the creator of all my contributions. I am the author of all contributed work submitted and further warrant and represent that such work is my original creation and I have the right to license it to The ANTLR Project for release under the 3-clause BSD license. I hereby grant The ANTLR Project a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, prepare derivative works, and otherwise use this contribution as part of the ANTLR project, associated documentation, books, and tools at no cost to The ANTLR Project. 2. I have the right to submit. This submission does not violate the rights of any person or entity and that I have legal authority over this submission and to make this certification. 3. If I violate another's rights, liability lies with me. I agree to defend, indemnify, and hold The ANTLR Project and ANTLR users harmless from any claim or demand, including reasonable attorney fees, made by any third party due to or arising out of my violation of these terms and conditions or my violation of the rights of another person or entity. 4. I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license indicated in the file. I have read this agreement and do so certify by adding my signoff to the end of the following contributors list. CONTRIBUTORS: YYYY/MM/DD, github id, Full name, email 2012/07/12, parrt, Terence Parr, parrt@antlr.org 2012/08/13, pgelinas, Pascal Gélinas, pascal.gelinas@polymtl.ca stringtemplate4-4.0.8/doxyfile000066400000000000000000000231631231426731300164260ustar00rootroot00000000000000# Doxyfile 1.5.2 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = "StringTemplate 4 API" PROJECT_NUMBER = 4.0.6 OUTPUT_DIRECTORY = api CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the ALWAYS_DETAILED_SEC = YES INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = /Applications/ STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 4 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = YES BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = YES EXTRACT_PRIVATE = YES EXTRACT_STATIC = YES EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = NO HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = NO GENERATE_BUGLIST = NO GENERATE_DEPRECATEDLIST= NO ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = NO FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = /Users/parrt/antlr/code/ST4/java/main/src INPUT_ENCODING = UTF-8 FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.d \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.idl \ *.odl \ *.cs \ *.php \ *.php3 \ *.inc \ *.m \ *.mm \ *.dox \ *.py RECURSIVE = YES EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXCLUDE_SYMBOLS = java::util \ java::io EXAMPLE_PATH = EXAMPLE_PATTERNS = * EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO REFERENCES_LINK_SOURCE = YES USE_HTAGS = NO VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = . HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = YES LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = NO MSCGEN_PATH = /Applications/Doxygen.app/Contents/Resources/ HIDE_UNDOC_RELATIONS = YES HAVE_DOT = YES CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = /Applications/Doxygen.app/Contents/Resources/ DOTFILE_DIRS = DOT_GRAPH_MAX_NODES = 50 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO stringtemplate4-4.0.8/nb-configuration.xml000066400000000000000000000134041231426731300206430ustar00rootroot00000000000000 project 4 4 4 true 80 none false 4 4 4 4 false 80 none *;java 4 4 4 false test 4 4 4 false 80 none false true stringtemplate4-4.0.8/pom.xml000066400000000000000000000321261231426731300161740ustar00rootroot00000000000000 org.sonatype.oss oss-parent 9 4.0.0 org.antlr ST4 jar 4.0.8 StringTemplate 4 StringTemplate is a java template engine for generating source code, web pages, emails, or any other formatted text output. StringTemplate is particularly good at multi-targeted code generators, multiple site skins, and internationalization/localization. It evolved over years of effort developing jGuru.com. StringTemplate also generates the stringtemplate website: http://www.stringtemplate.org and powers the ANTLR v3 code generator. Its distinguishing characteristic is that unlike other engines, it strictly enforces model-view separation. Strict separation makes websites and code generators more flexible and maintainable; it also provides an excellent defense against malicious template authors. There are currently about 600 StringTemplate source downloads a month. UTF-8 ${env.JAVA5_HOME} ${env.JAVA6_HOME} ${java5.home}/lib/rt.jar ${java6.home}/lib/rt.jar ${bootclasspath.java5} ${bootclasspath.java6} http://www.stringtemplate.org Terence Parr USFCA http://www.cs.usfca.edu parrt@antlr.org Project Leader Developer - Java Target PST Sam Harwell Tunnel Vision Laboratories, LLC http://tunnelvisionlabs.com sam@tunnelvisionlabs.com Developer CST Jim Idle Temporal Wave LLC http://www.temporal-wave.com jimi@temporal-wave.com Developer - Maven stuff PST BSD licence http://antlr.org/license.html repo GitHub Issues https://github.com/antlr/stringtemplate4/issues git://github.com/antlr/stringtemplate4.git scm:git:git://github.com/antlr/stringtemplate4.git scm:git:git@github.com:antlr/stringtemplate4.git 4.0.8 junit junit 4.10 test org.antlr antlr-runtime 3.5.2 compile sonatype-oss-release org.apache.maven.plugins maven-compiler-plugin default-compile ${bootclasspath.compile} default-testCompile ${bootclasspath.testCompile} org.apache.maven.plugins maven-shade-plugin 2.2 package shade true false true true true complete org.antlr st4hidden.org.antlr install src test test org.apache.maven.plugins maven-jar-plugin 2.4 true org.antlr antlr3-maven-plugin 3.5.2 src/org/stringtemplate/v4/compiler src true antlr org.apache.maven.plugins maven-compiler-plugin 3.1 src true true -Xlint -Xlint:-serial default-compile 1.5 1.5 default-testCompile 1.6 1.6 org.apache.maven.plugins maven-release-plugin 2.5 -Psonatype-oss-release ${release.arguments} org.apache.maven.plugins maven-surefire-plugin 2.17 ${basedir}/src org.codehaus.mojo findbugs-maven-plugin 2.5.3 true true true org.apache.maven.plugins maven-source-plugin 2.2.1 org.apache.maven.plugins maven-javadoc-plugin 2.9.1 true org.apache.maven.plugins maven-gpg-plugin 1.5 stringtemplate4-4.0.8/src/000077500000000000000000000000001231426731300154425ustar00rootroot00000000000000stringtemplate4-4.0.8/src/org/000077500000000000000000000000001231426731300162315ustar00rootroot00000000000000stringtemplate4-4.0.8/src/org/stringtemplate/000077500000000000000000000000001231426731300212735ustar00rootroot00000000000000stringtemplate4-4.0.8/src/org/stringtemplate/v4/000077500000000000000000000000001231426731300216245ustar00rootroot00000000000000stringtemplate4-4.0.8/src/org/stringtemplate/v4/AttributeRenderer.java000066400000000000000000000041101231426731300261150ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4; import java.util.Locale; /** * This interface describes an object that knows how to format or otherwise * render an object appropriately. There is one renderer registered per group * for a given Java type. * *

* If the format string passed to the renderer is not recognized then simply * call {@link Object#toString}.

* *

* {@code formatString} can be {@code null} but {@code locale} will at least be * {@link Locale#getDefault}.

*/ public interface AttributeRenderer { public String toString(Object o, String formatString, Locale locale); } stringtemplate4-4.0.8/src/org/stringtemplate/v4/AutoIndentWriter.java000066400000000000000000000164721231426731300257500ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4; import java.io.IOException; import java.io.Writer; import java.util.ArrayList; import java.util.List; import java.util.Stack; /** * Essentially a char filter that knows how to auto-indent output by maintaining * a stack of indent levels. *

* The indent stack is a stack of strings so we can repeat original indent not * just the same number of columns (don't have to worry about tabs vs spaces * then). Anchors are char positions (tabs won't work) that indicate where all * future wraps should justify to. The wrap position is actually the larger of * either the last anchor or the indentation level.

*

* This is a filter on a {@link Writer}.

*

* {@code \n} is the proper way to say newline for options and templates. * Templates can mix {@code \r\n} and {@code \n} them, but use {@code \n} in * options like {@code wrap="\n"}. This writer will render newline characters * according to {@link #newline}. The default value is taken from the * {@code line.separator} system property, and can be overridden by passing in a * {@code String} to the appropriate constructor.

*/ public class AutoIndentWriter implements STWriter { /** Stack of indents. Use {@link List} as it's much faster than {@link Stack}. Grows * from 0..n-1. */ public List indents = new ArrayList(); /** Stack of integer anchors (char positions in line); avoid {@link Integer} * creation overhead. */ public int[] anchors = new int[10]; public int anchors_sp = -1; /** {@code \n} or {@code \r\n}? */ public String newline; public Writer out = null; public boolean atStartOfLine = true; /** * Track char position in the line (later we can think about tabs). Indexed * from 0. We want to keep {@code charPosition <= }{@link #lineWidth}. * This is the position we are about to write, not the position * last written to. */ public int charPosition = 0; /** The absolute char index into the output of the next char to be written. */ public int charIndex = 0; public int lineWidth = NO_WRAP; public AutoIndentWriter(Writer out, String newline) { this.out = out; indents.add(null); // s oftart with no indent this.newline = newline; } public AutoIndentWriter(Writer out) { this(out, System.getProperty("line.separator")); } @Override public void setLineWidth(int lineWidth) { this.lineWidth = lineWidth; } @Override public void pushIndentation(String indent) { indents.add(indent); } @Override public String popIndentation() { return indents.remove(indents.size()-1); } @Override public void pushAnchorPoint() { if ( (anchors_sp +1)>=anchors.length ) { int[] a = new int[anchors.length*2]; System.arraycopy(anchors, 0, a, 0, anchors.length-1); anchors = a; } anchors_sp++; anchors[anchors_sp] = charPosition; } @Override public void popAnchorPoint() { anchors_sp--; } @Override public int index() { return charIndex; } /** Write out a string literal or attribute expression or expression element. */ @Override public int write(String str) throws IOException { int n = 0; int nll = newline.length(); int sl = str.length(); for (int i=0; i * If doing line wrap, then check {@code wrap} before emitting {@code str}. * If at or beyond desired line width then emit a {@link #newline} and any * indentation before spitting out {@code str}.

*/ @Override public int write(String str, String wrap) throws IOException { int n = writeWrap(wrap); return n + write(str); } @Override public int writeWrap(String wrap) throws IOException { int n = 0; // if want wrap and not already at start of line (last char was \n) // and we have hit or exceeded the threshold if ( lineWidth!=NO_WRAP && wrap!=null && !atStartOfLine && charPosition >= lineWidth ) { // ok to wrap // Walk wrap string and look for A\nB. Spit out A\n // then spit indent or anchor, whichever is larger // then spit out B. for (int i=0; i=0 && anchors[anchors_sp]>indentWidth ) { int remainder = anchors[anchors_sp]-indentWidth; for (int i=1; i<=remainder; i++) out.write(' '); n += remainder; } charPosition += n; charIndex += n; return n; } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/DateRenderer.java000066400000000000000000000067051231426731300250430ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; /** * A renderer for {@link Date} and {@link Calendar} objects. It understands a * variety of format names as shown in {@link #formatToInt} field. By default it * assumes {@code "short"} format. A prefix of {@code "date:"} or * {@code "time:"} shows only those components of the time object. */ public class DateRenderer implements AttributeRenderer { public static final Map formatToInt = new HashMap() { { put("short", DateFormat.SHORT); put("medium", DateFormat.MEDIUM); put("long", DateFormat.LONG); put("full", DateFormat.FULL); put("date:short", DateFormat.SHORT); put("date:medium", DateFormat.MEDIUM); put("date:long", DateFormat.LONG); put("date:full", DateFormat.FULL); put("time:short", DateFormat.SHORT); put("time:medium", DateFormat.MEDIUM); put("time:long", DateFormat.LONG); put("time:full", DateFormat.FULL); } }; @Override public String toString(Object o, String formatString, Locale locale) { Date d; if ( formatString==null ) formatString = "short"; if ( o instanceof Calendar ) d = ((Calendar)o).getTime(); else d = (Date)o; Integer styleI = formatToInt.get(formatString); DateFormat f; if ( styleI==null ) f = new SimpleDateFormat(formatString, locale); else { int style = styleI.intValue(); if ( formatString.startsWith("date:") ) f = DateFormat.getDateInstance(style, locale); else if ( formatString.startsWith("time:") ) f = DateFormat.getTimeInstance(style, locale); else f = DateFormat.getDateTimeInstance(style, style, locale); } return f.format(d); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/InstanceScope.java000066400000000000000000000055541231426731300252360ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4; import org.stringtemplate.v4.debug.EvalTemplateEvent; import org.stringtemplate.v4.debug.InterpEvent; import org.stringtemplate.v4.gui.STViz; import java.util.ArrayList; import java.util.List; /** */ public class InstanceScope { /** Template that invoked us. */ public final InstanceScope parent; /** Template we're executing. */ public final ST st; /** Current instruction pointer. */ public int ip; /** * Includes the {@link EvalTemplateEvent} for this template. This is a * subset of {@link Interpreter#events} field. The final * {@link EvalTemplateEvent} is stored in 3 places: * *
    *
  1. In {@link #parent}'s {@link #childEvalTemplateEvents} list
  2. *
  3. In this list
  4. *
  5. In the {@link Interpreter#events} list
  6. *
* * The root ST has the final {@link EvalTemplateEvent} in its list. *

* All events get added to the {@link #parent}'s event list.

*/ public List events = new ArrayList(); /** All templates evaluated and embedded in this {@link ST}. Used * for tree view in {@link STViz}. */ public List childEvalTemplateEvents = new ArrayList(); public boolean earlyEval; public InstanceScope(InstanceScope parent, ST st) { this.parent = parent; this.st = st; this.earlyEval = parent != null && parent.earlyEval; } }stringtemplate4-4.0.8/src/org/stringtemplate/v4/Interpreter.java000066400000000000000000001341541231426731300250020ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4; import org.stringtemplate.v4.compiler.*; import org.stringtemplate.v4.compiler.Compiler; import org.stringtemplate.v4.debug.*; import org.stringtemplate.v4.gui.STViz; import org.stringtemplate.v4.misc.*; import java.io.*; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.util.*; /** * This class knows how to execute template bytecodes relative to a particular * {@link STGroup}. To execute the byte codes, we need an output stream and a * reference to an {@link ST} instance. That instance's {@link ST#impl} field * points at a {@link CompiledST}, which contains all of the byte codes and * other information relevant to execution. *

* This interpreter is a stack-based bytecode interpreter. All operands go onto * an operand stack.

*

* If {@link #debug} set, we track interpreter events. For now, I am only * tracking instance creation events. These are used by {@link STViz} to pair up * output chunks with the template expressions that generate them.

*

* We create a new interpreter for each invocation of * {@link ST#render}, {@link ST#inspect}, or {@link ST#getEvents}.

*/ public class Interpreter { public enum Option { ANCHOR, FORMAT, NULL, SEPARATOR, WRAP } public static final int DEFAULT_OPERAND_STACK_SIZE = 100; public static final Set predefinedAnonSubtemplateAttributes = new HashSet() { { add("i"); add("i0"); } }; /** Operand stack, grows upwards. */ Object[] operands = new Object[DEFAULT_OPERAND_STACK_SIZE]; /** Stack pointer register. */ int sp = -1; /** The number of characters written on this template line so far. */ int nwline = 0; /** Render template with respect to this group. * * @see ST#groupThatCreatedThisInstance * @see CompiledST#nativeGroup */ STGroup group; /** For renderers, we have to pass in the locale. */ Locale locale; ErrorManager errMgr; /** * Dump bytecode instructions as they are executed. This field is mostly for * StringTemplate development. */ public static boolean trace = false; /** If {@link #trace} is {@code true}, track trace here. */ // TODO: track the pieces not a string and track what it contributes to output protected List executeTrace; /** When {@code true}, track events inside templates and in {@link #events}. */ public boolean debug = false; /** * Track everything happening in interpreter across all templates if * {@link #debug}. The last event in this field is the * {@link EvalTemplateEvent} for the root template. */ protected List events; public Interpreter(STGroup group, boolean debug) { this(group,Locale.getDefault(),group.errMgr, debug); } public Interpreter(STGroup group, Locale locale, boolean debug) { this(group, locale, group.errMgr, debug); } public Interpreter(STGroup group, ErrorManager errMgr, boolean debug) { this(group,Locale.getDefault(),errMgr, debug); } public Interpreter(STGroup group, Locale locale, ErrorManager errMgr, boolean debug) { this.group = group; this.locale = locale; this.errMgr = errMgr; this.debug = debug; if ( debug ) { events = new ArrayList(); executeTrace = new ArrayList(); } } // public static int[] count = new int[Bytecode.MAX_BYTECODE+1]; // public static void dumpOpcodeFreq() { // System.out.println("#### instr freq:"); // for (int i=1; i<=Bytecode.MAX_BYTECODE; i++) { // System.out.println(count[i]+" "+Bytecode.instructions[i].name); // } // } /** Execute template {@code self} and return how many characters it wrote to {@code out}. * * @return the number of characters written to {@code out} */ public int exec(STWriter out, InstanceScope scope) { final ST self = scope.st; if ( trace ) System.out.println("exec("+self.getName()+")"); try { setDefaultArguments(out, scope); return _exec(out, scope); } catch (Exception e) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); pw.flush(); errMgr.runTimeError(this, scope, ErrorType.INTERNAL_ERROR, "internal error: "+sw.toString()); return 0; } } protected int _exec(STWriter out, InstanceScope scope) { final ST self = scope.st; int start = out.index(); // track char we're about to write int prevOpcode = 0; int n = 0; // how many char we write out int nargs; int nameIndex; int addr; String name; Object o, left, right; ST st; Object[] options; byte[] code = self.impl.instrs; // which code block are we executing int ip = 0; while ( ip < self.impl.codeSize ) { if ( trace || debug ) trace(scope, ip); short opcode = code[ip]; //count[opcode]++; scope.ip = ip; ip++; //jump to next instruction or first byte of operand switch (opcode) { case Bytecode.INSTR_LOAD_STR : // just testing... load_str(self,ip); ip += Bytecode.OPND_SIZE_IN_BYTES; break; case Bytecode.INSTR_LOAD_ATTR : nameIndex = getShort(code, ip); ip += Bytecode.OPND_SIZE_IN_BYTES; name = self.impl.strings[nameIndex]; try { o = getAttribute(scope, name); if ( o==ST.EMPTY_ATTR ) o = null; } catch (STNoSuchAttributeException nsae) { errMgr.runTimeError(this, scope, ErrorType.NO_SUCH_ATTRIBUTE, name); o = null; } operands[++sp] = o; break; case Bytecode.INSTR_LOAD_LOCAL: int valueIndex = getShort(code, ip); ip += Bytecode.OPND_SIZE_IN_BYTES; o = self.locals[valueIndex]; if ( o==ST.EMPTY_ATTR ) o = null; operands[++sp] = o; break; case Bytecode.INSTR_LOAD_PROP : nameIndex = getShort(code, ip); ip += Bytecode.OPND_SIZE_IN_BYTES; o = operands[sp--]; name = self.impl.strings[nameIndex]; operands[++sp] = getObjectProperty(out, scope, o, name); break; case Bytecode.INSTR_LOAD_PROP_IND : Object propName = operands[sp--]; o = operands[sp]; operands[sp] = getObjectProperty(out, scope, o, propName); break; case Bytecode.INSTR_NEW : nameIndex = getShort(code, ip); ip += Bytecode.OPND_SIZE_IN_BYTES; name = self.impl.strings[nameIndex]; nargs = getShort(code, ip); ip += Bytecode.OPND_SIZE_IN_BYTES; // look up in original hierarchy not enclosing template (variable group) // see TestSubtemplates.testEvalSTFromAnotherGroup() st = self.groupThatCreatedThisInstance.getEmbeddedInstanceOf(this, scope, name); // get n args and store into st's attr list storeArgs(scope, nargs, st); sp -= nargs; operands[++sp] = st; break; case Bytecode.INSTR_NEW_IND: nargs = getShort(code, ip); ip += Bytecode.OPND_SIZE_IN_BYTES; name = (String)operands[sp-nargs]; st = self.groupThatCreatedThisInstance.getEmbeddedInstanceOf(this, scope, name); storeArgs(scope, nargs, st); sp -= nargs; sp--; // pop template name operands[++sp] = st; break; case Bytecode.INSTR_NEW_BOX_ARGS : nameIndex = getShort(code, ip); ip += Bytecode.OPND_SIZE_IN_BYTES; name = self.impl.strings[nameIndex]; Map attrs = (ArgumentsMap)operands[sp--]; // look up in original hierarchy not enclosing template (variable group) // see TestSubtemplates.testEvalSTFromAnotherGroup() st = self.groupThatCreatedThisInstance.getEmbeddedInstanceOf(this, scope, name); // get n args and store into st's attr list storeArgs(scope, attrs, st); operands[++sp] = st; break; case Bytecode.INSTR_SUPER_NEW : nameIndex = getShort(code, ip); ip += Bytecode.OPND_SIZE_IN_BYTES; name = self.impl.strings[nameIndex]; nargs = getShort(code, ip); ip += Bytecode.OPND_SIZE_IN_BYTES; super_new(scope, name, nargs); break; case Bytecode.INSTR_SUPER_NEW_BOX_ARGS : nameIndex = getShort(code, ip); ip += Bytecode.OPND_SIZE_IN_BYTES; name = self.impl.strings[nameIndex]; attrs = (ArgumentsMap)operands[sp--]; super_new(scope, name, attrs); break; case Bytecode.INSTR_STORE_OPTION: int optionIndex = getShort(code, ip); ip += Bytecode.OPND_SIZE_IN_BYTES; o = operands[sp--]; // value to store options = (Object[])operands[sp]; // get options options[optionIndex] = o; // store value into options on stack break; case Bytecode.INSTR_STORE_ARG: nameIndex = getShort(code, ip); name = self.impl.strings[nameIndex]; ip += Bytecode.OPND_SIZE_IN_BYTES; o = operands[sp--]; attrs = (ArgumentsMap)operands[sp]; attrs.put(name, o); // leave attrs on stack break; case Bytecode.INSTR_WRITE : o = operands[sp--]; int n1 = writeObjectNoOptions(out, scope, o); n += n1; nwline += n1; break; case Bytecode.INSTR_WRITE_OPT : options = (Object[])operands[sp--]; // get options o = operands[sp--]; // get option to write int n2 = writeObjectWithOptions(out, scope, o, options); n += n2; nwline += n2; break; case Bytecode.INSTR_MAP : st = (ST)operands[sp--]; // get prototype off stack o = operands[sp--]; // get object to map prototype across map(scope,o,st); break; case Bytecode.INSTR_ROT_MAP : int nmaps = getShort(code, ip); ip += Bytecode.OPND_SIZE_IN_BYTES; List templates = new ArrayList(); for (int i=nmaps-1; i>=0; i--) templates.add((ST)operands[sp-i]); sp -= nmaps; o = operands[sp--]; if ( o!=null ) rot_map(scope,o,templates); break; case Bytecode.INSTR_ZIP_MAP: st = (ST)operands[sp--]; nmaps = getShort(code, ip); ip += Bytecode.OPND_SIZE_IN_BYTES; List exprs = new ObjectList(); for (int i=nmaps-1; i>=0; i--) exprs.add(operands[sp-i]); sp -= nmaps; operands[++sp] = zip_map(scope, exprs, st); break; case Bytecode.INSTR_BR : ip = getShort(code, ip); break; case Bytecode.INSTR_BRF : addr = getShort(code, ip); ip += Bytecode.OPND_SIZE_IN_BYTES; o = operands[sp--]; // ... if ( !testAttributeTrue(o) ) ip = addr; // jump break; case Bytecode.INSTR_OPTIONS : operands[++sp] = new Object[Compiler.NUM_OPTIONS]; break; case Bytecode.INSTR_ARGS: operands[++sp] = new ArgumentsMap(); break; case Bytecode.INSTR_PASSTHRU : nameIndex = getShort(code, ip); ip += Bytecode.OPND_SIZE_IN_BYTES; name = self.impl.strings[nameIndex]; attrs = (ArgumentsMap)operands[sp]; passthru(scope, name, attrs); break; case Bytecode.INSTR_LIST : operands[++sp] = new ObjectList(); break; case Bytecode.INSTR_ADD : o = operands[sp--]; // pop value List list = (ObjectList)operands[sp]; // don't pop list addToList(scope, list, o); break; case Bytecode.INSTR_TOSTR : // replace with string value; early eval operands[sp] = toString(out, scope, operands[sp]); break; case Bytecode.INSTR_FIRST : operands[sp] = first(scope, operands[sp]); break; case Bytecode.INSTR_LAST : operands[sp] = last(scope, operands[sp]); break; case Bytecode.INSTR_REST : operands[sp] = rest(scope, operands[sp]); break; case Bytecode.INSTR_TRUNC : operands[sp] = trunc(scope, operands[sp]); break; case Bytecode.INSTR_STRIP : operands[sp] = strip(scope, operands[sp]); break; case Bytecode.INSTR_TRIM : o = operands[sp--]; if ( o.getClass() == String.class ) { operands[++sp] = ((String)o).trim(); } else { errMgr.runTimeError(this, scope, ErrorType.EXPECTING_STRING, "trim", o.getClass().getName()); operands[++sp] = o; } break; case Bytecode.INSTR_LENGTH : operands[sp] = length(operands[sp]); break; case Bytecode.INSTR_STRLEN : o = operands[sp--]; if ( o.getClass() == String.class ) { operands[++sp] = ((String)o).length(); } else { errMgr.runTimeError(this, scope, ErrorType.EXPECTING_STRING, "strlen", o.getClass().getName()); operands[++sp] = 0; } break; case Bytecode.INSTR_REVERSE : operands[sp] = reverse(scope, operands[sp]); break; case Bytecode.INSTR_NOT : operands[sp] = !testAttributeTrue(operands[sp]); break; case Bytecode.INSTR_OR : right = operands[sp--]; left = operands[sp--]; operands[++sp] = testAttributeTrue(left) || testAttributeTrue(right); break; case Bytecode.INSTR_AND : right = operands[sp--]; left = operands[sp--]; operands[++sp] = testAttributeTrue(left) && testAttributeTrue(right); break; case Bytecode.INSTR_INDENT : int strIndex = getShort(code, ip); ip += Bytecode.OPND_SIZE_IN_BYTES; indent(out, scope, strIndex); break; case Bytecode.INSTR_DEDENT : out.popIndentation(); break; case Bytecode.INSTR_NEWLINE : try { if ( prevOpcode==Bytecode.INSTR_NEWLINE || prevOpcode==Bytecode.INSTR_INDENT || nwline>0 ) { out.write(Misc.newline); } nwline = 0; } catch (IOException ioe) { errMgr.IOError(self, ErrorType.WRITE_IO_ERROR, ioe); } break; case Bytecode.INSTR_NOOP : break; case Bytecode.INSTR_POP : sp--; // throw away top of stack break; case Bytecode.INSTR_NULL : operands[++sp] = null; break; case Bytecode.INSTR_TRUE : operands[++sp] = true; break; case Bytecode.INSTR_FALSE : operands[++sp] = false; break; case Bytecode.INSTR_WRITE_STR : strIndex = getShort(code, ip); ip += Bytecode.OPND_SIZE_IN_BYTES; o = self.impl.strings[strIndex]; n1 = writeObjectNoOptions(out, scope, o); n += n1; nwline += n1; break; // TODO: generate this optimization // case Bytecode.INSTR_WRITE_LOCAL: // valueIndex = getShort(code, ip); // ip += Bytecode.OPND_SIZE_IN_BYTES; // o = self.locals[valueIndex]; // if ( o==ST.EMPTY_ATTR ) o = null; // n1 = writeObjectNoOptions(out, self, o); // n += n1; // nwline += n1; // break; default : errMgr.internalError(self, "invalid bytecode @ "+(ip-1)+": "+opcode, null); self.impl.dump(); } prevOpcode = opcode; } if ( debug ) { int stop = out.index() - 1; EvalTemplateEvent e = new EvalTemplateEvent(scope, start, stop); trackDebugEvent(scope, e); } return n; } void load_str(ST self, int ip) { int strIndex = getShort(self.impl.instrs, ip); ip += Bytecode.OPND_SIZE_IN_BYTES; operands[++sp] = self.impl.strings[strIndex]; } // TODO: refactor to remove dup'd code void super_new(InstanceScope scope, String name, int nargs) { final ST self = scope.st; ST st = null; CompiledST imported = self.impl.nativeGroup.lookupImportedTemplate(name); if ( imported==null ) { errMgr.runTimeError(this, scope, ErrorType.NO_IMPORTED_TEMPLATE, name); st = self.groupThatCreatedThisInstance.createStringTemplateInternally(new CompiledST()); } else { st = imported.nativeGroup.getEmbeddedInstanceOf(this, scope, name); st.groupThatCreatedThisInstance = group; } // get n args and store into st's attr list storeArgs(scope, nargs, st); sp -= nargs; operands[++sp] = st; } void super_new(InstanceScope scope, String name, Map attrs) { final ST self = scope.st; ST st = null; CompiledST imported = self.impl.nativeGroup.lookupImportedTemplate(name); if ( imported==null ) { errMgr.runTimeError(this, scope, ErrorType.NO_IMPORTED_TEMPLATE, name); st = self.groupThatCreatedThisInstance.createStringTemplateInternally(new CompiledST()); } else { st = imported.nativeGroup.createStringTemplateInternally(imported); st.groupThatCreatedThisInstance = group; } // get n args and store into st's attr list storeArgs(scope, attrs, st); operands[++sp] = st; } void passthru(InstanceScope scope, String templateName, Map attrs) { CompiledST c = group.lookupTemplate(templateName); if ( c==null ) return; // will get error later if ( c.formalArguments==null ) return; for (FormalArgument arg : c.formalArguments.values()) { // if not already set by user, set to value from outer scope if ( !attrs.containsKey(arg.name) ) { //System.out.println("arg "+arg.name+" missing"); try { Object o = getAttribute(scope, arg.name); // If the attribute exists but there is no value and // the formal argument has no default value, make it null. if ( o==ST.EMPTY_ATTR && arg.defaultValueToken==null ) { attrs.put(arg.name, null); } // Else, the attribute has an existing value, set arg. else if ( o!=ST.EMPTY_ATTR ) { attrs.put(arg.name, o); } } catch (STNoSuchAttributeException nsae) { // if no such attribute exists for arg.name, set parameter // if no default value if ( arg.defaultValueToken==null ) { errMgr.runTimeError(this, scope, ErrorType.NO_SUCH_ATTRIBUTE_PASS_THROUGH, arg.name); attrs.put(arg.name, null); } } } } } void storeArgs(InstanceScope scope, Map attrs, ST st) { if (st.impl.hasFormalArgs) { boolean argumentCountMismatch = false; Map formalArguments = st.impl.formalArguments; if (formalArguments == null) { formalArguments = Collections.emptyMap(); } // first make sure that all non-default arguments are specified for (Map.Entry formalArgument : formalArguments.entrySet()) { if (formalArgument.getValue().defaultValueToken != null || formalArgument.getValue().defaultValue != null) { // this argument has a default value, so it doesn't need to appear in attrs continue; } if (attrs == null || !attrs.containsKey(formalArgument.getKey())) { argumentCountMismatch = true; break; } } // next make sure there aren't too many arguments. note that the names // of arguments are checked below as they are applied to the template // instance, so there's no need to do that here. if (attrs != null && attrs.size() > formalArguments.size()) { argumentCountMismatch = true; } if (argumentCountMismatch) { int nargs = attrs != null ? attrs.size() : 0; int nformalArgs = formalArguments.size(); errMgr.runTimeError(this, scope, ErrorType.ARGUMENT_COUNT_MISMATCH, nargs, st.impl.name, nformalArgs); } } if (attrs != null) { for (Map.Entry argument : attrs.entrySet()) { if (!st.impl.hasFormalArgs) { if (st.impl.formalArguments == null || !st.impl.formalArguments.containsKey(argument.getKey())) { try { // we clone the CompiledST to prevent modifying the original // formalArguments map during interpretation. st.impl = st.impl.clone(); st.add(argument.getKey(), argument.getValue()); } catch (CloneNotSupportedException ex) { errMgr.runTimeError(this, scope, ErrorType.NO_SUCH_ATTRIBUTE, argument.getKey()); } } else { st.rawSetAttribute(argument.getKey(), argument.getValue()); } } else { // don't let it throw an exception in rawSetAttribute if ( st.impl.formalArguments==null || !st.impl.formalArguments.containsKey(argument.getKey()) ) { errMgr.runTimeError(this, scope, ErrorType.NO_SUCH_ATTRIBUTE, argument.getKey()); continue; } st.rawSetAttribute(argument.getKey(), argument.getValue()); } } } } void storeArgs(InstanceScope scope, int nargs, ST st) { if ( nargs>0 && !st.impl.hasFormalArgs && st.impl.formalArguments==null ) { st.add(ST.IMPLICIT_ARG_NAME, null); // pretend we have "it" arg } int nformalArgs = 0; if ( st.impl.formalArguments!=null ) nformalArgs = st.impl.formalArguments.size(); int firstArg = sp-(nargs-1); int numToStore = Math.min(nargs, nformalArgs); if ( st.impl.isAnonSubtemplate ) nformalArgs -= predefinedAnonSubtemplateAttributes.size(); if ( nargs < (nformalArgs-st.impl.numberOfArgsWithDefaultValues) || nargs > nformalArgs ) { errMgr.runTimeError(this, scope, ErrorType.ARGUMENT_COUNT_MISMATCH, nargs, st.impl.name, nformalArgs); } if ( st.impl.formalArguments==null ) return; Iterator argNames = st.impl.formalArguments.keySet().iterator(); for (int i=0; i} */ protected int writeObjectNoOptions(STWriter out, InstanceScope scope, Object o) { int start = out.index(); // track char we're about to write int n = writeObject(out, scope, o, null); if ( debug ) { EvalExprEvent e = new EvalExprEvent(scope, start, out.index() - 1, getExprStartChar(scope), getExprStopChar(scope)); trackDebugEvent(scope, e); } return n; } /** Write out an expression result that uses expression options. * E.g., {@code } */ protected int writeObjectWithOptions(STWriter out, InstanceScope scope, Object o, Object[] options) { int start = out.index(); // track char we're about to write // precompute all option values (render all the way to strings) String[] optionStrings = null; if ( options!=null ) { optionStrings = new String[options.length]; for (int i=0; i it = (Iterator)o; String separator = null; if ( options!=null ) separator = options[Option.SEPARATOR.ordinal()]; boolean seenAValue = false; while ( it.hasNext() ) { Object iterValue = it.next(); // Emit separator if we're beyond first value boolean needSeparator = seenAValue && separator!=null && // we have a separator and (iterValue!=null || // either we have a value options[Option.NULL.ordinal()]!=null); // or no value but null option if ( needSeparator ) n += out.writeSeparator(separator); int nw = writeObject(out, scope, iterValue, options); if ( nw > 0 ) seenAValue = true; n += nw; } return n; } protected int writePOJO(STWriter out, InstanceScope scope, Object o, String[] options) throws IOException { String formatString = null; if ( options!=null ) formatString = options[Option.FORMAT.ordinal()]; // ask the native group defining the surrounding template for the renderer AttributeRenderer r = scope.st.impl.nativeGroup.getAttributeRenderer(o.getClass()); String v; if ( r!=null ) v = r.toString(o, formatString, locale); else v = o.toString(); int n; if ( options!=null && options[Option.WRAP.ordinal()]!=null ) { n = out.write(v, options[Option.WRAP.ordinal()]); } else { n = out.write(v); } return n; } protected int getExprStartChar(InstanceScope scope) { Interval templateLocation = scope.st.impl.sourceMap[scope.ip]; if ( templateLocation!=null ) return templateLocation.a; return -1; } protected int getExprStopChar(InstanceScope scope) { Interval templateLocation = scope.st.impl.sourceMap[scope.ip]; if ( templateLocation!=null ) return templateLocation.b; return -1; } protected void map(InstanceScope scope, Object attr, final ST st) { rot_map(scope, attr, new ArrayList() {{add(st);}}); } /** * Renders expressions of the form {@code } or * {@code }. */ protected void rot_map(InstanceScope scope, Object attr, List prototypes) { if ( attr==null ) { operands[++sp] = null; return; } attr = convertAnythingIteratableToIterator(scope, attr); if ( attr instanceof Iterator ) { List mapped = rot_map_iterator(scope, (Iterator) attr, prototypes); operands[++sp] = mapped; } else { // if only single value, just apply first template to sole value ST proto = prototypes.get(0); ST st = group.createStringTemplateInternally(proto); if ( st!=null ) { setFirstArgument(scope, st, attr); if ( st.impl.isAnonSubtemplate ) { st.rawSetAttribute("i0", 0); st.rawSetAttribute("i", 1); } operands[++sp] = st; } else { operands[++sp] = null; } } } protected List rot_map_iterator(InstanceScope scope, Iterator attr, List prototypes) { List mapped = new ArrayList(); Iterator iter = attr; int i0 = 0; int i = 1; int ti = 0; while ( iter.hasNext() ) { Object iterValue = iter.next(); if ( iterValue == null ) { mapped.add(null); continue; } int templateIndex = ti % prototypes.size(); // rotate through ti++; ST proto = prototypes.get(templateIndex); ST st = group.createStringTemplateInternally(proto); setFirstArgument(scope, st, iterValue); if ( st.impl.isAnonSubtemplate ) { st.rawSetAttribute("i0", i0); st.rawSetAttribute("i", i); } mapped.add(st); i0++; i++; } return mapped; } /** * Renders expressions of the form {@code } or * {@code }. */ // todo: i, i0 not set unless mentioned? map:{k,v | ..}? protected ST.AttributeList zip_map(InstanceScope scope, List exprs, ST prototype) { if ( exprs==null || prototype==null || exprs.size()==0 ) { return null; // do not apply if missing templates or empty values } // make everything iterable for (int i = 0; i < exprs.size(); i++) { Object attr = exprs.get(i); if ( attr!=null ) exprs.set(i, convertAnythingToIterator(scope, attr)); } // ensure arguments line up int numExprs = exprs.size(); CompiledST code = prototype.impl; Map formalArguments = code.formalArguments; if ( !code.hasFormalArgs || formalArguments==null ) { errMgr.runTimeError(this, scope, ErrorType.MISSING_FORMAL_ARGUMENTS); return null; } // todo: track formal args not names for efficient filling of locals String[] formalArgumentNames = formalArguments.keySet().toArray(new String[formalArguments.size()]); int nformalArgs = formalArgumentNames.length; if ( prototype.isAnonSubtemplate() ) nformalArgs -= predefinedAnonSubtemplateAttributes.size(); if ( nformalArgs != numExprs ) { errMgr.runTimeError(this, scope, ErrorType.MAP_ARGUMENT_COUNT_MISMATCH, numExprs, nformalArgs); // TODO just fill first n // truncate arg list to match smaller size int shorterSize = Math.min(formalArgumentNames.length, numExprs); numExprs = shorterSize; String[] newFormalArgumentNames = new String[shorterSize]; System.arraycopy(formalArgumentNames, 0, newFormalArgumentNames, 0, shorterSize); formalArgumentNames = newFormalArgumentNames; } // keep walking while at least one attribute has values ST.AttributeList results = new ST.AttributeList(); int i = 0; // iteration number from 0 while ( true ) { // get a value for each attribute in list; put into ST instance int numEmpty = 0; ST embedded = group.createStringTemplateInternally(prototype); embedded.rawSetAttribute("i0", i); embedded.rawSetAttribute("i", i+1); for (int a = 0; a < numExprs; a++) { Iterator it = (Iterator) exprs.get(a); if ( it!=null && it.hasNext() ) { String argName = formalArgumentNames[a]; Object iteratedValue = it.next(); embedded.rawSetAttribute(argName, iteratedValue); } else { numEmpty++; } } if ( numEmpty==numExprs ) break; results.add(embedded); i++; } return results; } protected void setFirstArgument(InstanceScope scope, ST st, Object attr) { if ( !st.impl.hasFormalArgs ) { if ( st.impl.formalArguments==null ) { st.add(ST.IMPLICIT_ARG_NAME, attr); return; } // else fall thru to set locals[0] } if ( st.impl.formalArguments==null ) { errMgr.runTimeError(this, scope, ErrorType.ARGUMENT_COUNT_MISMATCH, 1, st.impl.name, 0); return; } st.locals[0] = attr; } protected void addToList(InstanceScope scope, List list, Object o) { o = convertAnythingIteratableToIterator(scope, o); if ( o instanceof Iterator ) { // copy of elements into our temp list Iterator it = (Iterator)o; while (it.hasNext()) list.add(it.next()); } else { list.add(o); } } /** * Return the first attribute if multi-valued, or the attribute itself if * single-valued. *

* This method is used for rendering expressions of the form * {@code }.

*/ public Object first(InstanceScope scope, Object v) { if ( v==null ) return null; Object r = v; v = convertAnythingIteratableToIterator(scope, v); if ( v instanceof Iterator ) { Iterator it = (Iterator)v; if ( it.hasNext() ) { r = it.next(); } } return r; } /** * Return the last attribute if multi-valued, or the attribute itself if * single-valued. Unless it's a {@link List} or array, this is pretty slow * as it iterates until the last element. *

* This method is used for rendering expressions of the form * {@code }.

*/ public Object last(InstanceScope scope, Object v) { if ( v==null ) return null; if ( v instanceof List ) return ((List)v).get(((List)v).size()-1); else if ( v.getClass().isArray() ) { return Array.get(v, Array.getLength(v) - 1); } Object last = v; v = convertAnythingIteratableToIterator(scope, v); if ( v instanceof Iterator ) { Iterator it = (Iterator)v; while ( it.hasNext() ) { last = it.next(); } } return last; } /** * Return everything but the first attribute if multi-valued, or * {@code null} if single-valued. */ public Object rest(InstanceScope scope, Object v) { if ( v == null ) return null; if ( v instanceof List ) { // optimize list case List elems = (List)v; if ( elems.size()<=1 ) return null; return elems.subList(1, elems.size()); } v = convertAnythingIteratableToIterator(scope, v); if ( v instanceof Iterator ) { List a = new ArrayList(); Iterator it = (Iterator)v; if ( !it.hasNext() ) return null; // if not even one value return null it.next(); // ignore first value while (it.hasNext()) { Object o = it.next(); a.add(o); } return a; } return null; // rest of single-valued attribute is null } /** Return all but the last element. trunc(x)==null if x is single-valued. */ public Object trunc(InstanceScope scope, Object v) { if ( v ==null ) return null; if ( v instanceof List ) { // optimize list case List elems = (List)v; if ( elems.size()<=1 ) return null; return elems.subList(0, elems.size()-1); } v = convertAnythingIteratableToIterator(scope, v); if ( v instanceof Iterator ) { List a = new ArrayList(); Iterator it = (Iterator) v; while (it.hasNext()) { Object o = it.next(); if ( it.hasNext() ) a.add(o); // only add if not last one } return a; } return null; // trunc(x)==null when x single-valued attribute } /** Return a new list without {@code null} values. */ public Object strip(InstanceScope scope, Object v) { if ( v ==null ) return null; v = convertAnythingIteratableToIterator(scope, v); if ( v instanceof Iterator ) { List a = new ArrayList(); Iterator it = (Iterator) v; while (it.hasNext()) { Object o = it.next(); if ( o!=null ) a.add(o); } return a; } return v; // strip(x)==x when x single-valued attribute } /** * Return a list with the same elements as {@code v} but in reverse order. *

* Note that {@code null} values are not stripped out; use * {@code reverse(strip(v))} to do that.

*/ public Object reverse(InstanceScope scope, Object v) { if ( v==null ) return null; v = convertAnythingIteratableToIterator(scope, v); if ( v instanceof Iterator ) { List a = new LinkedList(); Iterator it = (Iterator)v; while (it.hasNext()) a.add(0, it.next()); return a; } return v; } /** * Return the length of a multi-valued attribute or 1 if it is a single * attribute. If {@code v} is {@code null} return 0. *

* The implementation treats several common collections and arrays as * special cases for speed.

*/ public Object length(Object v) { if ( v == null) return 0; int i = 1; // we have at least one of something. Iterator and arrays might be empty. if ( v instanceof Map ) i = ((Map)v).size(); else if ( v instanceof Collection ) i = ((Collection)v).size(); else if ( v instanceof Object[] ) i = ((Object[])v).length; else if ( v.getClass().isArray() ) i = Array.getLength(v); else if ( v instanceof Iterator) { Iterator it = (Iterator)v; i = 0; while ( it.hasNext() ) { it.next(); i++; } } return i; } protected String toString(STWriter out, InstanceScope scope, Object value) { if ( value!=null ) { if ( value.getClass()==String.class ) return (String)value; // if not string already, must evaluate it StringWriter sw = new StringWriter(); STWriter stw; try { Class writerClass = out.getClass(); Constructor ctor = writerClass.getConstructor(Writer.class); stw = ctor.newInstance(sw); } catch (Exception e) { stw = new AutoIndentWriter(sw); errMgr.runTimeError(this, scope, ErrorType.WRITER_CTOR_ISSUE, out.getClass().getSimpleName()); } if (debug && !scope.earlyEval) { scope = new InstanceScope(scope, scope.st); scope.earlyEval = true; } writeObjectNoOptions(stw, scope, value); return sw.toString(); } return null; } public Object convertAnythingIteratableToIterator(InstanceScope scope, Object o) { Iterator iter = null; if ( o == null ) return null; if ( o instanceof Collection ) iter = ((Collection)o).iterator(); else if ( o instanceof Object[] ) iter = Arrays.asList((Object[])o).iterator(); else if ( o.getClass().isArray() ) iter = new ArrayIterator(o); else if ( o instanceof Map ) { if (scope.st.groupThatCreatedThisInstance.iterateAcrossValues) { iter = ((Map)o).values().iterator(); } else { iter = ((Map)o).keySet().iterator(); } } //// this is implied by the following line //else if ( o instanceof Iterator ) { // iter = (Iterator)o; //} if ( iter==null ) return o; return iter; } public Iterator convertAnythingToIterator(InstanceScope scope, Object o) { o = convertAnythingIteratableToIterator(scope, o); if ( o instanceof Iterator ) return (Iterator)o; List singleton = new ST.AttributeList(1); singleton.add(o); return singleton.iterator(); } protected boolean testAttributeTrue(Object a) { if ( a==null ) return false; if ( a instanceof Boolean ) return (Boolean)a; if ( a instanceof Collection ) return ((Collection)a).size()>0; if ( a instanceof Map ) return ((Map)a).size()>0; if ( a instanceof Iterator ) return ((Iterator)a).hasNext(); return true; // any other non-null object, return true--it's present } protected Object getObjectProperty(STWriter out, InstanceScope scope, Object o, Object property) { if ( o==null ) { errMgr.runTimeError(this, scope, ErrorType.NO_SUCH_PROPERTY, "null." + property); return null; } try { final ST self = scope.st; ModelAdaptor adap = self.groupThatCreatedThisInstance.getModelAdaptor(o.getClass()); return adap.getProperty(this, self, o, property, toString(out,scope,property)); } catch (STNoSuchPropertyException e) { errMgr.runTimeError(this, scope, ErrorType.NO_SUCH_PROPERTY, e, o.getClass().getName()+"."+property); } return null; } /** * Find an attribute via dynamic scoping up enclosing scope chain. Only look * for a dictionary definition if the attribute is not found, so attributes * sent in to a template override dictionary names. *

* Return {@link ST#EMPTY_ATTR} if found definition but no value.

*/ public Object getAttribute(InstanceScope scope, String name) { InstanceScope current = scope; while ( current!=null ) { ST p = current.st; FormalArgument localArg = null; if ( p.impl.formalArguments!=null ) localArg = p.impl.formalArguments.get(name); if ( localArg!=null ) { Object o = p.locals[localArg.index]; return o; } current = current.parent; // look up enclosing scope chain } // got to root scope and no definition, try dictionaries in group and up final ST self = scope.st; STGroup g = self.impl.nativeGroup; Object o = getDictionary(g, name); if ( o!=null ) return o; // not found, report unknown attr throw new STNoSuchAttributeException(name, scope); } public Object getDictionary(STGroup g, String name) { if ( g.isDictionary(name) ) { return g.rawGetDictionary(name); } if ( g.imports!=null ) { for (STGroup sup : g.imports) { Object o = getDictionary(sup, name); if ( o!=null ) return o; } } return null; } /** * Set any default argument values that were not set by the invoking * template or by {@link ST#add} directly. Note that the default values may * be templates. *

* The evaluation context is the {@code invokedST} template itself so * template default arguments can see other arguments.

*/ public void setDefaultArguments(STWriter out, InstanceScope scope) { final ST invokedST = scope.st; if ( invokedST.impl.formalArguments==null || invokedST.impl.numberOfArgsWithDefaultValues==0 ) { return; } for (FormalArgument arg : invokedST.impl.formalArguments.values()) { // if no value for attribute and default arg, inject default arg into self if ( invokedST.locals[arg.index]!=ST.EMPTY_ATTR || arg.defaultValueToken==null ) { continue; } //System.out.println("setting def arg "+arg.name+" to "+arg.defaultValueToken); if ( arg.defaultValueToken.getType()==GroupParser.ANONYMOUS_TEMPLATE ) { CompiledST code = arg.compiledDefaultValue; if (code == null) { code = new CompiledST(); } ST defaultArgST = group.createStringTemplateInternally(code); defaultArgST.groupThatCreatedThisInstance = group; // If default arg is template with single expression // wrapped in parens, x={<(...)>}, then eval to string // rather than setting x to the template for later // eval. String defArgTemplate = arg.defaultValueToken.getText(); if ( defArgTemplate.startsWith("{"+group.delimiterStartChar+"(") && defArgTemplate.endsWith(")"+group.delimiterStopChar+"}") ) { invokedST.rawSetAttribute(arg.name, toString(out, new InstanceScope(scope, invokedST), defaultArgST)); } else { invokedST.rawSetAttribute(arg.name, defaultArgST); } } else { invokedST.rawSetAttribute(arg.name, arg.defaultValue); } } } /** * If an instance of x is enclosed in a y which is in a * z, return a {@code String} of these instance names in order from * topmost to lowest; here that would be {@code [z y x]}. */ public static String getEnclosingInstanceStackString(InstanceScope scope) { List templates = getEnclosingInstanceStack(scope, true); StringBuilder buf = new StringBuilder(); int i = 0; for (ST st : templates) { if ( i>0 ) buf.append(" "); buf.append(st.getName()); i++; } return buf.toString(); } public static List getEnclosingInstanceStack(InstanceScope scope, boolean topdown) { List stack = new LinkedList(); InstanceScope p = scope; while ( p!=null ) { if ( topdown ) stack.add(0,p.st); else stack.add(p.st); p = p.parent; } return stack; } public static List getScopeStack(InstanceScope scope, boolean topdown) { List stack = new LinkedList(); InstanceScope p = scope; while ( p!=null ) { if ( topdown ) stack.add(0,p); else stack.add(p); p = p.parent; } return stack; } public static List getEvalTemplateEventStack(InstanceScope scope, boolean topdown) { List stack = new LinkedList(); InstanceScope p = scope; while ( p!=null ) { EvalTemplateEvent eval = (EvalTemplateEvent)p.events.get(p.events.size()-1); if ( topdown ) stack.add(0,eval); else stack.add(eval); p = p.parent; } return stack; } protected void trace(InstanceScope scope, int ip) { final ST self = scope.st; StringBuilder tr = new StringBuilder(); BytecodeDisassembler dis = new BytecodeDisassembler(self.impl); StringBuilder buf = new StringBuilder(); dis.disassembleInstruction(buf,ip); String name = self.impl.name+":"; if ( Misc.referenceEquals(self.impl.name, ST.UNKNOWN_NAME) ) name = ""; tr.append(String.format("%-40s",name+buf)); tr.append("\tstack=["); for (int i = 0; i <= sp; i++) { Object o = operands[i]; printForTrace(tr,scope,o); } tr.append(" ], calls="); tr.append(getEnclosingInstanceStackString(scope)); tr.append(", sp="+sp+", nw="+ nwline); String s = tr.toString(); if ( debug ) executeTrace.add(s); if ( trace ) System.out.println(s); } protected void printForTrace(StringBuilder tr, InstanceScope scope, Object o) { if ( o instanceof ST ) { if ( ((ST)o).impl ==null ) tr.append("bad-template()"); else tr.append(" "+((ST)o).impl.name+"()"); return; } o = convertAnythingIteratableToIterator(scope, o); if ( o instanceof Iterator ) { Iterator it = (Iterator)o; tr.append(" ["); while ( it.hasNext() ) { Object iterValue = it.next(); printForTrace(tr, scope, iterValue); } tr.append(" ]"); } else { tr.append(" "+o); } } public List getEvents() { return events; } /** * For every event, we track in overall {@link #events} list and in * {@code self}'s {@link InstanceScope#events} list so that each template * has a list of events used to create it. If {@code e} is an * {@link EvalTemplateEvent}, store in parent's * {@link InstanceScope#childEvalTemplateEvents} list for {@link STViz} tree * view. */ protected void trackDebugEvent(InstanceScope scope, InterpEvent e) { // System.out.println(e); this.events.add(e); scope.events.add(e); if ( e instanceof EvalTemplateEvent ) { InstanceScope parent = scope.parent; if ( parent!=null ) { // System.out.println("add eval "+e.self.getName()+" to children of "+parent.getName()); scope.parent.childEvalTemplateEvents.add((EvalTemplateEvent)e); } } } public List getExecutionTrace() { return executeTrace; } public static int getShort(byte[] memory, int index) { int b1 = memory[index]&0xFF; // mask off sign-extended bits int b2 = memory[index+1]&0xFF; return b1<<(8*1) | b2; } protected static class ObjectList extends ArrayList { } protected static class ArgumentsMap extends HashMap { } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/ModelAdaptor.java000066400000000000000000000053671231426731300250550ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4; import org.stringtemplate.v4.misc.STNoSuchPropertyException; import java.util.Map; /** * An object that knows how to convert property references to appropriate * actions on a model object. Some models, like JDBC, are interface based (we * aren't supposed to care about implementation classes). Some other models * don't follow StringTemplate's getter method naming convention. So, if we have * an object of type {@code M} with property method {@code M.foo()} (as opposed * to {@code M.getFoo()}), we can register a model adaptor object, {@code adap}, * that converts a lookup for property {@code foo} into a call to * {@code M.foo()}. *

* Given {@code }, we look up {@code foo} via the adaptor if * {@code a instanceof M}.

*/ public interface ModelAdaptor { /** * Lookup property name in {@code o} and return its value. *

* {@code property} is normally a {@code String} but doesn't have to be. * E.g., if {@code o} is {@link Map}, {@code property} could be * any key type. If we need to convert to {@code String}, then it's done by * {@code ST} and passed in here.

*/ public Object getProperty(Interpreter interp, ST self, Object o, Object property, String propertyName) throws STNoSuchPropertyException; } stringtemplate4-4.0.8/src/org/stringtemplate/v4/NoIndentWriter.java000066400000000000000000000035171231426731300254100ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4; import java.io.IOException; import java.io.Writer; /** Just pass through the text. */ public class NoIndentWriter extends AutoIndentWriter { public NoIndentWriter(Writer out) { super(out); } @Override public int write(String str) throws IOException { out.write(str); return str.length(); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/NumberRenderer.java000066400000000000000000000046061231426731300254140ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Formatter; import java.util.Locale; /** Works with {@link Byte}, {@link Short}, {@link Integer}, {@link Long}, and {@link BigInteger} as well as * {@link Float}, {@link Double}, and {@link BigDecimal}. You pass in a format string suitable * for {@link Formatter#format}. *

* For example, {@code %10d} emits a number as a decimal int padding to 10 char. * This can even do {@code long} to {@code Date} conversions using the format string.

*/ public class NumberRenderer implements AttributeRenderer { @Override public String toString(Object o, String formatString, Locale locale) { // o will be instanceof Number if ( formatString==null ) return o.toString(); Formatter f = new Formatter(locale); f.format(formatString, o); return f.toString(); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/ST.java000066400000000000000000000514101231426731300230160ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4; import org.stringtemplate.v4.compiler.CompiledST; import org.stringtemplate.v4.compiler.FormalArgument; import org.stringtemplate.v4.debug.AddAttributeEvent; import org.stringtemplate.v4.debug.ConstructionEvent; import org.stringtemplate.v4.debug.EvalTemplateEvent; import org.stringtemplate.v4.debug.InterpEvent; import org.stringtemplate.v4.gui.STViz; import org.stringtemplate.v4.misc.Aggregate; import org.stringtemplate.v4.misc.ErrorBuffer; import org.stringtemplate.v4.misc.ErrorManager; import org.stringtemplate.v4.misc.MultiMap; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; /** An instance of the StringTemplate. It consists primarily of * a {@linkplain ST#impl reference} to its implementation (shared among all * instances) and a hash table of {@linkplain ST#locals attributes}. Because * of dynamic scoping, we also need a reference to any enclosing instance. For * example, in a deeply nested template for an HTML page body, we could still * reference the title attribute defined in the outermost page template. *

* To use templates, you create one (usually via {@link STGroup}) and then inject * attributes using {@link #add}. To render its attacks, use {@link ST#render()}.

*

* TODO: {@link ST#locals} is not actually a hash table like the documentation * says.

*/ public class ST { public final static String VERSION = "4.0.7-SNAPSHOT"; /** {@code <@r()>}, {@code <@r>...<@end>}, and {@code @t.r() ::= "..."} defined manually by coder */ public static enum RegionType { /** {@code <@r()>} */ IMPLICIT, /** {@code <@r>...<@end>} */ EMBEDDED, /** {@code @t.r() ::= "..."} */ EXPLICIT } /** Events during template hierarchy construction (not evaluation) */ public static class DebugState { /** Record who made us? {@link ConstructionEvent} creates {@link Exception} to grab stack */ public ConstructionEvent newSTEvent; /** Track construction-time add attribute "events"; used for ST user-level debugging */ public MultiMap addAttrEvents = new MultiMap(); } public static final String UNKNOWN_NAME = "anonymous"; public static final Object EMPTY_ATTR = new Object(); /** When there are no formal args for template t and you map t across * some values, t implicitly gets arg "it". E.g., "$it$" */ public static final String IMPLICIT_ARG_NAME = "it"; /** The implementation for this template among all instances of same template . */ public CompiledST impl; /** Safe to simultaneously write via {@link #add}, which is synchronized. * Reading during exec is, however, NOT synchronized. So, not thread safe * to add attributes while it is being evaluated. Initialized to * {@link #EMPTY_ATTR} to distinguish {@code null} from empty. */ protected Object[] locals; /** Created as instance of which group? We need this to initialize interpreter * via render. So, we create st and then it needs to know which * group created it for sake of polymorphism: * *
     *  st = skin1.getInstanceOf("searchbox");
     *  result = st.render(); // knows skin1 created it
	 *  
* * Say we have a group {@code g1} with template {@code t} that imports * templates {@code t} and {@code u} from another group {@code g2}. * {@code g1.getInstanceOf("u")} finds {@code u} in {@code g2} but remembers * that {@code g1} created it. If {@code u} includes {@code t}, it should * create {@code g1.t} not {@code g2.t}. * *
	 *   g1 = {t(), u()}
	 *   |
	 *   v
	 *   g2 = {t()}
	 *  
*/ public STGroup groupThatCreatedThisInstance; /** If {@link STGroup#trackCreationEvents}, track creation and add * attribute events for each object. Create this object on first use. */ public DebugState debugState; /** Just an alias for {@link ArrayList}, but this way I can track whether a * list is something ST created or it's an incoming list. */ public static final class AttributeList extends ArrayList { public AttributeList(int size) { super(size); } public AttributeList() { super(); } } /** Used by group creation routine, not by users */ protected ST() { if ( STGroup.trackCreationEvents ) { if ( debugState==null ) debugState = new ST.DebugState(); debugState.newSTEvent = new ConstructionEvent(); } } /** Used to make templates inline in code for simple things like SQL or log records. * No formal arguments are set and there is no enclosing instance. */ public ST(String template) { this(STGroup.defaultGroup, template); } /** Create ST using non-default delimiters; each one of these will live * in it's own group since you're overriding a default; don't want to * alter {@link STGroup#defaultGroup}. */ public ST(String template, char delimiterStartChar, char delimiterStopChar) { this(new STGroup(delimiterStartChar, delimiterStopChar), template); } public ST(STGroup group, String template) { this(); groupThatCreatedThisInstance = group; impl = groupThatCreatedThisInstance.compile(group.getFileName(), null, null, template, null); impl.hasFormalArgs = false; impl.name = UNKNOWN_NAME; impl.defineImplicitlyDefinedTemplates(groupThatCreatedThisInstance); } /** Clone a prototype template. * Copy all fields minus {@link #debugState}; don't delegate to {@link #ST()}, * which creates {@link ConstructionEvent}. */ public ST(ST proto) { this.impl = proto.impl; if ( proto.locals!=null ) { //this.locals = Arrays.copyOf(proto.locals, proto.locals.length); this.locals = new Object[proto.locals.length]; System.arraycopy(proto.locals, 0, this.locals, 0, proto.locals.length); } else if (impl.formalArguments != null && !impl.formalArguments.isEmpty()) { this.locals = new Object[impl.formalArguments.size()]; } this.groupThatCreatedThisInstance = proto.groupThatCreatedThisInstance; } /** Inject an attribute (name/value pair). If there is already an attribute * with that name, this method turns the attribute into an * {@link AttributeList} with both the previous and the new attribute as * elements. This method will never alter a {@link List} that you inject. * If you send in a {@link List} and then inject a single value element, * {@code add} copies original list and adds the new value. The * attribute name cannot be null or contain '.'. *

* Return {@code this} so we can chain:

*

* {@code t.add("x", 1).add("y", "hi")}

*/ public synchronized ST add(String name, Object value) { if ( name==null ) { throw new NullPointerException("null attribute name"); } if ( name.indexOf('.')>=0 ) { throw new IllegalArgumentException("cannot have '.' in attribute names"); } if ( STGroup.trackCreationEvents ) { if ( debugState==null ) debugState = new ST.DebugState(); debugState.addAttrEvents.map(name, new AddAttributeEvent(name, value)); } FormalArgument arg = null; if ( impl.hasFormalArgs ) { if ( impl.formalArguments!=null ) arg = impl.formalArguments.get(name); if ( arg==null ) { throw new IllegalArgumentException("no such attribute: "+name); } } else { // define and make room in locals (a hack to make new ST("simple template") work.) if ( impl.formalArguments!=null ) { arg = impl.formalArguments.get(name); } if ( arg==null ) { // not defined arg = new FormalArgument(name); impl.addArg(arg); if ( locals==null ) locals = new Object[1]; //else locals = Arrays.copyOf(locals, impl.formalArguments.size()); else { Object[] copy = new Object[impl.formalArguments.size()]; System.arraycopy(locals, 0, copy, 0, Math.min(locals.length, impl.formalArguments.size())); locals = copy; } locals[arg.index] = EMPTY_ATTR; } } Object curvalue = locals[arg.index]; if ( curvalue==EMPTY_ATTR ) { // new attribute locals[arg.index] = value; return this; } // attribute will be multi-valued for sure now // convert current attribute to list if not already // copy-on-write semantics; copy a list injected by user to add new value AttributeList multi = convertToAttributeList(curvalue); locals[arg.index] = multi; // replace with list // now, add incoming value to multi-valued attribute if ( value instanceof List ) { // flatten incoming list into existing list multi.addAll((List)value); } else if ( value!=null && value.getClass().isArray() ) { if (value instanceof Object[]) { multi.addAll(Arrays.asList((Object[])value)); } else { multi.addAll(convertToAttributeList(value)); } } else { multi.add(value); } return this; } /** Split {@code aggrName.{propName1,propName2}} into list * {@code [propName1, propName2]} and the {@code aggrName}. Spaces are * allowed around {@code ','}. */ public synchronized ST addAggr(String aggrSpec, Object... values) { int dot = aggrSpec.indexOf(".{"); if ( values==null || values.length==0 ) { throw new IllegalArgumentException("missing values for aggregate attribute format: "+ aggrSpec); } int finalCurly = aggrSpec.indexOf('}'); if ( dot<0 || finalCurly < 0 ) { throw new IllegalArgumentException("invalid aggregate attribute format: "+ aggrSpec); } String aggrName = aggrSpec.substring(0, dot); String propString = aggrSpec.substring(dot+2, aggrSpec.length()-1); propString = propString.trim(); String[] propNames = propString.split("\\ *,\\ *"); if ( propNames==null || propNames.length==0 ) { throw new IllegalArgumentException("invalid aggregate attribute format: "+ aggrSpec); } if ( values.length != propNames.length ) { throw new IllegalArgumentException( "number of properties and values mismatch for aggregate attribute format: "+ aggrSpec); } int i=0; Aggregate aggr = new Aggregate(); for (String p : propNames) { Object v = values[i++]; aggr.properties.put(p, v); } add(aggrName, aggr); // now add as usual return this; } /** Remove an attribute value entirely (can't remove attribute definitions). */ public void remove(String name) { if ( impl.formalArguments==null ) { if ( impl.hasFormalArgs ) { throw new IllegalArgumentException("no such attribute: "+name); } return; } FormalArgument arg = impl.formalArguments.get(name); if ( arg==null ) { throw new IllegalArgumentException("no such attribute: "+name); } locals[arg.index] = EMPTY_ATTR; // reset value } /** Set {@code locals} attribute value when you only know the name, not the * index. This is ultimately invoked by calling {@code ST#add} from * outside so toss an exception to notify them. */ protected void rawSetAttribute(String name, Object value) { if ( impl.formalArguments==null ) { throw new IllegalArgumentException("no such attribute: "+name); } FormalArgument arg = impl.formalArguments.get(name); if ( arg==null ) { throw new IllegalArgumentException("no such attribute: "+name); } locals[arg.index] = value; } /** Find an attribute in this template only. */ public Object getAttribute(String name) { FormalArgument localArg = null; if ( impl.formalArguments!=null ) localArg = impl.formalArguments.get(name); if ( localArg!=null ) { Object o = locals[localArg.index]; if ( o==ST.EMPTY_ATTR ) o = null; return o; } return null; } public Map getAttributes() { if ( impl.formalArguments==null ) return null; Map attributes = new HashMap(); for (FormalArgument a : impl.formalArguments.values()) { Object o = locals[a.index]; if ( o==ST.EMPTY_ATTR ) o = null; attributes.put(a.name, o); } return attributes; } protected static AttributeList convertToAttributeList(Object curvalue) { AttributeList multi; if ( curvalue == null ) { multi = new AttributeList(); // make list to hold multiple values multi.add(curvalue); // add previous single-valued attribute } else if ( curvalue instanceof AttributeList ) { // already a list made by ST multi = (AttributeList)curvalue; } else if ( curvalue instanceof List) { // existing attribute is non-ST List // must copy to an ST-managed list before adding new attribute // (can't alter incoming attributes) List listAttr = (List)curvalue; multi = new AttributeList(listAttr.size()); multi.addAll(listAttr); } else if ( curvalue instanceof Object[] ) { // copy array to list Object[] a = (Object[])curvalue; multi = new AttributeList(a.length); multi.addAll(Arrays.asList(a)); // asList doesn't copy as far as I can tell } else if ( curvalue.getClass().isArray() ) { // copy primitive array to list int length = Array.getLength(curvalue); multi = new AttributeList(length); for (int i = 0; i < length; i++) { multi.add(Array.get(curvalue, i)); } } else { // curvalue nonlist and we want to add an attribute // must convert curvalue existing to list multi = new AttributeList(); // make list to hold multiple values multi.add(curvalue); // add previous single-valued attribute } return multi; } public String getName() { return impl.name; } public boolean isAnonSubtemplate() { return impl.isAnonSubtemplate; } public int write(STWriter out) throws IOException { Interpreter interp = new Interpreter(groupThatCreatedThisInstance, impl.nativeGroup.errMgr, false); InstanceScope scope = new InstanceScope(null, this); return interp.exec(out, scope); } public int write(STWriter out, Locale locale) { Interpreter interp = new Interpreter(groupThatCreatedThisInstance, locale, impl.nativeGroup.errMgr, false); InstanceScope scope = new InstanceScope(null, this); return interp.exec(out, scope); } public int write(STWriter out, STErrorListener listener) { Interpreter interp = new Interpreter(groupThatCreatedThisInstance, new ErrorManager(listener), false); InstanceScope scope = new InstanceScope(null, this); return interp.exec(out, scope); } public int write(STWriter out, Locale locale, STErrorListener listener) { Interpreter interp = new Interpreter(groupThatCreatedThisInstance, locale, new ErrorManager(listener), false); InstanceScope scope = new InstanceScope(null, this); return interp.exec(out, scope); } public int write(File outputFile, STErrorListener listener) throws IOException { return write(outputFile, listener, "UTF-8", Locale.getDefault(), STWriter.NO_WRAP); } public int write(File outputFile, STErrorListener listener, String encoding) throws IOException { return write(outputFile, listener, encoding, Locale.getDefault(), STWriter.NO_WRAP); } public int write(File outputFile, STErrorListener listener, String encoding, int lineWidth) throws IOException { return write(outputFile, listener, encoding, Locale.getDefault(), lineWidth); } public int write(File outputFile, STErrorListener listener, String encoding, Locale locale, int lineWidth) throws IOException { Writer bw = null; try { FileOutputStream fos = new FileOutputStream(outputFile); OutputStreamWriter osw = new OutputStreamWriter(fos, encoding); bw = new BufferedWriter(osw); AutoIndentWriter w = new AutoIndentWriter(bw); w.setLineWidth(lineWidth); int n = write(w, locale, listener); bw.close(); bw = null; return n; } finally { if (bw != null) bw.close(); } } public String render() { return render(Locale.getDefault()); } public String render(int lineWidth) { return render(Locale.getDefault(), lineWidth); } public String render(Locale locale) { return render(locale, STWriter.NO_WRAP); } public String render(Locale locale, int lineWidth) { StringWriter out = new StringWriter(); STWriter wr = new AutoIndentWriter(out); wr.setLineWidth(lineWidth); write(wr, locale); return out.toString(); } // LAUNCH A WINDOW TO INSPECT TEMPLATE HIERARCHY public STViz inspect() { return inspect(Locale.getDefault()); } public STViz inspect(int lineWidth) { return inspect(impl.nativeGroup.errMgr, Locale.getDefault(), lineWidth); } public STViz inspect(Locale locale) { return inspect(impl.nativeGroup.errMgr, locale, STWriter.NO_WRAP); } public STViz inspect(ErrorManager errMgr, Locale locale, int lineWidth) { ErrorBuffer errors = new ErrorBuffer(); impl.nativeGroup.setListener(errors); StringWriter out = new StringWriter(); STWriter wr = new AutoIndentWriter(out); wr.setLineWidth(lineWidth); Interpreter interp = new Interpreter(groupThatCreatedThisInstance, locale, true); InstanceScope scope = new InstanceScope(null, this); interp.exec(wr, scope); // render and track events List events = interp.getEvents(); EvalTemplateEvent overallTemplateEval = (EvalTemplateEvent)events.get(events.size()-1); STViz viz = new STViz(errMgr, overallTemplateEval, out.toString(), interp, interp.getExecutionTrace(), errors.errors); viz.open(); return viz; } // TESTING SUPPORT public List getEvents() { return getEvents(Locale.getDefault()); } public List getEvents(int lineWidth) { return getEvents(Locale.getDefault(), lineWidth); } public List getEvents(Locale locale) { return getEvents(locale, STWriter.NO_WRAP); } public List getEvents(Locale locale, int lineWidth) { StringWriter out = new StringWriter(); STWriter wr = new AutoIndentWriter(out); wr.setLineWidth(lineWidth); Interpreter interp = new Interpreter(groupThatCreatedThisInstance, locale, true); InstanceScope scope = new InstanceScope(null, this); interp.exec(wr, scope); // render and track events return interp.getEvents(); } @Override public String toString() { if ( impl==null ) return "bad-template()"; String name = impl.name+"()"; if (this.impl.isRegion) { name = "@" + STGroup.getUnMangledTemplateName(name); } return name; } /** *
	 * ST.format("name, phone | <name>:<phone>", n, p);
	 * ST.format("<%1>:<%2>", n, p);
	 * ST.format("<name>:<phone>", "name", x, "phone", y);
	 * 
*/ public static String format(String template, Object... attributes) { return format(STWriter.NO_WRAP, template, attributes); } public static String format(int lineWidth, String template, Object... attributes) { template = template.replaceAll("%([0-9]+)", "arg$1"); ST st = new ST(template); int i = 1; for (Object a : attributes) { st.add("arg"+i, a); i++; } return st.render(lineWidth); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/STErrorListener.java000066400000000000000000000034571231426731300255460ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4; import org.stringtemplate.v4.misc.STMessage; /** How to handle messages. */ public interface STErrorListener { public void compileTimeError(STMessage msg); public void runTimeError(STMessage msg); public void IOError(STMessage msg); public void internalError(STMessage msg); } stringtemplate4-4.0.8/src/org/stringtemplate/v4/STGroup.java000066400000000000000000000730521231426731300240410ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4; import org.antlr.runtime.*; import org.stringtemplate.v4.compiler.*; import org.stringtemplate.v4.compiler.Compiler; import org.stringtemplate.v4.gui.STViz; import org.stringtemplate.v4.misc.*; import java.io.*; import java.net.*; import java.util.*; /** A directory or directory tree of {@code .st} template files and/or group files. * Individual template files contain formal template definitions. In a sense, * it's like a single group file broken into multiple files, one for each template. * ST v3 had just the pure template inside, not the template name and header. * Name inside must match filename (minus suffix). */ public class STGroup { public static final String GROUP_FILE_EXTENSION; public static final String TEMPLATE_FILE_EXTENSION; static { GROUP_FILE_EXTENSION = ".stg"; TEMPLATE_FILE_EXTENSION = ".st"; } /** When we use key as a value in a dictionary, this is how we signify. */ public static final String DICT_KEY = "key"; public static final String DEFAULT_KEY = "default"; /** The encoding to use for loading files. Defaults to UTF-8. */ public String encoding = "UTF-8"; /** Every group can import templates/dictionaries from other groups. * The list must be synchronized (see {@link STGroup#importTemplates}). */ protected final List imports = Collections.synchronizedList(new ArrayList()); protected final List importsToClearOnUnload = Collections.synchronizedList(new ArrayList()); public char delimiterStartChar = '<'; // Use by default public char delimiterStopChar = '>'; /** Maps template name to {@link CompiledST} object. This map is synchronized. */ protected Map templates = Collections.synchronizedMap(new LinkedHashMap()); /** Maps dictionary names to {@link Map} objects representing the dictionaries * defined by the user like {@code typeInitMap ::= ["int":"0"]}. */ protected Map> dictionaries = Collections.synchronizedMap(new HashMap>()); /** A dictionary that allows people to register a renderer for * a particular kind of object for any template evaluated relative to this * group. For example, a date should be formatted differently depending * on the locale. You can set {@code Date.class} to an object whose * {@code toString(Object)} method properly formats a {@link Date} attribute * according to locale. Or you can have a different renderer object * for each locale. *

* Order of addition is recorded and matters. If more than one * renderer works for an object, the first registered has priority.

*

* Renderer associated with type {@code t} works for object {@code o} if

*
	 *  t.isAssignableFrom(o.getClass()) // would assignment t = o work?
	 *  
* So it works if {@code o} is subclass or implements {@code t}. *

* This structure is synchronized.

*/ protected Map, AttributeRenderer> renderers; /** A dictionary that allows people to register a model adaptor for * a particular kind of object (subclass or implementation). Applies * for any template evaluated relative to this group. *

* ST initializes with model adaptors that know how to pull * properties out of {@link Object}s, {@link Map}s, and {@link ST}s.

*

* The last one you register gets priority; do least to most specific.

*/ protected final Map, ModelAdaptor> adaptors; { TypeRegistry registry = new TypeRegistry(); registry.put(Object.class, new ObjectModelAdaptor()); registry.put(ST.class, new STModelAdaptor()); registry.put(Map.class, new MapModelAdaptor()); registry.put(Aggregate.class, new AggregateModelAdaptor()); adaptors = Collections.synchronizedMap(registry); } /** Used to indicate that the template doesn't exist. * Prevents duplicate group file loads and unnecessary file checks. */ protected static final CompiledST NOT_FOUND_ST = new CompiledST(); public static final ErrorManager DEFAULT_ERR_MGR = new ErrorManager(); /** Watch loading of groups and templates. */ public static boolean verbose = false; /** * For debugging with {@link STViz}. Records where in code an {@link ST} was * created and where code added attributes. */ public static boolean trackCreationEvents = false; /** v3 compatibility; used to iterate across {@link Map#values()} instead of * v4's default {@link Map#keySet()}. * But to convert ANTLR templates, it's too hard to find without * static typing in templates. */ public boolean iterateAcrossValues = false; public static STGroup defaultGroup = new STGroup(); /** The {@link ErrorManager} for entire group; all compilations and executions. * This gets copied to parsers, walkers, and interpreters. */ public ErrorManager errMgr = STGroup.DEFAULT_ERR_MGR; public STGroup() { } public STGroup(char delimiterStartChar, char delimiterStopChar) { this.delimiterStartChar = delimiterStartChar; this.delimiterStopChar = delimiterStopChar; } /** The primary means of getting an instance of a template from this * group. Names must be absolute, fully-qualified names like {@code /a/b}. */ public ST getInstanceOf(String name) { if ( name==null ) return null; if ( verbose ) System.out.println(getName()+".getInstanceOf("+name+")"); if ( name.charAt(0)!='/' ) name = "/"+name; CompiledST c = lookupTemplate(name); if ( c!=null ) { return createStringTemplate(c); } return null; } protected ST getEmbeddedInstanceOf(Interpreter interp, InstanceScope scope, String name) { String fullyQualifiedName = name; if ( name.charAt(0)!='/' ) { fullyQualifiedName = scope.st.impl.prefix + name; } if ( verbose ) System.out.println("getEmbeddedInstanceOf(" + fullyQualifiedName +")"); ST st = getInstanceOf(fullyQualifiedName); if ( st==null ) { errMgr.runTimeError(interp, scope, ErrorType.NO_SUCH_TEMPLATE, fullyQualifiedName); return createStringTemplateInternally(new CompiledST()); } // this is only called internally. wack any debug ST create events if ( trackCreationEvents ) { st.debugState.newSTEvent = null; // toss it out } return st; } /** Create singleton template for use with dictionary values. */ public ST createSingleton(Token templateToken) { String template; if ( templateToken.getType()==GroupParser.BIGSTRING ) { template = Misc.strip(templateToken.getText(),2); } else { template = Misc.strip(templateToken.getText(),1); } CompiledST impl = compile(getFileName(), null, null, template, templateToken); ST st = createStringTemplateInternally(impl); st.groupThatCreatedThisInstance = this; st.impl.hasFormalArgs = false; st.impl.name = ST.UNKNOWN_NAME; st.impl.defineImplicitlyDefinedTemplates(this); return st; } /** Is this template defined in this group or from this group below? * Names must be absolute, fully-qualified names like {@code /a/b}. */ public boolean isDefined(String name) { return lookupTemplate(name)!=null; } /** Look up a fully-qualified name. */ public CompiledST lookupTemplate(String name) { if ( name.charAt(0)!='/' ) name = "/"+name; if ( verbose ) System.out.println(getName()+".lookupTemplate("+name+")"); CompiledST code = rawGetTemplate(name); if ( code==NOT_FOUND_ST ) { if ( verbose ) System.out.println(name+" previously seen as not found"); return null; } // try to load from disk and look up again if ( code==null ) code = load(name); if ( code==null ) code = lookupImportedTemplate(name); if ( code==null ) { if ( verbose ) System.out.println(name+" recorded not found"); templates.put(name, NOT_FOUND_ST); } if ( verbose ) if ( code!=null ) System.out.println(getName()+".lookupTemplate("+name+") found"); return code; } /** * Unload all templates, dictionaries and import relationships, but leave * renderers and adaptors. This essentially forces the next call to * {@link #getInstanceOf} to reload templates. Call {@code unload()} on each * group in the {@link #imports} list, and remove all elements in * {@link #importsToClearOnUnload} from {@link #imports}. */ public synchronized void unload() { templates.clear(); dictionaries.clear(); for (STGroup imp : imports) { imp.unload(); } for (STGroup imp : importsToClearOnUnload) { imports.remove(imp); } importsToClearOnUnload.clear(); } /** Load st from disk if directory or load whole group file if .stg file (then * return just one template). {@code name} is fully-qualified. */ protected CompiledST load(String name) { return null; } /** Force a load if it makes sense for the group. */ public void load() { } protected CompiledST lookupImportedTemplate(String name) { if ( imports.size()==0 ) return null; for (STGroup g : imports) { if ( verbose ) System.out.println("checking "+g.getName()+" for imported "+name); CompiledST code = g.lookupTemplate(name); if ( code!=null ) { if ( verbose ) System.out.println(g.getName()+".lookupImportedTemplate("+name+") found"); return code; } } if ( verbose ) System.out.println(name+" not found in "+getName()+" imports"); return null; } public CompiledST rawGetTemplate(String name) { return templates.get(name); } public Map rawGetDictionary(String name) { return dictionaries.get(name); } public boolean isDictionary(String name) { return dictionaries.get(name)!=null; } /** for testing */ public CompiledST defineTemplate(String templateName, String template) { if ( templateName.charAt(0)!='/' ) templateName = "/"+templateName; try { CompiledST impl = defineTemplate(templateName, new CommonToken(GroupParser.ID, templateName), null, template, null); return impl; } catch (STException se) { // we have reported the error; the exception just blasts us // out of parsing this template } return null; } /** for testing */ public CompiledST defineTemplate(String name, String argsS, String template) { if ( name.charAt(0)!='/' ) name = "/"+name; String[] args = argsS.split(","); List a = new ArrayList(); for (String arg : args) { a.add(new FormalArgument(arg)); } return defineTemplate(name, new CommonToken(GroupParser.ID, name), a, template, null); } public CompiledST defineTemplate(String fullyQualifiedTemplateName, Token nameT, List args, String template, Token templateToken) { if ( verbose ) System.out.println("defineTemplate("+fullyQualifiedTemplateName+")"); if ( fullyQualifiedTemplateName==null || fullyQualifiedTemplateName.length()==0 ) { throw new IllegalArgumentException("empty template name"); } if ( fullyQualifiedTemplateName.indexOf('.')>=0 ) { throw new IllegalArgumentException("cannot have '.' in template names"); } template = Misc.trimOneStartingNewline(template); template = Misc.trimOneTrailingNewline(template); // compile, passing in templateName as enclosing name for any embedded regions CompiledST code = compile(getFileName(), fullyQualifiedTemplateName, args, template, templateToken); code.name = fullyQualifiedTemplateName; rawDefineTemplate(fullyQualifiedTemplateName, code, nameT); code.defineArgDefaultValueTemplates(this); code.defineImplicitlyDefinedTemplates(this); // define any anonymous subtemplates return code; } /** Make name and alias for target. Replace any previous definition of name. */ public CompiledST defineTemplateAlias(Token aliasT, Token targetT) { String alias = aliasT.getText(); String target = targetT.getText(); CompiledST targetCode = rawGetTemplate("/"+target); if ( targetCode==null ){ errMgr.compileTimeError(ErrorType.ALIAS_TARGET_UNDEFINED, null, aliasT, alias, target); return null; } rawDefineTemplate("/" + alias, targetCode, aliasT); return targetCode; } public CompiledST defineRegion(String enclosingTemplateName, Token regionT, String template, Token templateToken) { String name = regionT.getText(); template = Misc.trimOneStartingNewline(template); template = Misc.trimOneTrailingNewline(template); CompiledST code = compile(getFileName(), enclosingTemplateName, null, template, templateToken); String mangled = getMangledRegionName(enclosingTemplateName, name); if ( lookupTemplate(mangled)==null ) { errMgr.compileTimeError(ErrorType.NO_SUCH_REGION, templateToken, regionT, enclosingTemplateName, name); return new CompiledST(); } code.name = mangled; code.isRegion = true; code.regionDefType = ST.RegionType.EXPLICIT; code.templateDefStartToken = regionT; rawDefineTemplate(mangled, code, regionT); code.defineArgDefaultValueTemplates(this); code.defineImplicitlyDefinedTemplates(this); return code; } public void defineTemplateOrRegion( String fullyQualifiedTemplateName, String regionSurroundingTemplateName, Token templateToken, String template, Token nameToken, List args) { try { if ( regionSurroundingTemplateName!=null ) { defineRegion(regionSurroundingTemplateName, nameToken, template, templateToken); } else { defineTemplate(fullyQualifiedTemplateName, nameToken, args, template, templateToken); } } catch (STException e) { // after getting syntax error in a template, we emit msg // and throw exception to blast all the way out to here. } } public void rawDefineTemplate(String name, CompiledST code, Token defT) { CompiledST prev = rawGetTemplate(name); if ( prev!=null ) { if ( !prev.isRegion ) { errMgr.compileTimeError(ErrorType.TEMPLATE_REDEFINITION, null, defT); return; } if ( prev.isRegion ) { if ( code.regionDefType!=ST.RegionType.IMPLICIT && prev.regionDefType==ST.RegionType.EMBEDDED ) { errMgr.compileTimeError(ErrorType.EMBEDDED_REGION_REDEFINITION, null, defT, getUnMangledTemplateName(name)); return; } else if ( code.regionDefType==ST.RegionType.IMPLICIT || prev.regionDefType==ST.RegionType.EXPLICIT ) { errMgr.compileTimeError(ErrorType.REGION_REDEFINITION, null, defT, getUnMangledTemplateName(name)); return; } } } code.nativeGroup = this; code.templateDefStartToken = defT; templates.put(name, code); } public void undefineTemplate(String name) { templates.remove(name); } /** Compile a template. */ public CompiledST compile(String srcName, String name, List args, String template, Token templateToken) // for error location { //System.out.println("STGroup.compile: "+enclosingTemplateName); Compiler c = new Compiler(this); return c.compile(srcName, name, args, template, templateToken); } /** The {@code "foo"} of {@code t() ::= "<@foo()>"} is mangled to * {@code "/region__/t__foo"} */ public static String getMangledRegionName(String enclosingTemplateName, String name) { if ( enclosingTemplateName.charAt(0)!='/' ) { enclosingTemplateName = '/'+enclosingTemplateName; } return "/region__"+enclosingTemplateName+"__"+name; } /** Return {@code "t.foo"} from {@code "/region__/t__foo"} */ public static String getUnMangledTemplateName(String mangledName) { String t = mangledName.substring("/region__".length(), mangledName.lastIndexOf("__")); String r = mangledName.substring(mangledName.lastIndexOf("__")+2, mangledName.length()); return t+'.'+r; } /** Define a map for this group. *

* Not thread safe...do not keep adding these while you reference them.

*/ public void defineDictionary(String name, Map mapping) { dictionaries.put(name, mapping); } /** * Make this group import templates/dictionaries from {@code g}. *

* On unload imported templates are unloaded but stay in the {@link #imports} list.

*/ public void importTemplates(STGroup g) { importTemplates(g, false); } /** Import template files, directories, and group files. * Priority is given to templates defined in the current group; * this, in effect, provides inheritance. Polymorphism is in effect so * that if an inherited template references template {@code t()} then we * search for {@code t()} in the subgroup first. *

* Templates are loaded on-demand from import dirs. Imported groups are * loaded on-demand when searching for a template.

*

* The listener of this group is passed to the import group so errors * found while loading imported element are sent to listener of this group.

*

* On unload imported templates are unloaded and removed from the imports * list.

*

* This method is called when processing import statements specified in * group files. Use {@link #importTemplates(STGroup)} to import templates * 'programmatically'.

*/ public void importTemplates(Token fileNameToken) { if ( verbose ) System.out.println("importTemplates("+fileNameToken.getText()+")"); String fileName = fileNameToken.getText(); // do nothing upon syntax error if ( fileName==null || fileName.equals("") ) return; fileName = Misc.strip(fileName, 1); //System.out.println("import "+fileName); boolean isGroupFile = fileName.endsWith(GROUP_FILE_EXTENSION); boolean isTemplateFile = fileName.endsWith(TEMPLATE_FILE_EXTENSION); boolean isGroupDir = !(isGroupFile || isTemplateFile); STGroup g = null; // search path is: working dir, g.stg's dir, CLASSPATH URL thisRoot = getRootDirURL(); URL fileUnderRoot; // System.out.println("thisRoot="+thisRoot); try { fileUnderRoot = new URL(thisRoot+"/"+fileName); } catch (MalformedURLException mfe) { errMgr.internalError(null, "can't build URL for "+thisRoot+"/"+fileName, mfe); return; } if ( isTemplateFile ) { g = new STGroup(delimiterStartChar, delimiterStopChar); g.setListener(this.getListener()); URL fileURL; if ( Misc.urlExists(fileUnderRoot) ) fileURL = fileUnderRoot; else fileURL = getURL(fileName); // try CLASSPATH if ( fileURL!=null ) { try { InputStream s = fileURL.openStream(); ANTLRInputStream templateStream = new ANTLRInputStream(s); templateStream.name = fileName; CompiledST code = g.loadTemplateFile("/", fileName, templateStream); if ( code==null ) g = null; } catch (IOException ioe) { errMgr.internalError(null, "can't read from "+fileURL, ioe); g = null; } } else { g = null; } } else if ( isGroupFile ) { //System.out.println("look for fileUnderRoot: "+fileUnderRoot); if ( Misc.urlExists(fileUnderRoot) ) { g = new STGroupFile(fileUnderRoot, encoding, delimiterStartChar, delimiterStopChar); g.setListener(this.getListener()); } else { g = new STGroupFile(fileName, delimiterStartChar, delimiterStopChar); g.setListener(this.getListener()); } } else if ( isGroupDir ) { // System.out.println("try dir "+fileUnderRoot); if ( Misc.urlExists(fileUnderRoot) ) { g = new STGroupDir(fileUnderRoot, encoding, delimiterStartChar, delimiterStopChar); g.setListener(this.getListener()); } else { // try in CLASSPATH // System.out.println("try dir in CLASSPATH "+fileName); g = new STGroupDir(fileName, delimiterStartChar, delimiterStopChar); g.setListener(this.getListener()); } } if ( g==null ) { errMgr.compileTimeError(ErrorType.CANT_IMPORT, null, fileNameToken, fileName); } else { importTemplates(g, true); } } protected void importTemplates(STGroup g, boolean clearOnUnload) { if ( g==null ) return; imports.add(g); if (clearOnUnload) { importsToClearOnUnload.add(g); } } public List getImportedGroups() { return imports; } /** Load a group file with full path {@code fileName}; it's relative to root by {@code prefix}. */ public void loadGroupFile(String prefix, String fileName) { if ( verbose ) System.out.println(this.getClass().getSimpleName()+ ".loadGroupFile(group-file-prefix="+prefix+", fileName="+fileName+")"); GroupParser parser; try { URL f = new URL(fileName); ANTLRInputStream fs = new ANTLRInputStream(f.openStream(), encoding); GroupLexer lexer = new GroupLexer(fs); fs.name = fileName; CommonTokenStream tokens = new CommonTokenStream(lexer); parser = new GroupParser(tokens); parser.group(this, prefix); } catch (Exception e) { errMgr.IOError(null, ErrorType.CANT_LOAD_GROUP_FILE, e, fileName); } } /** Load template file into this group using absolute {@code fileName}. */ public CompiledST loadAbsoluteTemplateFile(String fileName) { ANTLRFileStream fs; try { fs = new ANTLRFileStream(fileName, encoding); fs.name = fileName; } catch (IOException ioe) { // doesn't exist //errMgr.IOError(null, ErrorType.NO_SUCH_TEMPLATE, ioe, fileName); return null; } return loadTemplateFile("", fileName, fs); } /** Load template stream into this group. {@code unqualifiedFileName} is * {@code "a.st"}. The {@code prefix} is path from group root to * {@code unqualifiedFileName} like {@code "/subdir"} if file is in * {@code /subdir/a.st}. */ public CompiledST loadTemplateFile(String prefix, String unqualifiedFileName, CharStream templateStream) { GroupLexer lexer = new GroupLexer(templateStream); CommonTokenStream tokens = new CommonTokenStream(lexer); GroupParser parser = new GroupParser(tokens); parser.group = this; lexer.group = this; try { parser.templateDef(prefix); } catch (RecognitionException re) { errMgr.groupSyntaxError(ErrorType.SYNTAX_ERROR, unqualifiedFileName, re, re.getMessage()); } String templateName = Misc.getFileNameNoSuffix(unqualifiedFileName); if ( prefix!=null && prefix.length()>0 ) templateName = prefix+templateName; CompiledST impl = rawGetTemplate(templateName); impl.prefix = prefix; return impl; } /** * Add an adaptor for a kind of object so ST knows how to pull properties * from them. Add adaptors in increasing order of specificity. ST adds * {@link Object}, {@link Map}, {@link ST}, and {@link Aggregate} model * adaptors for you first. Adaptors you add have priority over default * adaptors. *

* If an adaptor for type {@code T} already exists, it is replaced by the * {@code adaptor} argument.

*

* This must invalidate cache entries, so set your adaptors up before * calling {@link ST#render} for efficiency.

*/ public void registerModelAdaptor(Class attributeType, ModelAdaptor adaptor) { if ( attributeType.isPrimitive() ) { throw new IllegalArgumentException("can't register ModelAdaptor for primitive type "+ attributeType.getSimpleName()); } adaptors.put(attributeType, adaptor); } public ModelAdaptor getModelAdaptor(Class attributeType) { return adaptors.get(attributeType); } /** Register a renderer for all objects of a particular "kind" for all * templates evaluated relative to this group. Use {@code r} to render if * object in question is an instance of {@code attributeType}. Recursively * set renderer into all import groups. */ public void registerRenderer(Class attributeType, AttributeRenderer r) { registerRenderer(attributeType, r, true); } public void registerRenderer(Class attributeType, AttributeRenderer r, boolean recursive) { if ( attributeType.isPrimitive() ) { throw new IllegalArgumentException("can't register renderer for primitive type "+ attributeType.getSimpleName()); } if ( renderers == null ) { renderers = Collections.synchronizedMap(new TypeRegistry()); } renderers.put(attributeType, r); if ( recursive ) { load(); // make sure imports exist (recursively) for (STGroup g : imports) { g.registerRenderer(attributeType, r, true); } } } /** Get renderer for class {@code T} associated with this group. *

* For non-imported groups and object-to-render of class {@code T}, use renderer * (if any) registered for {@code T}. For imports, any renderer * set on import group is ignored even when using an imported template. * You should set the renderer on the main group * you use (or all to be sure). I look at import groups as * "helpers" that should give me templates and nothing else. If you * have multiple renderers for {@code String}, say, then just make uber combined * renderer with more specific format names.

*/ public AttributeRenderer getAttributeRenderer(Class attributeType) { if ( renderers==null ) { return null; } return renderers.get(attributeType); } public ST createStringTemplate(CompiledST impl) { ST st = new ST(); st.impl = impl; st.groupThatCreatedThisInstance = this; if ( impl.formalArguments!=null ) { st.locals = new Object[impl.formalArguments.size()]; Arrays.fill(st.locals, ST.EMPTY_ATTR); } return st; } /** Differentiate so we can avoid having creation events for regions, * map operations, and other implicit "new ST" events during rendering. */ public ST createStringTemplateInternally(CompiledST impl) { ST st = createStringTemplate(impl); if ( trackCreationEvents && st.debugState!=null ) { st.debugState.newSTEvent = null; // toss it out } return st; } public ST createStringTemplateInternally(ST proto) { return new ST(proto); // no need to wack debugState; not set in ST(proto). } public String getName() { return ";"; } public String getFileName() { return null; } /** Return root dir if this is group dir; return dir containing group file * if this is group file. This is derived from original incoming * dir or filename. If it was absolute, this should come back * as full absolute path. If only a URL is available, return URL of * one dir up. */ public URL getRootDirURL() { return null; } public URL getURL(String fileName) { URL url; ClassLoader cl = Thread.currentThread().getContextClassLoader(); url = cl.getResource(fileName); if ( url==null ) { cl = this.getClass().getClassLoader(); url = cl.getResource(fileName); } return url; } @Override public String toString() { return getName(); } public String show() { StringBuilder buf = new StringBuilder(); if ( imports.size()!=0 ) buf.append(" : "+imports); for (String name : templates.keySet()) { CompiledST c = rawGetTemplate(name); if ( c.isAnonSubtemplate || c==NOT_FOUND_ST ) continue; int slash = name.lastIndexOf('/'); name = name.substring(slash+1, name.length()); buf.append(name); buf.append('('); if ( c.formalArguments!=null ) buf.append( Misc.join(c.formalArguments.values().iterator(), ",") ); buf.append(')'); buf.append(" ::= <<"+Misc.newline); buf.append(c.template+ Misc.newline); buf.append(">>"+Misc.newline); } return buf.toString(); } public STErrorListener getListener() { return errMgr.listener; } public void setListener(STErrorListener listener) { errMgr = new ErrorManager(listener); } public Set getTemplateNames() { load(); HashSet result = new HashSet(); for (Map.Entry e: templates.entrySet()) { if (e.getValue() != NOT_FOUND_ST) { result.add(e.getKey()); } } return result; } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/STGroupDir.java000066400000000000000000000150521231426731300244740ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4; import org.antlr.runtime.*; import org.stringtemplate.v4.compiler.*; import org.stringtemplate.v4.misc.*; import java.io.*; import java.net.*; // TODO: caching? /** A directory or directory tree full of templates and/or group files. * We load files on-demand. Dir search path: current working dir then * CLASSPATH (as a resource). Do not look for templates outside of this dir * subtree (except via imports). */ public class STGroupDir extends STGroup { public String groupDirName; public URL root; public STGroupDir(String dirName) { this(dirName, '<', '>'); } public STGroupDir(String dirName, char delimiterStartChar, char delimiterStopChar) { super(delimiterStartChar, delimiterStopChar); this.groupDirName = dirName; File dir = new File(dirName); if ( dir.exists() && dir.isDirectory() ) { // we found the directory and it'll be file based try { root = dir.toURI().toURL(); } catch (MalformedURLException e) { throw new STException("can't load dir "+dirName, e); } if ( verbose ) System.out.println("STGroupDir("+dirName+") found at "+root); } else { ClassLoader cl = Thread.currentThread().getContextClassLoader(); root = cl.getResource(dirName); if ( root==null ) { cl = this.getClass().getClassLoader(); root = cl.getResource(dirName); } if ( verbose ) System.out.println("STGroupDir("+dirName+") found via CLASSPATH at "+root); if ( root==null ) { throw new IllegalArgumentException("No such directory: "+ dirName); } } } public STGroupDir(String dirName, String encoding) { this(dirName, encoding, '<', '>'); } public STGroupDir(String dirName, String encoding, char delimiterStartChar, char delimiterStopChar) { this(dirName, delimiterStartChar, delimiterStopChar); this.encoding = encoding; } public STGroupDir(URL root, String encoding, char delimiterStartChar, char delimiterStopChar) { super(delimiterStartChar, delimiterStopChar); this.groupDirName = new File(root.getFile()).getName(); this.root = root; this.encoding = encoding; } @Override public void importTemplates(Token fileNameToken) { String msg = "import illegal in group files embedded in STGroupDirs; "+ "import "+fileNameToken.getText()+" in STGroupDir "+this.getName(); throw new UnsupportedOperationException(msg); } /** Load a template from directory or group file. Group file is given * precedence over directory with same name. {@code name} is always fully-qualified. */ @Override protected CompiledST load(String name) { if ( verbose ) System.out.println("STGroupDir.load("+name+")"); String parent = Misc.getParent(name); // must have parent; it's fully-qualified String prefix = Misc.getPrefix(name); // if (parent.isEmpty()) { // // no need to check for a group file as name has no parent // return loadTemplateFile("/", name+TEMPLATE_FILE_EXTENSION); // load t.st file // } URL groupFileURL = null; try { // see if parent of template name is a group file groupFileURL = new URL(root+parent+GROUP_FILE_EXTENSION); } catch (MalformedURLException e) { errMgr.internalError(null, "bad URL: "+root+parent+GROUP_FILE_EXTENSION, e); return null; } InputStream is = null; try { is = groupFileURL.openStream(); } catch (IOException ioe) { // must not be in a group file String unqualifiedName = Misc.getFileName(name); return loadTemplateFile(prefix, unqualifiedName+TEMPLATE_FILE_EXTENSION); // load t.st file } finally { // clean up try { if (is!=null ) is.close(); } catch (IOException ioe) { errMgr.internalError(null, "can't close template file stream "+name, ioe); } } loadGroupFile(prefix, root+parent+GROUP_FILE_EXTENSION); return rawGetTemplate(name); } /** Load .st as relative file name relative to root by {@code prefix}. */ public CompiledST loadTemplateFile(String prefix, String unqualifiedFileName) { if ( verbose ) System.out.println("loadTemplateFile("+unqualifiedFileName+") in groupdir "+ "from "+root+" prefix="+prefix); URL f = null; try { f = new URL(root+prefix+unqualifiedFileName); } catch (MalformedURLException me) { errMgr.runTimeError(null, null, ErrorType.INVALID_TEMPLATE_NAME, me, root + unqualifiedFileName); return null; } ANTLRInputStream fs; try { fs = new ANTLRInputStream(f.openStream(), encoding); fs.name = unqualifiedFileName; } catch (IOException ioe) { if ( verbose ) System.out.println(root+"/"+unqualifiedFileName+" doesn't exist"); //errMgr.IOError(null, ErrorType.NO_SUCH_TEMPLATE, ioe, unqualifiedFileName); return null; } return loadTemplateFile(prefix, unqualifiedFileName, fs); } @Override public String getName() { return groupDirName; } @Override public String getFileName() { return root.getFile(); } @Override public URL getRootDirURL() { return root; } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/STGroupFile.java000066400000000000000000000131741231426731300246400ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4; import org.stringtemplate.v4.compiler.*; import org.stringtemplate.v4.misc.*; import java.io.File; import java.net.*; /** The internal representation of a single group file (which must end in * ".stg"). If we fail to find a group file, look for it via the * CLASSPATH as a resource. Templates are only looked up in this file * or an import. */ public class STGroupFile extends STGroup { public String fileName; public URL url; protected boolean alreadyLoaded = false; /** Load a file relative to current directory or from root or via CLASSPATH. */ public STGroupFile(String fileName) { this(fileName, '<', '>'); } public STGroupFile(String fileName, char delimiterStartChar, char delimiterStopChar) { super(delimiterStartChar, delimiterStopChar); if ( !fileName.endsWith(GROUP_FILE_EXTENSION) ) { throw new IllegalArgumentException("Group file names must end in .stg: "+fileName); } //try { File f = new File(fileName); if ( f.exists() ) { try { url = f.toURI().toURL(); } catch (MalformedURLException e) { throw new STException("can't load group file "+fileName, e); } if ( verbose ) System.out.println("STGroupFile(" + fileName + ") == file "+f.getAbsolutePath()); } else { // try in classpath url = getURL(fileName); if ( url==null ) { throw new IllegalArgumentException("No such group file: "+ fileName); } if ( verbose ) System.out.println("STGroupFile(" + fileName + ") == url "+url); } this.fileName = fileName; } public STGroupFile(String fullyQualifiedFileName, String encoding) { this(fullyQualifiedFileName, encoding, '<', '>'); } public STGroupFile(String fullyQualifiedFileName, String encoding, char delimiterStartChar, char delimiterStopChar) { this(fullyQualifiedFileName, delimiterStartChar, delimiterStopChar); this.encoding = encoding; } public STGroupFile(URL url, String encoding, char delimiterStartChar, char delimiterStopChar) { super(delimiterStartChar, delimiterStopChar); this.url = url; this.encoding = encoding; try { // When group is loaded from jar file the URL starts with // "jar:file:" which cannot be converted into a URI/File. // Remove the "jar:" prefix to enable the conversion. String urlString = url.toString(); if (urlString.startsWith("jar:file:")) { urlString = urlString.substring(4); } this.fileName = new File(new URI(urlString)).getAbsolutePath(); } catch (Exception e) { // ignore. If this happens (bad url etc.) filename is null } } @Override public boolean isDictionary(String name) { if ( !alreadyLoaded ) load(); return super.isDictionary(name); } @Override public boolean isDefined(String name) { if ( !alreadyLoaded ) load(); return super.isDefined(name); } @Override public synchronized void unload() { super.unload(); alreadyLoaded = false; } @Override protected CompiledST load(String name) { if ( !alreadyLoaded ) load(); return rawGetTemplate(name); } @Override public void load() { if ( alreadyLoaded ) return; alreadyLoaded = true; // do before actual load to say we're doing it // no prefix since this group file is the entire group, nothing lives // beneath it. if ( verbose ) System.out.println("loading group file "+url.toString()); loadGroupFile("/", url.toString()); if ( verbose ) System.out.println("found "+templates.size()+" templates in "+url.toString()+" = "+templates.keySet()); } @Override public String show() { if ( !alreadyLoaded ) load(); return super.show(); } @Override public String getName() { return Misc.getFileNameNoSuffix(fileName); } @Override public String getFileName() { return fileName; } @Override public URL getRootDirURL() { //System.out.println("url of "+fileName+" is "+url.toString()); String parent = Misc.stripLastPathElement(url.toString()); try { return new URL(parent); } catch (MalformedURLException mue) { errMgr.runTimeError(null, null, ErrorType.INVALID_TEMPLATE_NAME, mue, parent); } return null; } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/STGroupString.java000066400000000000000000000063041231426731300252240ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4; import org.antlr.runtime.*; import org.stringtemplate.v4.compiler.*; import org.stringtemplate.v4.misc.ErrorType; /** A group derived from a string not a file or directory. */ public class STGroupString extends STGroup { public String sourceName; public String text; protected boolean alreadyLoaded = false; public STGroupString(String text) { this("", text, '<', '>'); } public STGroupString(String sourceName, String text) { this(sourceName, text, '<', '>'); } public STGroupString(String sourceName, String text, char delimiterStartChar, char delimiterStopChar) { super(delimiterStartChar, delimiterStopChar); this.sourceName = sourceName; this.text = text; } @Override public boolean isDictionary(String name) { if ( !alreadyLoaded ) load(); return super.isDictionary(name); } @Override public boolean isDefined(String name) { if ( !alreadyLoaded ) load(); return super.isDefined(name); } @Override protected CompiledST load(String name) { if ( !alreadyLoaded ) load(); return rawGetTemplate(name); } @Override public void load() { if (alreadyLoaded) return; alreadyLoaded = true; GroupParser parser = null; try { ANTLRStringStream fs = new ANTLRStringStream(text); fs.name = sourceName; GroupLexer lexer = new GroupLexer(fs); CommonTokenStream tokens = new CommonTokenStream(lexer); parser = new GroupParser(tokens); // no prefix since this group file is the entire group, nothing lives // beneath it. parser.group(this, "/"); } catch (Exception e) { errMgr.IOError(null, ErrorType.CANT_LOAD_GROUP_FILE, e, ""); } } @Override public String getFileName() { return ""; } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/STRawGroupDir.java000066400000000000000000000034051231426731300251450ustar00rootroot00000000000000package org.stringtemplate.v4; import org.antlr.runtime.CharStream; import org.antlr.runtime.CommonToken; import org.stringtemplate.v4.compiler.*; import org.stringtemplate.v4.compiler.Compiler; import org.stringtemplate.v4.misc.Misc; import java.net.URL; /** A directory of templates without headers like ST v3 had. Still allows group * files in directory though like {@link STGroupDir} parent. */ public class STRawGroupDir extends STGroupDir { public STRawGroupDir(String dirName) { super(dirName); } public STRawGroupDir(String dirName, char delimiterStartChar, char delimiterStopChar) { super(dirName, delimiterStartChar, delimiterStopChar); } public STRawGroupDir(String dirName, String encoding) { super(dirName, encoding); } public STRawGroupDir(String dirName, String encoding, char delimiterStartChar, char delimiterStopChar) { super(dirName, encoding, delimiterStartChar, delimiterStopChar); } public STRawGroupDir(URL root, String encoding, char delimiterStartChar, char delimiterStopChar) { super(root, encoding, delimiterStartChar, delimiterStopChar); } @Override public CompiledST loadTemplateFile(String prefix, String unqualifiedFileName, CharStream templateStream) { String template = templateStream.substring(0, templateStream.size() - 1); String templateName = Misc.getFileNameNoSuffix(unqualifiedFileName); String fullyQualifiedTemplateName = prefix + templateName; CompiledST impl = new Compiler(this).compile(fullyQualifiedTemplateName, template); CommonToken nameT = new CommonToken(STLexer.SEMI); // Seems like a hack, best I could come up with. nameT.setInputStream(templateStream); rawDefineTemplate(fullyQualifiedTemplateName, impl, nameT); impl.defineImplicitlyDefinedTemplates(this); return impl; } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/STWriter.java000066400000000000000000000071601231426731300242160ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4; import org.stringtemplate.v4.compiler.Bytecode; import java.io.IOException; /** Generic StringTemplate output writer filter. *

* Literals and the elements of expressions are emitted via {@link #write(String)}. * Separators are emitted via {@link #writeSeparator(String)} because they must be * handled specially when wrapping lines (we don't want to wrap * in between an element and it's separator).

*/ public interface STWriter { public static final int NO_WRAP = -1; void pushIndentation(String indent); String popIndentation(); void pushAnchorPoint(); void popAnchorPoint(); void setLineWidth(int lineWidth); /** Write the string and return how many actual characters were written. * With auto-indentation and wrapping, more chars than {@code str.length()} * can be emitted. No wrapping is done. */ int write(String str) throws IOException; /** Same as write, but wrap lines using the indicated string as the * wrap character (such as {@code "\n"}). */ int write(String str, String wrap) throws IOException; /** * Because we evaluate ST instance by invoking * {@link Interpreter#exec(STWriter, InstanceScope)} again, we can't pass options in. * So the {@link Bytecode#INSTR_WRITE} instruction of an applied template * (such as when we wrap in between template applications like * {@code ]}; wrap>}) we need to write the {@code wrap} string * before calling {@link Interpreter#exec}. We expose just like for the * separator. See {@link Interpreter#writeObject} where it checks for ST * instance. If POJO, {@link Interpreter#writePOJO} passes {@code wrap} to * {@link STWriter#write(String str, String wrap)}. Can't pass to * {@link Interpreter#exec}. */ int writeWrap(String wrap) throws IOException; /** Write a separator. Same as {@link #write(String)} except that a {@code "\n"} * cannot be inserted before emitting a separator. */ int writeSeparator(String str) throws IOException; /** Return the absolute char index into the output of the char * we're about to write. Returns 0 if no char written yet. */ int index(); } stringtemplate4-4.0.8/src/org/stringtemplate/v4/StringRenderer.java000066400000000000000000000100001231426731300254130ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.Locale; /** This render knows to perform a few format operations on {@link String} objects: *
    *
  • {@code upper}: Convert to upper case.
  • *
  • {@code lower}: Convert to lower case.
  • *
  • {@code cap}: Convert first character to upper case.
  • *
  • {@code url-encode}:
  • *
  • {@code xml-encode}:
  • *
*/ public class StringRenderer implements AttributeRenderer { // trim(s) and strlen(s) built-in funcs; these are format options @Override public String toString(Object o, String formatString, Locale locale) { String s = (String)o; if ( formatString==null ) return s; if ( formatString.equals("upper") ) return s.toUpperCase(locale); if ( formatString.equals("lower") ) return s.toLowerCase(locale); if ( formatString.equals("cap") ) { return (s.length() > 0) ? Character.toUpperCase(s.charAt(0))+s.substring(1) : s; } if ( formatString.equals("url-encode") ) { try { return URLEncoder.encode(s, "UTF-8"); } catch (UnsupportedEncodingException ex) { // UTF-8 is standard, should always be available } } if ( formatString.equals("xml-encode") ) { return escapeHTML(s); } return String.format(locale, formatString, s); } public static String escapeHTML(String s) { if ( s==null ) { return null; } StringBuilder buf = new StringBuilder( s.length() ); int len = s.length(); for (int i=0; i' : buf.append(">"); break; case '\r': case '\n': case '\t': buf.append(c); break; default: boolean control = c < ' '; // 32 boolean aboveASCII = c > 126; if ( control || aboveASCII ) { buf.append("&#"); buf.append((int)c); buf.append(";"); } else buf.append(c); } } return buf.toString(); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/compiler/000077500000000000000000000000001231426731300234365ustar00rootroot00000000000000stringtemplate4-4.0.8/src/org/stringtemplate/v4/compiler/Bytecode.java000066400000000000000000000174731231426731300260530ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.compiler; public class Bytecode { public static final int MAX_OPNDS = 2; public static final int OPND_SIZE_IN_BYTES = 2; public enum OperandType { NONE, STRING, ADDR, INT } public static class Instruction { public String name; // E.g., "load_str", "new" public OperandType[] type = new OperandType[MAX_OPNDS]; public int nopnds = 0; public Instruction(String name) { this(name,OperandType.NONE,OperandType.NONE); nopnds =0; } public Instruction(String name, OperandType a) { this(name,a,OperandType.NONE); nopnds =1; } public Instruction(String name, OperandType a, OperandType b) { this.name = name; type[0] = a; type[1] = b; nopnds = MAX_OPNDS; } } // don't use enum for efficiency; don't want CompiledST.instrs to // be an array of objects (Bytecode[]). We want it to be byte[]. // INSTRUCTION BYTECODES (byte is signed; use a short to keep 0..255) public static final short INSTR_LOAD_STR = 1; public static final short INSTR_LOAD_ATTR = 2; public static final short INSTR_LOAD_LOCAL = 3; // load stuff like it, i, i0 public static final short INSTR_LOAD_PROP = 4; public static final short INSTR_LOAD_PROP_IND = 5; public static final short INSTR_STORE_OPTION = 6; public static final short INSTR_STORE_ARG = 7; public static final short INSTR_NEW = 8; // create new template instance public static final short INSTR_NEW_IND = 9; // create new instance using value on stack public static final short INSTR_NEW_BOX_ARGS = 10; // create new instance using args in Map on stack public static final short INSTR_SUPER_NEW = 11; // create new instance using value on stack public static final short INSTR_SUPER_NEW_BOX_ARGS = 12; // create new instance using args in Map on stack public static final short INSTR_WRITE = 13; public static final short INSTR_WRITE_OPT = 14; public static final short INSTR_MAP = 15; // , , public static final short INSTR_ROT_MAP = 16; // public static final short INSTR_ZIP_MAP = 17; // public static final short INSTR_BR = 18; public static final short INSTR_BRF = 19; public static final short INSTR_OPTIONS = 20; // push options map public static final short INSTR_ARGS = 21; // push args map public static final short INSTR_PASSTHRU = 22; //public static final short INSTR_PASSTHRU_IND = 23; public static final short INSTR_LIST = 24; public static final short INSTR_ADD = 25; public static final short INSTR_TOSTR = 26; // Predefined functions public static final short INSTR_FIRST = 27; public static final short INSTR_LAST = 28; public static final short INSTR_REST = 29; public static final short INSTR_TRUNC = 30; public static final short INSTR_STRIP = 31; public static final short INSTR_TRIM = 32; public static final short INSTR_LENGTH = 33; public static final short INSTR_STRLEN = 34; public static final short INSTR_REVERSE = 35; public static final short INSTR_NOT = 36; public static final short INSTR_OR = 37; public static final short INSTR_AND = 38; public static final short INSTR_INDENT = 39; public static final short INSTR_DEDENT = 40; public static final short INSTR_NEWLINE = 41; public static final short INSTR_NOOP = 42; // do nothing public static final short INSTR_POP = 43; public static final short INSTR_NULL = 44; // push null value public static final short INSTR_TRUE = 45; // push true value public static final short INSTR_FALSE = 46; // combined instructions public static final short INSTR_WRITE_STR = 47; // load_str n, write public static final short INSTR_WRITE_LOCAL = 48; // TODO load_local n, write public static final short MAX_BYTECODE = 48; /** Used for assembly/disassembly; describes instruction set */ public static Instruction[] instructions = new Instruction[] { null, // new Instruction("load_str",OperandType.STRING), // index is the opcode new Instruction("load_attr",OperandType.STRING), new Instruction("load_local",OperandType.INT), new Instruction("load_prop",OperandType.STRING), new Instruction("load_prop_ind"), new Instruction("store_option",OperandType.INT), new Instruction("store_arg",OperandType.STRING), new Instruction("new",OperandType.STRING,OperandType.INT), new Instruction("new_ind",OperandType.INT), new Instruction("new_box_args",OperandType.STRING), new Instruction("super_new",OperandType.STRING,OperandType.INT), new Instruction("super_new_box_args",OperandType.STRING), new Instruction("write"), new Instruction("write_opt"), new Instruction("map"), new Instruction("rot_map", OperandType.INT), new Instruction("zip_map", OperandType.INT), new Instruction("br", OperandType.ADDR), new Instruction("brf", OperandType.ADDR), new Instruction("options"), new Instruction("args"), new Instruction("passthru", OperandType.STRING), null, //new Instruction("passthru_ind", OperandType.INT), new Instruction("list"), new Instruction("add"), new Instruction("tostr"), new Instruction("first"), new Instruction("last"), new Instruction("rest"), new Instruction("trunc"), new Instruction("strip"), new Instruction("trim"), new Instruction("length"), new Instruction("strlen"), new Instruction("reverse"), new Instruction("not"), new Instruction("or"), new Instruction("and"), new Instruction("indent", OperandType.STRING), new Instruction("dedent"), new Instruction("newline"), new Instruction("noop"), new Instruction("pop"), new Instruction("null"), new Instruction("true"), new Instruction("false"), new Instruction("write_str", OperandType.STRING), new Instruction("write_local",OperandType.INT), }; } stringtemplate4-4.0.8/src/org/stringtemplate/v4/compiler/BytecodeDisassembler.java000066400000000000000000000133331231426731300304000ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.compiler; import org.stringtemplate.v4.misc.Interval; import org.stringtemplate.v4.misc.Misc; import java.util.ArrayList; import java.util.List; public class BytecodeDisassembler { CompiledST code; public BytecodeDisassembler(CompiledST code) { this.code = code; } public String instrs() { StringBuilder buf = new StringBuilder(); int ip=0; while (ip0 ) buf.append(", "); int opcode = code.instrs[ip]; Bytecode.Instruction I = Bytecode.instructions[opcode]; buf.append(I.name); ip++; for (int opnd=0; opnd=code.codeSize ) { throw new IllegalArgumentException("ip out of range: "+ip); } Bytecode.Instruction I = Bytecode.instructions[opcode]; if ( I==null ) { throw new IllegalArgumentException("no such instruction "+opcode+ " at address "+ip); } String instrName = I.name; buf.append( String.format("%04d:\t%-14s", ip, instrName) ); ip++; if ( I.nopnds ==0 ) { buf.append(" "); return ip; } List operands = new ArrayList(); for (int i=0; i0 ) buf.append(", "); buf.append( s ); } return ip; } private String showConstPoolOperand(int poolIndex) { StringBuilder buf = new StringBuilder(); buf.append("#"); buf.append(poolIndex); String s = ""; if ( poolIndex args] returns [CompiledST impl] scope { CompilationState state; // automatically get a new state pointer per invocation } @init { $template::state = new CompilationState(errMgr, name, input.getTokenStream()); $impl = $template::state.impl; if ( $template.size() == 1 ) outermostImpl = $impl; $impl.defineFormalArgs($args); // make sure args are defined prior to compilation if ( name!=null && name.startsWith(Compiler.SUBTEMPLATE_PREFIX) ) { $impl.addArg(new FormalArgument("i")); $impl.addArg(new FormalArgument("i0")); } $impl.template = template; // always forget the entire template; char indexes are relative to it } : chunk { // finish off the CompiledST result if ( $template::state.stringtable!=null ) $impl.strings = $template::state.stringtable.toArray(); $impl.codeSize = $template::state.ip; } ; chunk : element* ; element : ^(INDENTED_EXPR INDENT compoundElement[$INDENT]) // ignore indent in front of IF and region blocks | compoundElement[null] | ^(INDENTED_EXPR INDENT {$template::state.indent($INDENT);} singleElement {$template::state.emit(Bytecode.INSTR_DEDENT);}) | singleElement ; singleElement : exprElement | TEXT { if ( $TEXT.text.length()>0 ) { emit1($TEXT,Bytecode.INSTR_WRITE_STR, $TEXT.text); } } | NEWLINE {emit($NEWLINE, Bytecode.INSTR_NEWLINE);} ; compoundElement[CommonTree indent] : ifstat[indent] | region[indent] ; exprElement @init { short op = Bytecode.INSTR_WRITE; } : ^( EXPR expr (exprOptions {op=Bytecode.INSTR_WRITE_OPT;})? ) { /* CompilationState state = $template::state; CompiledST impl = state.impl; if ( impl.instrs[state.ip-1] == Bytecode.INSTR_LOAD_LOCAL ) { impl.instrs[state.ip-1] = Bytecode.INSTR_WRITE_LOCAL; } else { emit($EXPR, op); } */ emit($EXPR, op); } ; region[CommonTree indent] returns [String name] @init { if ( indent!=null ) $template::state.indent(indent); } @after { if ( indent!=null ) $template::state.emit(Bytecode.INSTR_DEDENT); } : ^( REGION ID {$name = STGroup.getMangledRegionName(outermostTemplateName, $ID.text);} template[$name,null] { CompiledST sub = $template.impl; sub.isRegion = true; sub.regionDefType = ST.RegionType.EMBEDDED; sub.templateDefStartToken = $ID.token; //sub.dump(); outermostImpl.addImplicitlyDefinedTemplate(sub); emit2($start, Bytecode.INSTR_NEW, $region.name, 0); emit($start, Bytecode.INSTR_WRITE); } ) ; subtemplate returns [String name, int nargs] @init { $name = Compiler.getNewSubtemplateName(); List args = new ArrayList(); } : ^( SUBTEMPLATE (^(ARGS (ID {args.add(new FormalArgument($ID.text));})+))* {$nargs = args.size();} template[$name,args] { CompiledST sub = $template.impl; sub.isAnonSubtemplate = true; sub.templateDefStartToken = $SUBTEMPLATE.token; sub.ast = $SUBTEMPLATE; sub.ast.setUnknownTokenBoundaries(); sub.tokens = input.getTokenStream(); //sub.dump(); outermostImpl.addImplicitlyDefinedTemplate(sub); } ) | SUBTEMPLATE // {} { CompiledST sub = new CompiledST(); sub.name = $name; sub.template = ""; sub.addArg(new FormalArgument("i")); sub.addArg(new FormalArgument("i0")); sub.isAnonSubtemplate = true; sub.templateDefStartToken = $SUBTEMPLATE.token; sub.ast = $SUBTEMPLATE; sub.ast.setUnknownTokenBoundaries(); sub.tokens = input.getTokenStream(); //sub.dump(); outermostImpl.addImplicitlyDefinedTemplate(sub); } ; ifstat[CommonTree indent] @init { /** Tracks address of branch operand (in code block). It's how * we backpatch forward references when generating code for IFs. */ int prevBranchOperand = -1; /** Branch instruction operands that are forward refs to end of IF. * We need to update them once we see the endif. */ List endRefs = new ArrayList(); if ( indent!=null ) $template::state.indent(indent); } @after { if ( indent!=null ) $template::state.emit(Bytecode.INSTR_DEDENT); } : ^( i='if' conditional { prevBranchOperand = address()+1; emit1($i,Bytecode.INSTR_BRF, -1); // write placeholder as branch target } chunk ( ^(eif='elseif' { endRefs.add(address()+1); emit1($eif,Bytecode.INSTR_BR, -1); // br end // update previous branch instruction write(prevBranchOperand, (short)address()); prevBranchOperand = -1; } ec=conditional { prevBranchOperand = address()+1; // write placeholder as branch target emit1($ec.start, Bytecode.INSTR_BRF, -1); } chunk ) )* ( ^( el='else' { endRefs.add(address()+1); emit1($el, Bytecode.INSTR_BR, -1); // br end // update previous branch instruction write(prevBranchOperand, (short)address()); prevBranchOperand = -1; } chunk ) )? ) { if ( prevBranchOperand>=0 ) { write(prevBranchOperand, (short)address()); } for (int opnd : endRefs) write(opnd, (short)address()); } ; conditional : ^(OR conditional conditional) {emit($OR, Bytecode.INSTR_OR);} | ^(AND conditional conditional) {emit($AND, Bytecode.INSTR_AND);} | ^(BANG conditional) {emit($BANG, Bytecode.INSTR_NOT);} | expr // not all expr are valid, but reuse code gen (parser restricts syntax) ; exprOptions : {emit($start, Bytecode.INSTR_OPTIONS);} ^(OPTIONS option*) ; option : ^('=' ID expr) {setOption($ID);} ; expr @init {int nt = 0, ne = 0;} : ^(ZIP ^(ELEMENTS (expr {ne++;})+) mapTemplateRef[ne]) {emit1($ZIP, Bytecode.INSTR_ZIP_MAP, ne);} | ^(MAP expr (mapTemplateRef[1] {nt++;})+) { if ( nt>1 ) emit1($MAP, nt>1?Bytecode.INSTR_ROT_MAP:Bytecode.INSTR_MAP, nt); else emit($MAP, Bytecode.INSTR_MAP); } | prop | includeExpr ; prop: ^(PROP expr ID) {emit1($PROP, Bytecode.INSTR_LOAD_PROP, $ID.text);} | ^(PROP_IND expr expr) {emit($PROP_IND, Bytecode.INSTR_LOAD_PROP_IND);} ; mapTemplateRef[int num_exprs] : ^( INCLUDE ID {for (int i=1; i<=$num_exprs; i++) emit($INCLUDE,Bytecode.INSTR_NULL);} args ) { if ( $args.passThru ) emit1($start, Bytecode.INSTR_PASSTHRU, $ID.text); if ( $args.namedArgs ) emit1($INCLUDE, Bytecode.INSTR_NEW_BOX_ARGS, $ID.text); else emit2($INCLUDE, Bytecode.INSTR_NEW, $ID.text, $args.n+$num_exprs); } | subtemplate { if ( $subtemplate.nargs != $num_exprs ) { errMgr.compileTimeError(ErrorType.ANON_ARGUMENT_MISMATCH, templateToken, $subtemplate.start.token, $subtemplate.nargs, $num_exprs); } for (int i=1; i<=$num_exprs; i++) emit($subtemplate.start,Bytecode.INSTR_NULL); emit2($subtemplate.start, Bytecode.INSTR_NEW, $subtemplate.name, $num_exprs); } | ^( INCLUDE_IND expr { emit($INCLUDE_IND,Bytecode.INSTR_TOSTR); for (int i=1; i<=$num_exprs; i++) emit($INCLUDE_IND,Bytecode.INSTR_NULL); } args { emit1($INCLUDE_IND, Bytecode.INSTR_NEW_IND, $args.n+$num_exprs); } ) ; includeExpr : ^(EXEC_FUNC ID expr?) {func($ID);} | ^(INCLUDE ID args) { if ( $args.passThru ) emit1($start, Bytecode.INSTR_PASSTHRU, $ID.text); if ( $args.namedArgs ) emit1($INCLUDE, Bytecode.INSTR_NEW_BOX_ARGS, $ID.text); else emit2($INCLUDE, Bytecode.INSTR_NEW, $ID.text, $args.n); } | ^(INCLUDE_SUPER ID args) { if ( $args.passThru ) emit1($start, Bytecode.INSTR_PASSTHRU, $ID.text); if ( $args.namedArgs ) emit1($INCLUDE_SUPER, Bytecode.INSTR_SUPER_NEW_BOX_ARGS, $ID.text); else emit2($INCLUDE_SUPER, Bytecode.INSTR_SUPER_NEW, $ID.text, $args.n); } | ^(INCLUDE_REGION ID) { CompiledST impl = Compiler.defineBlankRegion(outermostImpl, $ID.token); //impl.dump(); emit2($INCLUDE_REGION,Bytecode.INSTR_NEW,impl.name,0); } | ^(INCLUDE_SUPER_REGION ID) { String mangled = STGroup.getMangledRegionName(outermostImpl.name, $ID.text); emit2($INCLUDE_SUPER_REGION,Bytecode.INSTR_SUPER_NEW,mangled,0); } | primary ; primary : ID {refAttr($ID);} | STRING {emit1($STRING,Bytecode.INSTR_LOAD_STR, Misc.strip($STRING.text,1));} | TRUE {emit($TRUE, Bytecode.INSTR_TRUE);} | FALSE {emit($FALSE, Bytecode.INSTR_FALSE);} | subtemplate // push a subtemplate but ignore args since we can't pass any to it here {emit2($start,Bytecode.INSTR_NEW, $subtemplate.name, 0);} | list | ^( INCLUDE_IND expr {emit($INCLUDE_IND, Bytecode.INSTR_TOSTR);} args {emit1($INCLUDE_IND, Bytecode.INSTR_NEW_IND, $args.n);} ) | ^(TO_STR expr) {emit($TO_STR, Bytecode.INSTR_TOSTR);} ; arg : expr ; args returns [int n=0, boolean namedArgs=false, boolean passThru] : ( arg {$n++;} )+ | {emit($args.start, Bytecode.INSTR_ARGS); $namedArgs=true;} ( ^(eq='=' ID expr) {$n++; emit1($eq, Bytecode.INSTR_STORE_ARG, defineString($ID.text));} )+ ( '...' {$passThru=true;} )? | '...' {$passThru=true; emit($args.start, Bytecode.INSTR_ARGS); $namedArgs=true;} | ; list: {emit($start, Bytecode.INSTR_LIST);} ^(LIST (listElement {emit($listElement.start, Bytecode.INSTR_ADD);})* ) ; listElement : expr | NULL {emit($NULL,Bytecode.INSTR_NULL);} ; stringtemplate4-4.0.8/src/org/stringtemplate/v4/compiler/CompilationState.java000066400000000000000000000152351231426731300275660ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.compiler; import org.antlr.runtime.*; import org.antlr.runtime.tree.CommonTree; import org.stringtemplate.v4.Interpreter; import org.stringtemplate.v4.misc.*; /** Temporary data used during construction and functions that fill it / use it. * Result is {@link #impl} {@link CompiledST} object. */ public class CompilationState { /** The compiled code implementation to fill in. */ CompiledST impl = new CompiledST(); /** Track unique strings; copy into {@link CompiledST#strings} after compilation. */ StringTable stringtable = new StringTable(); /** * Track instruction location within * {@code impl.}{@link CompiledST#instrs instrs} array; this is next address * to write to. Byte-addressable memory. */ int ip = 0; TokenStream tokens; ErrorManager errMgr; public CompilationState(ErrorManager errMgr, String name, TokenStream tokens) { this.errMgr = errMgr; this.tokens = tokens; impl.name = name; impl.prefix = Misc.getPrefix(name); } public int defineString(String s) { return stringtable.add(s); } public void refAttr(Token templateToken, CommonTree id) { String name = id.getText(); if ( impl.formalArguments!=null && impl.formalArguments.get(name)!=null ) { FormalArgument arg = impl.formalArguments.get(name); int index = arg.index; emit1(id, Bytecode.INSTR_LOAD_LOCAL, index); } else { if ( Interpreter.predefinedAnonSubtemplateAttributes.contains(name) ) { errMgr.compileTimeError(ErrorType.REF_TO_IMPLICIT_ATTRIBUTE_OUT_OF_SCOPE, templateToken, id.token); emit(id, Bytecode.INSTR_NULL); } else { emit1(id, Bytecode.INSTR_LOAD_ATTR, name); } } } public void setOption(CommonTree id) { Interpreter.Option O = Compiler.supportedOptions.get(id.getText()); emit1(id, Bytecode.INSTR_STORE_OPTION, O.ordinal()); } public void func(Token templateToken, CommonTree id) { Short funcBytecode = Compiler.funcs.get(id.getText()); if ( funcBytecode==null ) { errMgr.compileTimeError(ErrorType.NO_SUCH_FUNCTION, templateToken, id.token); emit(id, Bytecode.INSTR_POP); } else { emit(id, funcBytecode); } } public void emit(short opcode) { emit(null,opcode); } public void emit(CommonTree opAST, short opcode) { ensureCapacity(1); if ( opAST!=null ) { int i = opAST.getTokenStartIndex(); int j = opAST.getTokenStopIndex(); int p = ((CommonToken)tokens.get(i)).getStartIndex(); int q = ((CommonToken)tokens.get(j)).getStopIndex(); if ( !(p<0 || q<0) ) impl.sourceMap[ip] = new Interval(p, q); } impl.instrs[ip++] = (byte)opcode; } public void emit1(CommonTree opAST, short opcode, int arg) { emit(opAST, opcode); ensureCapacity(Bytecode.OPND_SIZE_IN_BYTES); writeShort(impl.instrs, ip, (short)arg); ip += Bytecode.OPND_SIZE_IN_BYTES; } public void emit2(CommonTree opAST, short opcode, int arg, int arg2) { emit(opAST, opcode); ensureCapacity(Bytecode.OPND_SIZE_IN_BYTES * 2); writeShort(impl.instrs, ip, (short)arg); ip += Bytecode.OPND_SIZE_IN_BYTES; writeShort(impl.instrs, ip, (short)arg2); ip += Bytecode.OPND_SIZE_IN_BYTES; } public void emit2(CommonTree opAST, short opcode, String s, int arg2) { int i = defineString(s); emit2(opAST, opcode, i, arg2); } public void emit1(CommonTree opAST, short opcode, String s) { int i = defineString(s); emit1(opAST, opcode, i); } public void insert(int addr, short opcode, String s) { //System.out.println("before insert of "+opcode+"("+s+"):"+ Arrays.toString(impl.instrs)); ensureCapacity(1+Bytecode.OPND_SIZE_IN_BYTES); int instrSize = 1 + Bytecode.OPND_SIZE_IN_BYTES; System.arraycopy(impl.instrs, addr, impl.instrs, addr + instrSize, ip-addr); // make room for opcode, opnd int save = ip; ip = addr; emit1(null,opcode, s); ip = save+instrSize; //System.out.println("after insert of "+opcode+"("+s+"):"+ Arrays.toString(impl.instrs)); // adjust addresses for BR and BRF int a=addr+instrSize; while ( a < ip ) { byte op = impl.instrs[a]; Bytecode.Instruction I = Bytecode.instructions[op]; if ( op == Bytecode.INSTR_BR || op == Bytecode.INSTR_BRF ) { int opnd = BytecodeDisassembler.getShort(impl.instrs, a+1); writeShort(impl.instrs, a+1, (short)(opnd+instrSize)); } a += I.nopnds * Bytecode.OPND_SIZE_IN_BYTES + 1; } //System.out.println("after insert of "+opcode+"("+s+"):"+ Arrays.toString(impl.instrs)); } public void write(int addr, short value) { writeShort(impl.instrs, addr, value); } protected void ensureCapacity(int n) { if ( (ip+n) >= impl.instrs.length ) { // ensure room for full instruction byte[] c = new byte[impl.instrs.length*2]; System.arraycopy(impl.instrs, 0, c, 0, impl.instrs.length); impl.instrs = c; Interval[] sm = new Interval[impl.sourceMap.length*2]; System.arraycopy(impl.sourceMap, 0, sm, 0, impl.sourceMap.length); impl.sourceMap = sm; } } public void indent(CommonTree indent) { emit1(indent,Bytecode.INSTR_INDENT, indent.getText()); } /** Write value at index into a byte array highest to lowest byte, * left to right. */ public static void writeShort(byte[] memory, int index, short value) { memory[index+0] = (byte)((value>>(8*1))&0xFF); memory[index+1] = (byte)(value&0xFF); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/compiler/CompiledST.java000066400000000000000000000226611231426731300263130ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.compiler; import org.antlr.runtime.*; import org.antlr.runtime.tree.CommonTree; import org.stringtemplate.v4.*; import org.stringtemplate.v4.misc.*; import java.io.*; import java.util.*; /** The result of compiling an {@link ST}. Contains all the bytecode instructions, * string table, bytecode address to source code map, and other bookkeeping * info. It's the implementation of an ST you might say. All instances * of the same template share a single implementation ({@link ST#impl} field). */ public class CompiledST implements Cloneable { public String name; /** * Every template knows where it is relative to the group that loaded it. * The prefix is the relative path from the root. {@code "/prefix/name"} is * the fully qualified name of this template. All calls to * {@link STGroup#getInstanceOf} calls must use fully qualified names. A * {@code "/"} is added to the front if you don't specify one. Template * references within template code, however, uses relative names, unless of * course the name starts with {@code "/"}. *

* This has nothing to do with the outer filesystem path to the group dir or * group file.

*

* We set this as we load/compile the template.

*

* Always ends with {@code "/"}.

*/ public String prefix = "/"; /** The original, immutable pattern (not really used again after * initial "compilation"). Useful for debugging. Even for * subtemplates, this is entire overall template. */ public String template; /** The token that begins template definition; could be {@code <@r>} of region. */ public Token templateDefStartToken; /** Overall token stream for template (debug only). */ public TokenStream tokens; /** How do we interpret syntax of template? (debug only) */ public CommonTree ast; public Map formalArguments; public boolean hasFormalArgs; public int numberOfArgsWithDefaultValues; /** A list of all regions and subtemplates. */ public List implicitlyDefinedTemplates; /** * The group that physically defines this {@link ST} definition. We use it * to initiate interpretation via {@link ST#toString}. From there, it * becomes field {@link Interpreter#group} and is fixed until rendering * completes. */ public STGroup nativeGroup = STGroup.defaultGroup; /** Does this template come from a {@code <@region>...<@end>} embedded in * another template? */ public boolean isRegion; /** * If someone refs {@code <@r()>} in template t, an implicit * *

* {@code @t.r() ::= ""}

*

* is defined, but you can overwrite this def by defining your own. We need * to prevent more than one manual def though. Between this var and * {@link #isRegion} we can determine these cases.

*/ public ST.RegionType regionDefType; public boolean isAnonSubtemplate; // {...} public String[] strings; // string operands of instructions public byte[] instrs; // byte-addressable code memory. public int codeSize; public Interval[] sourceMap; // maps IP to range in template pattern public CompiledST() { instrs = new byte[Compiler.TEMPLATE_INITIAL_CODE_SIZE]; sourceMap = new Interval[Compiler.TEMPLATE_INITIAL_CODE_SIZE]; template = ""; } /** * Cloning the {@link CompiledST} for an {@link ST} instance allows * {@link ST#add} to be called safely during interpretation for templates * that do not contain formal arguments. * * @return A copy of the current {@link CompiledST} instance. The copy is a * shallow copy, with the exception of the {@link #formalArguments} field * which is also cloned. * * @exception CloneNotSupportedException If the current instance cannot be * cloned. */ @Override public CompiledST clone() throws CloneNotSupportedException { CompiledST clone = (CompiledST)super.clone(); if (formalArguments != null) { formalArguments = Collections.synchronizedMap(new LinkedHashMap(formalArguments)); } return clone; } public void addImplicitlyDefinedTemplate(CompiledST sub) { sub.prefix = this.prefix; if ( sub.name.charAt(0)!='/' ) sub.name = sub.prefix+sub.name; if ( implicitlyDefinedTemplates == null ) { implicitlyDefinedTemplates = new ArrayList(); } implicitlyDefinedTemplates.add(sub); } public void defineArgDefaultValueTemplates(STGroup group) { if ( formalArguments==null ) return; for (String a : formalArguments.keySet()) { FormalArgument fa = formalArguments.get(a); if ( fa.defaultValueToken!=null ) { numberOfArgsWithDefaultValues++; switch (fa.defaultValueToken.getType()) { case GroupParser.ANONYMOUS_TEMPLATE: String argSTname = fa.name + "_default_value"; Compiler c2 = new Compiler(group); String defArgTemplate = Misc.strip(fa.defaultValueToken.getText(), 1); fa.compiledDefaultValue = c2.compile(group.getFileName(), argSTname, null, defArgTemplate, fa.defaultValueToken); fa.compiledDefaultValue.name = argSTname; fa.compiledDefaultValue.defineImplicitlyDefinedTemplates(group); break; case GroupParser.STRING: fa.defaultValue = Misc.strip(fa.defaultValueToken.getText(), 1); break; case GroupParser.LBRACK: fa.defaultValue = Collections.emptyList(); break; case GroupParser.TRUE: case GroupParser.FALSE: fa.defaultValue = fa.defaultValueToken.getType()==GroupParser.TRUE; break; default: throw new UnsupportedOperationException("Unexpected default value token type."); } } } } public void defineFormalArgs(List args) { hasFormalArgs = true; // even if no args; it's formally defined if ( args == null ) formalArguments = null; else for (FormalArgument a : args) addArg(a); } /** Used by {@link ST#add} to add args one by one without turning on full formal args definition signal. */ public void addArg(FormalArgument a) { if ( formalArguments==null ) { formalArguments = Collections.synchronizedMap(new LinkedHashMap()); } a.index = formalArguments.size(); formalArguments.put(a.name, a); } public void defineImplicitlyDefinedTemplates(STGroup group) { if ( implicitlyDefinedTemplates !=null ) { for (CompiledST sub : implicitlyDefinedTemplates) { group.rawDefineTemplate(sub.name, sub, sub.templateDefStartToken); sub.defineImplicitlyDefinedTemplates(group); } } } public String getTemplateSource() { Interval r = getTemplateRange(); return template.substring(r.a, r.b+1); } public Interval getTemplateRange() { if ( isAnonSubtemplate ) { int start = Integer.MAX_VALUE; int stop = Integer.MIN_VALUE; for (Interval interval : sourceMap) { if (interval == null) { continue; } start = Math.min(start, interval.a); stop = Math.max(stop, interval.b); } if (start <= stop + 1) { return new Interval(start, stop); } } return new Interval(0, template.length()-1); } public String instrs() { BytecodeDisassembler dis = new BytecodeDisassembler(this); return dis.instrs(); } public void dump() { BytecodeDisassembler dis = new BytecodeDisassembler(this); System.out.println(name+":"); System.out.println(dis.disassemble()); System.out.println("Strings:"); System.out.println(dis.strings()); System.out.println("Bytecode to template map:"); System.out.println(dis.sourceMap()); } public String disasm() { BytecodeDisassembler dis = new BytecodeDisassembler(this); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); pw.println(dis.disassemble()); pw.println("Strings:"); pw.println(dis.strings()); pw.println("Bytecode to template map:"); pw.println(dis.sourceMap()); pw.close(); return sw.toString(); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/compiler/Compiler.java000066400000000000000000000174341231426731300260640ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.compiler; import org.antlr.runtime.*; import org.antlr.runtime.tree.CommonTree; import org.antlr.runtime.tree.CommonTreeNodeStream; import org.stringtemplate.v4.Interpreter; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.misc.ErrorType; import java.util.HashMap; import java.util.List; import java.util.Map; /** A compiler for a single template. */ public class Compiler { public static final String SUBTEMPLATE_PREFIX = "_sub"; public static final int TEMPLATE_INITIAL_CODE_SIZE = 15; public static final Map supportedOptions = new HashMap() { { put("anchor", Interpreter.Option.ANCHOR); put("format", Interpreter.Option.FORMAT); put("null", Interpreter.Option.NULL); put("separator", Interpreter.Option.SEPARATOR); put("wrap", Interpreter.Option.WRAP); } }; public static final int NUM_OPTIONS = supportedOptions.size(); public static final Map defaultOptionValues = new HashMap() { { put("anchor", "true"); put("wrap", "\n"); } }; public static Map funcs = new HashMap() { { put("first", Bytecode.INSTR_FIRST); put("last", Bytecode.INSTR_LAST); put("rest", Bytecode.INSTR_REST); put("trunc", Bytecode.INSTR_TRUNC); put("strip", Bytecode.INSTR_STRIP); put("trim", Bytecode.INSTR_TRIM); put("length", Bytecode.INSTR_LENGTH); put("strlen", Bytecode.INSTR_STRLEN); put("reverse", Bytecode.INSTR_REVERSE); } }; /** Name subtemplates {@code _sub1}, {@code _sub2}, ... */ public static int subtemplateCount = 0; public STGroup group; public Compiler() { this(STGroup.defaultGroup); } public Compiler(STGroup group) { this.group = group; } public CompiledST compile(String template) { CompiledST code = compile(null, null, null, template, null); code.hasFormalArgs = false; return code; } /** Compile full template with unknown formal arguments. */ public CompiledST compile(String name, String template) { CompiledST code = compile(null, name, null, template, null); code.hasFormalArgs = false; return code; } /** Compile full template with respect to a list of formal arguments. */ public CompiledST compile(String srcName, String name, List args, String template, Token templateToken) { ANTLRStringStream is = new ANTLRStringStream(template); is.name = srcName!=null ? srcName : name; STLexer lexer = null; if ( templateToken!=null && templateToken.getType() == GroupParser.BIGSTRING_NO_NL ) { lexer = new STLexer(group.errMgr, is, templateToken, group.delimiterStartChar, group.delimiterStopChar) { /** Throw out \n and indentation tokens inside BIGSTRING_NO_NL */ @Override public Token nextToken() { Token t = super.nextToken(); while ( t.getType() == STLexer.NEWLINE || t.getType()==STLexer.INDENT ) { t = super.nextToken(); } return t; } }; } else { lexer = new STLexer(group.errMgr, is, templateToken, group.delimiterStartChar, group.delimiterStopChar); } CommonTokenStream tokens = new CommonTokenStream(lexer); STParser p = new STParser(tokens, group.errMgr, templateToken); STParser.templateAndEOF_return r = null; try { r = p.templateAndEOF(); } catch (RecognitionException re) { reportMessageAndThrowSTException(tokens, templateToken, p, re); return null; } if ( p.getNumberOfSyntaxErrors()>0 || r.getTree()==null ) { CompiledST impl = new CompiledST(); impl.defineFormalArgs(args); return impl; } //System.out.println(((CommonTree)r.getTree()).toStringTree()); CommonTreeNodeStream nodes = new CommonTreeNodeStream(r.getTree()); nodes.setTokenStream(tokens); CodeGenerator gen = new CodeGenerator(nodes, group.errMgr, name, template, templateToken); CompiledST impl=null; try { impl = gen.template(name,args); impl.nativeGroup = group; impl.template = template; impl.ast = r.getTree(); impl.ast.setUnknownTokenBoundaries(); impl.tokens = tokens; } catch (RecognitionException re) { group.errMgr.internalError(null, "bad tree structure", re); } return impl; } public static CompiledST defineBlankRegion(CompiledST outermostImpl, Token nameToken) { String outermostTemplateName = outermostImpl.name; String mangled = STGroup.getMangledRegionName(outermostTemplateName, nameToken.getText()); CompiledST blank = new CompiledST(); blank.isRegion = true; blank.templateDefStartToken = nameToken; blank.regionDefType = ST.RegionType.IMPLICIT; blank.name = mangled; outermostImpl.addImplicitlyDefinedTemplate(blank); return blank; } public static String getNewSubtemplateName() { subtemplateCount++; return SUBTEMPLATE_PREFIX+subtemplateCount; } protected void reportMessageAndThrowSTException(TokenStream tokens, Token templateToken, Parser parser, RecognitionException re) { if ( re.token.getType() == STLexer.EOF_TYPE ) { String msg = "premature EOF"; group.errMgr.compileTimeError(ErrorType.SYNTAX_ERROR, templateToken, re.token, msg); } else if ( re instanceof NoViableAltException) { String msg = "'"+re.token.getText()+"' came as a complete surprise to me"; group.errMgr.compileTimeError(ErrorType.SYNTAX_ERROR, templateToken, re.token, msg); } else if ( tokens.index() == 0 ) { // couldn't parse anything String msg = "this doesn't look like a template: \""+tokens+"\""; group.errMgr.compileTimeError(ErrorType.SYNTAX_ERROR, templateToken, re.token, msg); } else if ( tokens.LA(1) == STLexer.LDELIM ) { // couldn't parse expr String msg = "doesn't look like an expression"; group.errMgr.compileTimeError(ErrorType.SYNTAX_ERROR, templateToken, re.token, msg); } else { String msg = parser.getErrorMessage(re, parser.getTokenNames()); group.errMgr.compileTimeError(ErrorType.SYNTAX_ERROR, templateToken, re.token, msg); } throw new STException(); // we have reported the error, so just blast out } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/compiler/FormalArgument.java000066400000000000000000000103061231426731300272240ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.compiler; import org.antlr.runtime.Token; /** * Represents the name of a formal argument defined in a template: *
 *  test(a,b,x=defaultvalue) ::= "<a> <n> <x>"
 * 
Each template has a set of these formal arguments or sets * {@link CompiledST#hasFormalArgs} to {@code false} (indicating that no * arguments were specified such as when we create a template with * {@code new ST(...)}). * *

* Note: originally, I tracked cardinality as well as the name of an attribute. * I'm leaving the code here as I suspect something may come of it later. * Currently, though, cardinality is not used.

*/ public class FormalArgument { /* // the following represent bit positions emulating a cardinality bitset. public static final int OPTIONAL = 1; // a? public static final int REQUIRED = 2; // a public static final int ZERO_OR_MORE = 4; // a* public static final int ONE_OR_MORE = 8; // a+ public static final String[] suffixes = { null, "?", "", null, "*", null, null, null, "+" }; protected int cardinality = REQUIRED; */ public String name; public int index; // which argument is it? from 0..n-1 /** If they specified default value {@code x=y}, store the token here */ public Token defaultValueToken; public Object defaultValue; // x="str", x=true, x=false public CompiledST compiledDefaultValue; // x={...} public FormalArgument(String name) { this.name = name; } public FormalArgument(String name, Token defaultValueToken) { this.name = name; this.defaultValueToken = defaultValueToken; } /* public static String getCardinalityName(int cardinality) { switch (cardinality) { case OPTIONAL : return "optional"; case REQUIRED : return "exactly one"; case ZERO_OR_MORE : return "zero-or-more"; case ONE_OR_MORE : return "one-or-more"; default : return "unknown"; } } */ @Override public int hashCode() { return name.hashCode() + defaultValueToken.hashCode(); } @Override public boolean equals(Object o) { if ( o==null || !(o instanceof FormalArgument) ) { return false; } FormalArgument other = (FormalArgument)o; if ( !this.name.equals(other.name) ) { return false; } // only check if there is a default value; that's all return !((this.defaultValueToken != null && other.defaultValueToken == null) || (this.defaultValueToken == null && other.defaultValueToken != null)); } @Override public String toString() { if ( defaultValueToken!=null ) return name+"="+defaultValueToken.getText(); return name; } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/compiler/Group.g000066400000000000000000000331661231426731300247130ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ grammar Group; options { language=Java; } tokens { TRUE='true'; FALSE='false'; LBRACK='['; RBRACK=']'; } @header { /* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.compiler; import java.util.Collections; import java.util.Map; import java.util.HashMap; import java.util.List; import java.util.ArrayList; import org.stringtemplate.v4.misc.*; import org.stringtemplate.v4.*; import java.io.File; } @lexer::header { /* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.compiler; import org.stringtemplate.v4.*; import org.stringtemplate.v4.misc.*; import java.io.File; } @members { public STGroup group; @Override public void displayRecognitionError(String[] tokenNames, RecognitionException e) { String msg = getErrorMessage(e, tokenNames); group.errMgr.groupSyntaxError(ErrorType.SYNTAX_ERROR, getSourceName(), e, msg); } @Override public String getSourceName() { String fullFileName = super.getSourceName(); File f = new File(fullFileName); // strip to simple name return f.getName(); } public void error(String msg) { NoViableAltException e = new NoViableAltException("", 0, 0, input); group.errMgr.groupSyntaxError(ErrorType.SYNTAX_ERROR, getSourceName(), e, msg); recover(input, null); } } @lexer::members { public STGroup group; @Override public void reportError(RecognitionException e) { String msg = null; if ( e instanceof NoViableAltException ) { msg = "invalid character '"+(char)input.LA(1)+"'"; } else if ( e instanceof MismatchedTokenException && ((MismatchedTokenException)e).expecting=='"' ) { msg = "unterminated string"; } else { msg = getErrorMessage(e, getTokenNames()); } group.errMgr.groupSyntaxError(ErrorType.SYNTAX_ERROR, getSourceName(), e, msg); } @Override public String getSourceName() { String fullFileName = super.getSourceName(); File f = new File(fullFileName); // strip to simple name return f.getName(); } } group[STGroup group, String prefix] @init { GroupLexer lexer = (GroupLexer)input.getTokenSource(); this.group = lexer.group = $group; } : oldStyleHeader? delimiters? ( 'import' STRING {group.importTemplates($STRING);} | 'import' // common error: name not in string { MismatchedTokenException e = new MismatchedTokenException(STRING, input); reportError(e); } ID ('.' ID)* // might be a.b.c.d )* def[prefix]* EOF ; oldStyleHeader // ignore but lets us use this parser in AW for both v3 and v4 : 'group' ID ( ':' ID )? ( 'implements' ID (',' ID)* )? ';' ; groupName returns [String name] @init {StringBuilder buf = new StringBuilder();} : a=ID {buf.append($a.text);} ('.' a=ID {buf.append($a.text);})* ; delimiters : 'delimiters' a=STRING ',' b=STRING { group.delimiterStartChar=$a.getText().charAt(1); group.delimiterStopChar=$b.getText().charAt(1); } ; /** Match template and dictionary defs outside of (...)+ loop in group. * The key is catching while still in the loop; must keep prediction of * elements separate from "stay in loop" prediction. */ def[String prefix] : templateDef[prefix] | dictDef ; catch[RecognitionException re] { // pretend we already saw an error here state.lastErrorIndex = input.index(); error("garbled template definition starting at '"+input.LT(1).getText()+"'"); } templateDef[String prefix] @init { String template=null; int n=0; // num char to strip from left, right of template def } : ( '@' enclosing=ID '.' name=ID '(' ')' | name=ID '(' formalArgs ')' ) '::=' {Token templateToken = input.LT(1);} ( STRING {template=$STRING.text; n=1;} | BIGSTRING {template=$BIGSTRING.text; n=2;} | BIGSTRING_NO_NL {template=$BIGSTRING_NO_NL.text; n=2;} | { template = ""; String msg = "missing template at '"+input.LT(1).getText()+"'"; NoViableAltException e = new NoViableAltException("", 0, 0, input); group.errMgr.groupSyntaxError(ErrorType.SYNTAX_ERROR, getSourceName(), e, msg); } ) { if ( $name.index >= 0 ) { // if ID missing template = Misc.strip(template, n); String templateName = $name.text; if ( prefix.length()>0 ) templateName = prefix+$name.text; String enclosingTemplateName = $enclosing.text; if (enclosingTemplateName != null && enclosingTemplateName.length()>0 && prefix.length()>0) { enclosingTemplateName = prefix + enclosingTemplateName; } group.defineTemplateOrRegion(templateName, enclosingTemplateName, templateToken, template, $name, $formalArgs.args); } } | alias=ID '::=' target=ID {group.defineTemplateAlias($alias, $target);} ; formalArgs returns[List args = new ArrayList()] scope { boolean hasOptionalParameter; } @init { $formalArgs::hasOptionalParameter = false; } : formalArg[$args] (',' formalArg[$args])* | ; formalArg[List args] : ID ( '=' a=(STRING|ANONYMOUS_TEMPLATE|'true'|'false') {$formalArgs::hasOptionalParameter = true;} | '=' a='[' ']' {$formalArgs::hasOptionalParameter = true;} | { if ($formalArgs::hasOptionalParameter) { group.errMgr.compileTimeError(ErrorType.REQUIRED_PARAMETER_AFTER_OPTIONAL, null, $ID); } } ) {$args.add(new FormalArgument($ID.text, $a));} ; /* suffix returns [int cardinality=FormalArgument.REQUIRED] : OPTIONAL | STAR | PLUS | ; */ dictDef : ID '::=' dict { if ( group.rawGetDictionary($ID.text)!=null ) { group.errMgr.compileTimeError(ErrorType.MAP_REDEFINITION, null, $ID); } else if ( group.rawGetTemplate($ID.text)!=null ) { group.errMgr.compileTimeError(ErrorType.TEMPLATE_REDEFINITION_AS_MAP, null, $ID); } else { group.defineDictionary($ID.text, $dict.mapping); } } ; dict returns [Map mapping] @init {mapping=new HashMap();} : '[' dictPairs[mapping] ']' ; dictPairs[Map mapping] : keyValuePair[mapping] (',' keyValuePair[mapping])* (',' defaultValuePair[mapping])? | defaultValuePair[mapping] ; catch[RecognitionException re] { error("missing dictionary entry at '"+input.LT(1).getText()+"'"); } defaultValuePair[Map mapping] : 'default' ':' keyValue {mapping.put(STGroup.DEFAULT_KEY, $keyValue.value);} ; keyValuePair[Map mapping] : STRING ':' keyValue {mapping.put(Misc.replaceEscapes(Misc.strip($STRING.text, 1)), $keyValue.value);} ; keyValue returns [Object value] : BIGSTRING {$value = group.createSingleton($BIGSTRING);} | BIGSTRING_NO_NL {$value = group.createSingleton($BIGSTRING_NO_NL);} | ANONYMOUS_TEMPLATE {$value = group.createSingleton($ANONYMOUS_TEMPLATE);} | STRING {$value = Misc.replaceEscapes(Misc.strip($STRING.text, 1));} | TRUE {$value = true;} | FALSE {$value = false;} | '[' ']' {$value = Collections.emptyList();} | {input.LT(1).getText().equals("key")}?=> ID {$value = STGroup.DICT_KEY;} ; catch[RecognitionException re] { error("missing value for key at '"+input.LT(1).getText()+"'"); } ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'-'|'_')* ; STRING : '"' ( '\\' '"' | '\\' ~'"' | { String msg = "\\n in string"; NoViableAltException e = new NoViableAltException("", 0, 0, input); group.errMgr.groupLexerError(ErrorType.SYNTAX_ERROR, getSourceName(), e, msg); } '\n' | ~('\\'|'"'|'\n') )* '"' { String txt = getText().replaceAll("\\\\\"","\""); setText(txt); } ; BIGSTRING_NO_NL // same as BIGSTRING but means ignore newlines later : '<%' ( . )* '%>' // %\> is the escape to avoid end of string { String txt = getText().replaceAll("\%\\\\>","\%>"); setText(txt); } ; /** Match <<...>> but also allow <<..>> so we can have tag on end. Escapes: >\> means >> inside of <<...>>. Escapes: \>> means >> inside of <<...>> unless at end like <<...\>>>>. In that case, use <%..>>%> instead. */ BIGSTRING : '<<' ( options {greedy=false;} : '\\' '>' // \> escape | '\\' ~'>' // allow this but don't collapse in action | ~'\\' )* '>>' { String txt = getText(); txt = Misc.replaceEscapedRightAngle(txt); // replace \> with > unless <\\> setText(txt); } ; ANONYMOUS_TEMPLATE : '{' { Token templateToken = new CommonToken(input, ANONYMOUS_TEMPLATE, 0, getCharIndex(), getCharIndex()); STLexer lexer = new STLexer(group.errMgr, input, templateToken, group.delimiterStartChar, group.delimiterStopChar); lexer.subtemplateDepth = 1; Token t = lexer.nextToken(); while ( lexer.subtemplateDepth>=1 || t.getType()!=STLexer.RCURLY ) { if ( t.getType()==STLexer.EOF_TYPE ) { MismatchedTokenException e = new MismatchedTokenException('}', input); String msg = "missing final '}' in {...} anonymous template"; group.errMgr.groupLexerError(ErrorType.SYNTAX_ERROR, getSourceName(), e, msg); break; } t = lexer.nextToken(); } } // don't match '}' here; our little {...} scanner loop matches it // to terminate. ; COMMENT : '/*' ( options {greedy=false;} : . )* '*/' {skip();} ; LINE_COMMENT : '//' ~('\n'|'\r')* '\r'? '\n' {skip();} ; WS : (' '|'\r'|'\t'|'\n') {skip();} ; stringtemplate4-4.0.8/src/org/stringtemplate/v4/compiler/STException.java000066400000000000000000000033051231426731300265070ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.compiler; public class STException extends RuntimeException { // no checking damnit! public STException() { ; } public STException(String msg, Exception cause) { super(msg,cause); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/compiler/STLexer.java000066400000000000000000000513101231426731300256270ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.compiler; import org.antlr.runtime.CharStream; import org.antlr.runtime.CommonToken; import org.antlr.runtime.MismatchedTokenException; import org.antlr.runtime.NoViableAltException; import org.antlr.runtime.RecognitionException; import org.antlr.runtime.Token; import org.antlr.runtime.TokenSource; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.misc.ErrorManager; import org.stringtemplate.v4.misc.Misc; import java.util.ArrayList; import java.util.List; /** * This class represents the tokenizer for templates. It operates in two modes: * inside and outside of expressions. It implements the {@link TokenSource} * interface so it can be used with ANTLR parsers. Outside of expressions, we * can return these token types: {@link #TEXT}, {@link #INDENT}, {@link #LDELIM} * (start of expression), {@link #RCURLY} (end of subtemplate), and * {@link #NEWLINE}. Inside of an expression, this lexer returns all of the * tokens needed by {@link STParser}. From the parser's point of view, it can * treat a template as a simple stream of elements. *

* This class defines the token types and communicates these values to * {@code STParser.g} via {@code STLexer.tokens} file (which must remain * consistent).

*/ public class STLexer implements TokenSource { public static final char EOF = (char)-1; // EOF char public static final int EOF_TYPE = CharStream.EOF; // EOF token type /** We build {@code STToken} tokens instead of relying on {@link CommonToken} * so we can override {@link #toString()}. It just converts token types to * token names like 23 to {@code "LDELIM"}. */ public static class STToken extends CommonToken { public STToken(CharStream input, int type, int start, int stop) { super(input, type, DEFAULT_CHANNEL, start, stop); } public STToken(int type, String text) { super(type, text); } @Override public String toString() { String channelStr = ""; if ( channel>0 ) { channelStr=",channel="+channel; } String txt = getText(); if ( txt!=null ) txt = Misc.replaceEscapes(txt); else txt = ""; String tokenName = null; if ( type==EOF_TYPE ) tokenName = "EOF"; else tokenName = STParser.tokenNames[type]; return "[@"+getTokenIndex()+","+start+":"+stop+"='"+txt+"',<"+ tokenName +">"+channelStr+","+line+":"+getCharPositionInLine()+"]"; } } public static final Token SKIP = new STToken(-1, ""); // must follow STLexer.tokens file that STParser.g loads public static final int RBRACK=17; public static final int LBRACK=16; public static final int ELSE=5; public static final int ELLIPSIS=11; public static final int LCURLY=20; public static final int BANG=10; public static final int EQUALS=12; public static final int TEXT=22; public static final int ID=25; public static final int SEMI=9; public static final int LPAREN=14; public static final int IF=4; public static final int ELSEIF=6; public static final int COLON=13; public static final int RPAREN=15; public static final int COMMA=18; public static final int RCURLY=21; public static final int ENDIF=7; public static final int RDELIM=24; public static final int SUPER=8; public static final int DOT=19; public static final int LDELIM=23; public static final int STRING=26; public static final int PIPE=28; public static final int OR=29; public static final int AND=30; public static final int INDENT=31; public static final int NEWLINE=32; public static final int AT=33; public static final int REGION_END=34; public static final int TRUE=35; public static final int FALSE=36; public static final int COMMENT=37; /** The char which delimits the start of an expression. */ char delimiterStartChar = '<'; /** The char which delimits the end of an expression. */ char delimiterStopChar = '>'; /** * This keeps track of the current mode of the lexer. Are we inside or * outside an ST expression? */ boolean scanningInsideExpr = false; /** To be able to properly track the inside/outside mode, we need to * track how deeply nested we are in some templates. Otherwise, we * know whether a '}' and the outermost subtemplate to send this * back to outside mode. */ public int subtemplateDepth = 0; // start out *not* in a {...} subtemplate ErrorManager errMgr; /** template embedded in a group file? this is the template */ Token templateToken; CharStream input; /** current character */ char c; /** When we started token, track initial coordinates so we can properly * build token objects. */ int startCharIndex; int startLine; int startCharPositionInLine; /** Our lexer routines might have to emit more than a single token. We * buffer everything through this list. */ List tokens = new ArrayList(); public STLexer(CharStream input) { this(STGroup.DEFAULT_ERR_MGR, input, null, '<', '>'); } public STLexer(ErrorManager errMgr, CharStream input, Token templateToken) { this(errMgr, input, templateToken, '<', '>'); } public STLexer(ErrorManager errMgr, CharStream input, Token templateToken, char delimiterStartChar, char delimiterStopChar) { this.errMgr = errMgr; this.input = input; c = (char)input.LA(1); // prime lookahead this.templateToken = templateToken; this.delimiterStartChar = delimiterStartChar; this.delimiterStopChar = delimiterStopChar; } @Override public Token nextToken() { Token t; if ( tokens.size()>0 ) { t = tokens.remove(0); } else t = _nextToken(); // System.out.println(t); return t; } /** Consume if {@code x} is next character on the input stream. */ public void match(char x) { if ( c != x ) { NoViableAltException e = new NoViableAltException("",0,0,input); errMgr.lexerError(input.getSourceName(), "expecting '"+x+"', found '"+str(c)+"'", templateToken, e); } consume(); } protected void consume() { input.consume(); c = (char)input.LA(1); } public void emit(Token token) { tokens.add(token); } public Token _nextToken() { //System.out.println("nextToken: c="+(char)c+"@"+input.index()); while ( true ) { // lets us avoid recursion when skipping stuff startCharIndex = input.index(); startLine = input.getLine(); startCharPositionInLine = input.getCharPositionInLine(); if ( c==EOF ) return newToken(EOF_TYPE); Token t; if ( scanningInsideExpr ) t = inside(); else t = outside(); if ( t!=SKIP ) return t; } } protected Token outside() { if ( input.getCharPositionInLine()==0 && (c==' '||c=='\t') ) { while ( c==' ' || c=='\t' ) consume(); // scarf indent if ( c!=EOF ) return newToken(INDENT); return newToken(TEXT); } if ( c==delimiterStartChar ) { consume(); if ( c=='!' ) return COMMENT(); if ( c=='\\' ) return ESCAPE(); // <\\> <\uFFFF> <\n> etc... scanningInsideExpr = true; return newToken(LDELIM); } if ( c=='\r' ) { consume(); consume(); return newToken(NEWLINE); } // \r\n -> \n if ( c=='\n') { consume(); return newToken(NEWLINE); } if ( c=='}' && subtemplateDepth>0 ) { scanningInsideExpr = true; subtemplateDepth--; consume(); return newTokenFromPreviousChar(RCURLY); } return mTEXT(); } protected Token inside() { while ( true ) { switch ( c ) { case ' ': case '\t': case '\n': case '\r': consume(); return SKIP; case '.' : consume(); if ( input.LA(1)=='.' && input.LA(2)=='.' ) { consume(); match('.'); return newToken(ELLIPSIS); } return newToken(DOT); case ',' : consume(); return newToken(COMMA); case ':' : consume(); return newToken(COLON); case ';' : consume(); return newToken(SEMI); case '(' : consume(); return newToken(LPAREN); case ')' : consume(); return newToken(RPAREN); case '[' : consume(); return newToken(LBRACK); case ']' : consume(); return newToken(RBRACK); case '=' : consume(); return newToken(EQUALS); case '!' : consume(); return newToken(BANG); case '@' : consume(); if ( c=='e' && input.LA(2)=='n' && input.LA(3)=='d' ) { consume(); consume(); consume(); return newToken(REGION_END); } return newToken(AT); case '"' : return mSTRING(); case '&' : consume(); match('&'); return newToken(AND); // && case '|' : consume(); match('|'); return newToken(OR); // || case '{' : return subTemplate(); default: if ( c==delimiterStopChar ) { consume(); scanningInsideExpr =false; return newToken(RDELIM); } if ( isIDStartLetter(c) ) { Token id = mID(); String name = id.getText(); if ( name.equals("if") ) return newToken(IF); else if ( name.equals("endif") ) return newToken(ENDIF); else if ( name.equals("else") ) return newToken(ELSE); else if ( name.equals("elseif") ) return newToken(ELSEIF); else if ( name.equals("super") ) return newToken(SUPER); else if ( name.equals("true") ) return newToken(TRUE); else if ( name.equals("false") ) return newToken(FALSE); return id; } RecognitionException re = new NoViableAltException("",0,0,input); re.line = startLine; re.charPositionInLine = startCharPositionInLine; errMgr.lexerError(input.getSourceName(), "invalid character '"+str(c)+"'", templateToken, re); if (c==EOF) { return newToken(EOF_TYPE); } consume(); } } } Token subTemplate() { // look for "{ args ID (',' ID)* '|' ..." subtemplateDepth++; int m = input.mark(); int curlyStartChar = startCharIndex; int curlyLine = startLine; int curlyPos = startCharPositionInLine; List argTokens = new ArrayList(); consume(); Token curly = newTokenFromPreviousChar(LCURLY); WS(); argTokens.add( mID() ); WS(); while ( c==',' ) { consume(); argTokens.add( newTokenFromPreviousChar(COMMA) ); WS(); argTokens.add( mID() ); WS(); } WS(); if ( c=='|' ) { consume(); argTokens.add( newTokenFromPreviousChar(PIPE) ); if ( isWS(c) ) consume(); // ignore a single whitespace after | //System.out.println("matched args: "+argTokens); for (Token t : argTokens) emit(t); input.release(m); scanningInsideExpr = false; startCharIndex = curlyStartChar; // reset state startLine = curlyLine; startCharPositionInLine = curlyPos; return curly; } input.rewind(m); startCharIndex = curlyStartChar; // reset state startLine = curlyLine; startCharPositionInLine = curlyPos; consume(); scanningInsideExpr = false; return curly; } Token ESCAPE() { startCharIndex = input.index(); startCharPositionInLine = input.getCharPositionInLine(); consume(); // kill \\ if ( c=='u') return UNICODE(); String text = null; switch ( c ) { case '\\' : LINEBREAK(); return SKIP; case 'n' : text = "\n"; break; case 't' : text = "\t"; break; case ' ' : text = " "; break; default : NoViableAltException e = new NoViableAltException("",0,0,input); errMgr.lexerError(input.getSourceName(), "invalid escaped char: '"+str(c)+"'", templateToken, e); consume(); match(delimiterStopChar); return SKIP; } consume(); Token t = newToken(TEXT, text, input.getCharPositionInLine()-2); match(delimiterStopChar); return t; } Token UNICODE() { consume(); char[] chars = new char[4]; if ( !isUnicodeLetter(c) ) { NoViableAltException e = new NoViableAltException("",0,0,input); errMgr.lexerError(input.getSourceName(), "invalid unicode char: '"+str(c)+"'", templateToken, e); } chars[0] = c; consume(); if ( !isUnicodeLetter(c) ) { NoViableAltException e = new NoViableAltException("",0,0,input); errMgr.lexerError(input.getSourceName(), "invalid unicode char: '"+str(c)+"'", templateToken, e); } chars[1] = c; consume(); if ( !isUnicodeLetter(c) ) { NoViableAltException e = new NoViableAltException("",0,0,input); errMgr.lexerError(input.getSourceName(), "invalid unicode char: '"+str(c)+"'", templateToken, e); } chars[2] = c; consume(); if ( !isUnicodeLetter(c) ) { NoViableAltException e = new NoViableAltException("",0,0,input); errMgr.lexerError(input.getSourceName(), "invalid unicode char: '"+str(c)+"'", templateToken, e); } chars[3] = c; // ESCAPE kills > char uc = (char)Integer.parseInt(new String(chars), 16); Token t = newToken(TEXT, String.valueOf(uc), input.getCharPositionInLine()-6); consume(); match(delimiterStopChar); return t; } Token mTEXT() { boolean modifiedText = false; StringBuilder buf = new StringBuilder(); while ( c != EOF && c != delimiterStartChar ) { if ( c=='\r' || c=='\n') break; if ( c=='}' && subtemplateDepth>0 ) break; if ( c=='\\' ) { if ( input.LA(2)=='\\' ) { // convert \\ to \ consume(); consume(); buf.append('\\'); modifiedText = true; continue; } if ( input.LA(2)==delimiterStartChar || input.LA(2)=='}' ) { modifiedText = true; consume(); // toss out \ char buf.append(c); consume(); } else { buf.append(c); consume(); } continue; } buf.append(c); consume(); } if ( modifiedText ) return newToken(TEXT, buf.toString()); else return newToken(TEXT); } /**
	 *  ID  : ('a'..'z'|'A'..'Z'|'_'|'/')
	 *        ('a'..'z'|'A'..'Z'|'0'..'9'|'_'|'/')*
	 *      ;
	 *  
*/ Token mID() { // called from subTemplate; so keep resetting position during speculation startCharIndex = input.index(); startLine = input.getLine(); startCharPositionInLine = input.getCharPositionInLine(); consume(); while ( isIDLetter(c) ) { consume(); } return newToken(ID); } /**
	 *  STRING : '"'
	 *           (   '\\' '"'
	 *           |   '\\' ~'"'
	 *           |   ~('\\'|'"')
	 *           )*
	 *           '"'
	 *         ;
	 * 
*/ Token mSTRING() { //{setText(getText().substring(1, getText().length()-1));} boolean sawEscape = false; StringBuilder buf = new StringBuilder(); buf.append(c); consume(); while ( c != '"' ) { if ( c=='\\' ) { sawEscape = true; consume(); switch ( c ) { case 'n' : buf.append('\n'); break; case 'r' : buf.append('\r'); break; case 't' : buf.append('\t'); break; default : buf.append(c); break; } consume(); continue; } buf.append(c); consume(); if ( c==EOF ) { RecognitionException re = new MismatchedTokenException((int)'"', input); re.line = input.getLine(); re.charPositionInLine = input.getCharPositionInLine(); errMgr.lexerError(input.getSourceName(), "EOF in string", templateToken, re); break; } } buf.append(c); consume(); if ( sawEscape ) return newToken(STRING, buf.toString()); else return newToken(STRING); } void WS() { while ( c==' ' || c=='\t' || c=='\n' || c=='\r' ) consume(); } Token COMMENT() { match('!'); while ( !(c=='!' && input.LA(2)==delimiterStopChar) ) { if (c==EOF) { RecognitionException re = new MismatchedTokenException((int)'!', input); re.line = input.getLine(); re.charPositionInLine = input.getCharPositionInLine(); errMgr.lexerError(input.getSourceName(), "Nonterminated comment starting at " + startLine+":"+startCharPositionInLine+": '!"+ delimiterStopChar+"' missing", templateToken, re); break; } consume(); } consume(); consume(); // grab !> return newToken(COMMENT); } void LINEBREAK() { match('\\'); // only kill 2nd \ as ESCAPE() kills first one match(delimiterStopChar); while ( c==' ' || c=='\t' ) consume(); // scarf WS after <\\> if ( c==EOF ) { RecognitionException re = new RecognitionException(input); re.line = input.getLine(); re.charPositionInLine = input.getCharPositionInLine(); errMgr.lexerError(input.getSourceName(), "Missing newline after newline escape <\\\\>", templateToken, re); return; } if ( c=='\r' ) consume(); match('\n'); while ( c==' ' || c=='\t' ) consume(); // scarf any indent } public static boolean isIDStartLetter(char c) { return isIDLetter(c); } public static boolean isIDLetter(char c) { return c>='a'&&c<='z' || c>='A'&&c<='Z' || c>='0'&&c<='9' || c=='_' || c=='/'; } public static boolean isWS(char c) { return c==' ' || c=='\t' || c=='\n' || c=='\r'; } public static boolean isUnicodeLetter(char c) { return c>='a'&&c<='f' || c>='A'&&c<='F' || c>='0'&&c<='9'; } public Token newToken(int ttype) { STToken t = new STToken(input, ttype, startCharIndex, input.index()-1); t.setLine(startLine); t.setCharPositionInLine(startCharPositionInLine); return t; } public Token newTokenFromPreviousChar(int ttype) { STToken t = new STToken(input, ttype, input.index()-1, input.index()-1); t.setLine(input.getLine()); t.setCharPositionInLine(input.getCharPositionInLine()-1); return t; } public Token newToken(int ttype, String text, int pos) { STToken t = new STToken(ttype, text); t.setStartIndex(startCharIndex); t.setStopIndex(input.index()-1); t.setLine(input.getLine()); t.setCharPositionInLine(pos); return t; } public Token newToken(int ttype, String text) { STToken t = new STToken(ttype, text); t.setStartIndex(startCharIndex); t.setStopIndex(input.index()-1); t.setLine(startLine); t.setCharPositionInLine(startCharPositionInLine); return t; } // public String getErrorHeader() { // return startLine+":"+startCharPositionInLine; // } // @Override public String getSourceName() { return "no idea"; } public static String str(int c) { if ( c==EOF ) return ""; return String.valueOf((char)c); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/compiler/STLexer.tokens000066400000000000000000000007401231426731300262120ustar00rootroot00000000000000RBRACK=17 LBRACK=16 ELSE=5 ELLIPSIS=11 LCURLY=20 BANG=10 EQUALS=12 TEXT=22 ID=25 SEMI=9 LPAREN=14 IF=4 ELSEIF=6 COLON=13 RPAREN=15 WS=27 COMMA=18 RCURLY=21 ENDIF=7 RDELIM=24 SUPER=8 DOT=19 LDELIM=23 STRING=26 PIPE=28 OR=29 AND=30 INDENT=31 NEWLINE=32 AT=33 END=34 TRUE=35 FALSE=36 COMMENT=37 '...'=11 'super'=8 '|'=28 '!'=10 '}'=21 'else'=5 'if'=4 '{'=20 '...'=11 'elseif'=6 ';'=9 '='=12 ':'=13 '('=14 '['=16 ','=18 '.'=19 'endif'=7 ')'=15 ']'=17 '||'=29 '&&'=30 '@'=33 '@end'=34 stringtemplate4-4.0.8/src/org/stringtemplate/v4/compiler/STParser.g000066400000000000000000000170301231426731300253120ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** Build an AST from a single StringTemplate template */ parser grammar STParser; options { language=Java; tokenVocab=STLexer; TokenLabelType=CommonToken; output=AST; ASTLabelType=CommonTree; } tokens { EXPR; OPTIONS; PROP; PROP_IND; INCLUDE; INCLUDE_IND; EXEC_FUNC; INCLUDE_SUPER; INCLUDE_SUPER_REGION; INCLUDE_REGION; TO_STR; LIST; MAP; ZIP; SUBTEMPLATE; ARGS; ELEMENTS; REGION; NULL; INDENTED_EXPR; } @header { package org.stringtemplate.v4.compiler; import org.stringtemplate.v4.misc.ErrorManager; import org.stringtemplate.v4.misc.ErrorType; } @members { ErrorManager errMgr; Token templateToken; public STParser(TokenStream input, ErrorManager errMgr, Token templateToken) { this(input); this.errMgr = errMgr; this.templateToken = templateToken; } @Override protected Object recoverFromMismatchedToken(IntStream input, int ttype, BitSet follow) throws RecognitionException { throw new MismatchedTokenException(ttype, input); } } @rulecatch { catch (RecognitionException re) { throw re; } } templateAndEOF : template EOF -> template? ; template : element* ; element : {input.LT(1).getCharPositionInLine()==0}? INDENT? COMMENT NEWLINE -> // throw away | INDENT singleElement -> ^(INDENTED_EXPR INDENT singleElement?) // singleElement is optional to handle error returning nil | singleElement | compoundElement ; singleElement : exprTag | TEXT | NEWLINE | COMMENT! // throw away ; compoundElement : ifstat | region ; exprTag : LDELIM expr ( ';' exprOptions )? RDELIM -> ^(EXPR[$LDELIM,"EXPR"] expr exprOptions?) ; region @init {Token indent=null;} : i=INDENT? x=LDELIM '@' ID RDELIM {if (input.LA(1)!=NEWLINE) indent=$i;} template INDENT? LDELIM '@end' RDELIM // kill \n for <@end> on line by itself if multi-line embedded region ({$region.start.getLine()!=input.LT(1).getLine()}?=> NEWLINE)? -> {indent!=null}? ^(INDENTED_EXPR $i ^(REGION[$x] ID template?)) -> ^(REGION[$x] ID template?) ; subtemplate : lc='{' (ids+= ID ( ',' ids+= ID )* '|' )? template INDENT? '}' // ignore final INDENT before } as it's not part of outer indent -> ^(SUBTEMPLATE[$lc,"SUBTEMPLATE"] ^(ARGS $ids)* template?) ; ifstat @init {Token indent=null;} : i=INDENT? LDELIM 'if' '(' c1=conditional ')' RDELIM {if (input.LA(1)!=NEWLINE) indent=$i;} t1=template ( INDENT? LDELIM 'elseif' '(' c2+=conditional ')' RDELIM t2+=template )* ( INDENT? LDELIM 'else' RDELIM t3=template )? INDENT? endif= LDELIM 'endif' RDELIM // kill \n for on line by itself if multi-line IF ({$ifstat.start.getLine()!=input.LT(1).getLine()}?=> NEWLINE)? -> {indent!=null}? ^(INDENTED_EXPR $i ^('if' $c1 $t1? ^('elseif' $c2 $t2)* ^('else' $t3?)?)) -> ^('if' $c1 $t1? ^('elseif' $c2 $t2)* ^('else' $t3?)?) ; conditional scope { boolean inside; } : andConditional ( '||'^ andConditional )* ; andConditional : notConditional ( '&&'^ notConditional )* ; notConditional : '!'^ notConditional | memberExpr ; notConditionalExpr : (ID->ID) ( p='.' prop=ID -> ^(PROP[$p,"PROP"] $notConditionalExpr $prop) | p='.' '(' mapExpr ')' -> ^(PROP_IND[$p,"PROP_IND"] $notConditionalExpr mapExpr) )* ; exprOptions : option ( ',' option )* -> ^(OPTIONS option*) ; option @init { String id = input.LT(1).getText(); String defVal = Compiler.defaultOptionValues.get(id); boolean validOption = Compiler.supportedOptions.get(id)!=null; } : ID { if ( !validOption ) { errMgr.compileTimeError(ErrorType.NO_SUCH_OPTION, templateToken, $ID, $ID.text); } } ( '=' exprNoComma -> {validOption}? ^('=' ID exprNoComma) -> | { if ( defVal==null ) { errMgr.compileTimeError(ErrorType.NO_DEFAULT_VALUE, templateToken, $ID); } } -> {validOption&&defVal!=null}? ^(EQUALS["="] ID STRING[$ID,'"'+defVal+'"']) -> ) ; exprNoComma : memberExpr ( ':' mapTemplateRef -> ^(MAP memberExpr mapTemplateRef) | -> memberExpr ) ; expr : mapExpr ; // more complicated than necessary to avoid backtracking, which ruins // error handling mapExpr : memberExpr ( (c=',' memberExpr)+ col=':' mapTemplateRef -> ^(ZIP[$col] ^(ELEMENTS memberExpr+) mapTemplateRef) | -> memberExpr ) ( {if ($x!=null) $x.clear();} // don't keep queueing x; new list for each iteration col=':' x+=mapTemplateRef ({$c==null}?=> ',' x+=mapTemplateRef )* -> ^(MAP[$col] $mapExpr $x+) )* ; /** expr:template(args) apply template to expr expr:{arg | ...} apply subtemplate to expr expr:(e)(args) convert e to a string template name and apply to expr */ mapTemplateRef : ID '(' args ')' -> ^(INCLUDE ID args?) | subtemplate | lp='(' mapExpr rp=')' '(' argExprList? ')' -> ^(INCLUDE_IND mapExpr argExprList?) ; memberExpr : (includeExpr->includeExpr) ( p='.' ID -> ^(PROP[$p,"PROP"] $memberExpr ID) | p='.' '(' mapExpr ')' -> ^(PROP_IND[$p,"PROP_IND"] $memberExpr mapExpr) )* ; includeExpr options {k=2;} // prevent full LL(*), which fails, falling back on k=1; need k=2 : {Compiler.funcs.containsKey(input.LT(1).getText())}? // predefined function ID '(' expr? ')' -> ^(EXEC_FUNC ID expr?) | 'super' '.' ID '(' args ')' -> ^(INCLUDE_SUPER ID args?) | ID '(' args ')' -> ^(INCLUDE ID args?) | '@' 'super' '.' ID '(' rp=')' -> ^(INCLUDE_SUPER_REGION ID) | '@' ID '(' rp=')' -> ^(INCLUDE_REGION ID) | primary ; primary : ID | STRING | TRUE | FALSE | subtemplate | list | {$conditional.size()>0}?=> '('! conditional ')'! | {$conditional.size()==0}?=> lp='(' expr ')' ( '(' argExprList? ')' -> ^(INCLUDE_IND[$lp] expr argExprList?) | -> ^(TO_STR[$lp] expr) ) ; args: argExprList | namedArg ( ',' namedArg )* (',' '...')? -> namedArg+ '...'? | '...' | ; argExprList : arg ( ',' arg )* -> arg+ ; arg : exprNoComma ; namedArg : ID '=' arg -> ^('=' ID arg) ; list: {input.LA(2)==RBRACK}? // hush warning; [] special case lb='[' ']' -> LIST[$lb] | lb='[' listElement ( ',' listElement )* ']' -> ^(LIST[$lb] listElement*) ; listElement : exprNoComma | -> NULL ; stringtemplate4-4.0.8/src/org/stringtemplate/v4/compiler/StringTable.java000066400000000000000000000042141231426731300265200ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.compiler; import java.util.LinkedHashMap; /** A unique set of strings where we can get a string's index. * We can also get them back out in original order. */ public class StringTable { protected LinkedHashMap table = new LinkedHashMap(); protected int i = -1; public int add(String s) { Integer I = table.get(s); if ( I!=null ) return I; i++; table.put(s, i); return i; } public String[] toArray() { String[] a = new String[table.size()]; int i = 0; for (String s : table.keySet()) a[i++] = s; return a; } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/debug/000077500000000000000000000000001231426731300227125ustar00rootroot00000000000000stringtemplate4-4.0.8/src/org/stringtemplate/v4/debug/AddAttributeEvent.java000066400000000000000000000037461231426731300271450ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.debug; public class AddAttributeEvent extends ConstructionEvent { String name; /** Reserved for future use. */ Object value; public AddAttributeEvent(String name, Object value) { this.name = name; this.value = value; } @Override public String toString() { return "addEvent{" + ", name='" + name + '\'' + ", value=" + value + ", location=" + getFileName()+":"+getLine()+ '}'; } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/debug/ConstructionEvent.java000066400000000000000000000041531231426731300272540ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.debug; /** An event that happens when building ST trees, adding attributes etc... */ public class ConstructionEvent { public Throwable stack; public ConstructionEvent() { stack = new Throwable(); } public String getFileName() { return getSTEntryPoint().getFileName(); } public int getLine() { return getSTEntryPoint().getLineNumber(); } public StackTraceElement getSTEntryPoint() { StackTraceElement[] trace = stack.getStackTrace(); for (StackTraceElement e : trace) { String name = e.toString(); if ( !name.startsWith("org.stringtemplate.v4") ) return e; } return trace[0]; } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/debug/EvalExprEvent.java000066400000000000000000000047261231426731300263160ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.debug; import org.stringtemplate.v4.InstanceScope; public class EvalExprEvent extends InterpEvent { /** Index of first char in template. */ public final int exprStartChar; /** Index of last char in template (inclusive). */ public final int exprStopChar; public final String expr; public EvalExprEvent(InstanceScope scope, int start, int stop, int exprStartChar, int exprStopChar) { super(scope, start, stop); this.exprStartChar = exprStartChar; this.exprStopChar = exprStopChar; if ( exprStartChar >=0 && exprStopChar >=0 ) { expr = scope.st.impl.template.substring(exprStartChar, exprStopChar +1); } else { expr = ""; } } @Override public String toString() { return getClass().getSimpleName()+"{" + "self=" + scope.st + ", expr='" + expr + '\'' + ", exprStartChar=" + exprStartChar + ", exprStopChar=" + exprStopChar + ", start=" + outputStartChar + ", stop=" + outputStopChar + '}'; } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/debug/EvalTemplateEvent.java000066400000000000000000000034051231426731300271440ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.debug; import org.stringtemplate.v4.InstanceScope; public class EvalTemplateEvent extends InterpEvent { public EvalTemplateEvent(InstanceScope scope, int exprStartChar, int exprStopChar) { super(scope, exprStartChar, exprStopChar); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/debug/IndentEvent.java000066400000000000000000000034221231426731300260010ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.debug; import org.stringtemplate.v4.InstanceScope; public class IndentEvent extends EvalExprEvent { public IndentEvent(InstanceScope scope, int start, int stop, int exprStartChar, int exprStopChar) { super(scope, start, stop, exprStartChar, exprStopChar); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/debug/InterpEvent.java000066400000000000000000000043661231426731300260310ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.debug; import org.stringtemplate.v4.InstanceScope; public class InterpEvent { public InstanceScope scope; /** Index of first char into output stream. */ public final int outputStartChar; /** Index of last char into output stream (inclusive). */ public final int outputStopChar; public InterpEvent(InstanceScope scope, int outputStartChar, int outputStopChar) { this.scope = scope; this.outputStartChar = outputStartChar; this.outputStopChar = outputStopChar; } @Override public String toString() { return getClass().getSimpleName()+"{" + "self=" + scope.st + ", start=" + outputStartChar + ", stop=" + outputStopChar + '}'; } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/gui/000077500000000000000000000000001231426731300224105ustar00rootroot00000000000000stringtemplate4-4.0.8/src/org/stringtemplate/v4/gui/JTreeASTModel.java000066400000000000000000000056401231426731300256220ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.gui; import org.antlr.runtime.tree.CommonTreeAdaptor; import org.antlr.runtime.tree.TreeAdaptor; import javax.swing.event.TreeModelListener; import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; // TODO: copied from ANTLR v4; rm when upgraded to v4 public class JTreeASTModel implements TreeModel { TreeAdaptor adaptor; Object root; public JTreeASTModel(TreeAdaptor adaptor, Object root) { this.adaptor = adaptor; this.root = root; } public JTreeASTModel(Object root) { this.adaptor = new CommonTreeAdaptor(); this.root = root; } @Override public int getChildCount(Object parent) { return adaptor.getChildCount(parent); } @Override public int getIndexOfChild(Object parent, Object child){ if ( parent==null ) return -1; return adaptor.getChildIndex(child); } @Override public Object getChild(Object parent, int index){ return adaptor.getChild(parent, index); } @Override public boolean isLeaf(Object node) { return getChildCount(node)==0; } @Override public Object getRoot() { return root; } @Override public void valueForPathChanged(TreePath treePath, Object o) { } @Override public void addTreeModelListener(TreeModelListener treeModelListener) { } @Override public void removeTreeModelListener(TreeModelListener treeModelListener) { } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/gui/JTreeSTModel.java000066400000000000000000000100241231426731300255110ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.gui; import org.stringtemplate.v4.Interpreter; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.StringRenderer; import org.stringtemplate.v4.debug.EvalTemplateEvent; import javax.swing.event.TreeModelListener; import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; public class JTreeSTModel implements TreeModel { public Interpreter interp; public Wrapper root; public static class Wrapper { EvalTemplateEvent event; public Wrapper(EvalTemplateEvent event) { this.event = event; } @Override public int hashCode() { return event.hashCode(); } @Override public boolean equals(Object o) { //System.out.println(event+"=="+((Wrapper)o).event+" is "+(this.event == ((Wrapper)o).event)); return this.event == ((Wrapper)o).event; } @Override public String toString() { ST st = event.scope.st; if ( st.isAnonSubtemplate() ) return "{...}"; if ( st.debugState!=null && st.debugState.newSTEvent!=null ) { String label = st.toString()+" @ "+st.debugState.newSTEvent.getFileName()+":"+ st.debugState.newSTEvent.getLine(); return "" + StringRenderer.escapeHTML(label) + ""; } else { return st.toString(); } } } public JTreeSTModel(Interpreter interp, EvalTemplateEvent root) { this.interp = interp; this.root = new Wrapper(root); } @Override public Object getChild(Object parent, int index) { EvalTemplateEvent e = ((Wrapper)parent).event; return new Wrapper(e.scope.childEvalTemplateEvents.get(index)); } @Override public int getChildCount(Object parent) { EvalTemplateEvent e = ((Wrapper)parent).event; return e.scope.childEvalTemplateEvents.size(); } @Override public int getIndexOfChild(Object parent, Object child) { EvalTemplateEvent p = ((Wrapper)parent).event; EvalTemplateEvent c = ((Wrapper)parent).event; int i = 0; for (EvalTemplateEvent e : p.scope.childEvalTemplateEvents) { if ( e.scope.st == c.scope.st ) { // System.out.println(i); // System.out.println("found "+e.self+" as child of "+parentST); return i; } i++; } return -1; } @Override public boolean isLeaf(Object node) { return getChildCount(node) == 0; } @Override public Object getRoot() { return root; } @Override public void valueForPathChanged(TreePath treePath, Object o) { } @Override public void addTreeModelListener(TreeModelListener treeModelListener) { } @Override public void removeTreeModelListener(TreeModelListener treeModelListener) { } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/gui/JTreeScopeStackModel.java000066400000000000000000000114701231426731300272300ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.gui; import org.antlr.runtime.tree.CommonTree; import org.stringtemplate.v4.InstanceScope; import org.stringtemplate.v4.Interpreter; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.StringRenderer; import org.stringtemplate.v4.debug.AddAttributeEvent; import javax.swing.event.TreeModelListener; import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; /** From a scope, get stack of enclosing scopes in order from root down * to scope. Then show each scope's (ST's) attributes as children. */ public class JTreeScopeStackModel implements TreeModel { CommonTree root; public static class StringTree extends CommonTree { String text; public StringTree(String text) {this.text = text;} @Override public boolean isNil() { return text==null; } @Override public String toString() { if ( !isNil() ) return text.toString(); return "nil"; } } public JTreeScopeStackModel(InstanceScope scope) { root = new StringTree("Scope stack:"); Set names = new HashSet(); List stack = Interpreter.getScopeStack(scope, false); for (InstanceScope s : stack) { StringTree templateNode = new StringTree(s.st.getName()); root.insertChild(0, templateNode); addAttributeDescriptions(s.st, templateNode, names); } //System.out.println(root.toStringTree()); } public void addAttributeDescriptions(ST st, StringTree node, Set names) { Map attrs = st.getAttributes(); if ( attrs==null ) return; for (String a : attrs.keySet()) { String descr = null; if ( st.debugState!=null && st.debugState.addAttrEvents!=null ) { List events = st.debugState.addAttrEvents.get(a); StringBuilder locations = new StringBuilder(); int i = 0; if ( events!=null ) { for (AddAttributeEvent ae : events) { if ( i>0 ) locations.append(", "); locations.append(ae.getFileName()+":"+ae.getLine()); i++; } } if ( locations.length()>0 ) { descr = a+" = "+attrs.get(a)+" @ "+locations.toString(); } else { descr = a + " = " +attrs.get(a); } } else { descr = a + " = " +attrs.get(a); } if (!names.add(a)) { StringBuilder builder = new StringBuilder(); builder.append(""); builder.append(StringRenderer.escapeHTML(descr)); builder.append(""); descr = builder.toString(); } node.addChild( new StringTree(descr) ); } } @Override public Object getRoot() { return root; } @Override public Object getChild(Object parent, int i) { StringTree t = (StringTree)parent; return t.getChild(i); } @Override public int getChildCount(Object parent) { StringTree t = (StringTree)parent; return t.getChildCount(); } @Override public boolean isLeaf(Object node) { return getChildCount(node) == 0; } @Override public int getIndexOfChild(Object parent, Object child) { StringTree c = (StringTree)child; return c.getChildIndex(); } @Override public void valueForPathChanged(TreePath treePath, Object o) { } @Override public void addTreeModelListener(TreeModelListener treeModelListener) { } @Override public void removeTreeModelListener(TreeModelListener treeModelListener) { } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/gui/STViewFrame.java000066400000000000000000000153141231426731300254130ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Created by JFormDesigner on Sun Nov 29 12:38:59 PST 2009 */ package org.stringtemplate.v4.gui; import javax.swing.*; import java.awt.*; /** * @author Terence Parr */ public class STViewFrame extends JFrame { public STViewFrame() { initComponents(); } private void initComponents() { // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents // Generated using JFormDesigner non-commercial license toolBar1 = new JToolBar(); treeContentSplitPane = new JSplitPane(); treeAttributesSplitPane = new JSplitPane(); treeScrollPane = new JScrollPane(); tree = new JTree(); attributeScrollPane = new JScrollPane(); attributes = new JTree(); outputTemplateSplitPane = new JSplitPane(); scrollPane7 = new JScrollPane(); output = new JTextPane(); templateBytecodeTraceTabPanel = new JTabbedPane(); panel1 = new JPanel(); scrollPane3 = new JScrollPane(); template = new JTextPane(); scrollPane2 = new JScrollPane(); ast = new JTree(); scrollPane15 = new JScrollPane(); bytecode = new JTextPane(); scrollPane1 = new JScrollPane(); trace = new JTextPane(); errorScrollPane = new JScrollPane(); errorList = new JList(); //======== this ======== Container contentPane = getContentPane(); contentPane.setLayout(new GridBagLayout()); ((GridBagLayout)contentPane.getLayout()).columnWidths = new int[] {0, 0}; ((GridBagLayout)contentPane.getLayout()).rowHeights = new int[] {0, 0, 0, 0}; ((GridBagLayout)contentPane.getLayout()).columnWeights = new double[] {1.0, 1.0E-4}; ((GridBagLayout)contentPane.getLayout()).rowWeights = new double[] {0.0, 1.0, 0.0, 1.0E-4}; contentPane.add(toolBar1, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); //======== treeContentSplitPane ======== { treeContentSplitPane.setResizeWeight(0.25); //======== treeAttributesSplitPane ======== { treeAttributesSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT); treeAttributesSplitPane.setResizeWeight(0.7); //======== treeScrollPane ======== { treeScrollPane.setViewportView(tree); } treeAttributesSplitPane.setTopComponent(treeScrollPane); //======== attributeScrollPane ======== { attributeScrollPane.setViewportView(attributes); } treeAttributesSplitPane.setBottomComponent(attributeScrollPane); } treeContentSplitPane.setLeftComponent(treeAttributesSplitPane); //======== outputTemplateSplitPane ======== { outputTemplateSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT); outputTemplateSplitPane.setResizeWeight(0.7); //======== scrollPane7 ======== { scrollPane7.setViewportView(output); } outputTemplateSplitPane.setTopComponent(scrollPane7); //======== templateBytecodeTraceTabPanel ======== { //======== panel1 ======== { panel1.setLayout(new BoxLayout(panel1, BoxLayout.X_AXIS)); //======== scrollPane3 ======== { scrollPane3.setViewportView(template); } panel1.add(scrollPane3); //======== scrollPane2 ======== { scrollPane2.setViewportView(ast); } panel1.add(scrollPane2); } templateBytecodeTraceTabPanel.addTab("template", panel1); //======== scrollPane15 ======== { scrollPane15.setViewportView(bytecode); } templateBytecodeTraceTabPanel.addTab("bytecode", scrollPane15); //======== scrollPane1 ======== { scrollPane1.setViewportView(trace); } templateBytecodeTraceTabPanel.addTab("trace", scrollPane1); } outputTemplateSplitPane.setBottomComponent(templateBytecodeTraceTabPanel); } treeContentSplitPane.setRightComponent(outputTemplateSplitPane); } contentPane.add(treeContentSplitPane, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); //======== errorScrollPane ======== { errorScrollPane.setViewportView(errorList); } contentPane.add(errorScrollPane, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); pack(); setLocationRelativeTo(getOwner()); // JFormDesigner - End of component initialization //GEN-END:initComponents } // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables // Generated using JFormDesigner non-commercial license private JToolBar toolBar1; public JSplitPane treeContentSplitPane; public JSplitPane treeAttributesSplitPane; public JScrollPane treeScrollPane; protected JTree tree; protected JScrollPane attributeScrollPane; protected JTree attributes; public JSplitPane outputTemplateSplitPane; protected JScrollPane scrollPane7; public JTextPane output; public JTabbedPane templateBytecodeTraceTabPanel; private JPanel panel1; private JScrollPane scrollPane3; public JTextPane template; private JScrollPane scrollPane2; public JTree ast; protected JScrollPane scrollPane15; protected JTextPane bytecode; private JScrollPane scrollPane1; public JTextPane trace; public JScrollPane errorScrollPane; protected JList errorList; // JFormDesigner - End of variables declaration //GEN-END:variables } stringtemplate4-4.0.8/src/org/stringtemplate/v4/gui/STViewFrame.jfd000066400000000000000000000445611231426731300252430ustar00rootroot00000000000000 form/swing javax.swing.JFrame java.awt.GridBagLayout $columnSpecs 0:1.0 $rowSpecs 0, 0:1.0, 0 $alignTop true $alignLeft true $locationPolicy 0 $sizePolicy 0 JavaCodeGenerator.variableModifiers 4 javax.swing.JToolBar javax.swing.JToolBar toolBar1 com.jformdesigner.runtime.GridBagConstraintsEx javax.swing.JSplitPane javax.swing.JSplitPane resizeWeight 0.25 JavaCodeGenerator.variableModifiers 1 treeContentSplitPane javax.swing.JSplitPane javax.swing.JSplitPane orientation 0 resizeWeight 0.7 JavaCodeGenerator.variableModifiers 1 treeAttributesSplitPane javax.swing.JScrollPane javax.swing.JScrollPane JavaCodeGenerator.variableModifiers 1 treeScrollPane javax.swing.JTree tree JavaCodeGenerator.variableModifiers 4 java.lang.String value left javax.swing.JScrollPane javax.swing.JScrollPane JavaCodeGenerator.variableModifiers 4 attributeScrollPane javax.swing.JTree attributes JavaCodeGenerator.variableModifiers 4 java.lang.String value right java.lang.String value left javax.swing.JSplitPane javax.swing.JSplitPane orientation 0 resizeWeight 0.7 JavaCodeGenerator.variableModifiers 1 outputTemplateSplitPane javax.swing.JScrollPane javax.swing.JScrollPane JavaCodeGenerator.variableModifiers 4 scrollPane7 javax.swing.JTextPane output JavaCodeGenerator.variableModifiers 1 java.lang.String value left javax.swing.JTabbedPane javax.swing.JTabbedPane JavaCodeGenerator.variableModifiers 1 templateBytecodeTraceTabPanel javax.swing.JPanel javax.swing.BoxLayout panel1 javax.swing.JScrollPane javax.swing.JScrollPane scrollPane3 javax.swing.JTextPane template JavaCodeGenerator.variableModifiers 1 javax.swing.JScrollPane javax.swing.JScrollPane scrollPane2 javax.swing.JTree ast JavaCodeGenerator.variableModifiers 1 title template javax.swing.JScrollPane javax.swing.JScrollPane JavaCodeGenerator.variableModifiers 4 scrollPane15 javax.swing.JTextPane bytecode JavaCodeGenerator.variableModifiers 4 title bytecode javax.swing.JScrollPane javax.swing.JScrollPane scrollPane1 javax.swing.JTextPane trace JavaCodeGenerator.variableModifiers 1 title trace java.lang.String value right java.lang.String value right com.jformdesigner.runtime.GridBagConstraintsEx gridy 1 hAlign 5 vAlign 5 javax.swing.JScrollPane javax.swing.JScrollPane JavaCodeGenerator.variableModifiers 1 errorScrollPane javax.swing.JList errorList JavaCodeGenerator.variableModifiers 4 com.jformdesigner.runtime.GridBagConstraintsEx gridy 2 hAlign 5 vAlign 5 this location 35 25 size 870 675 stringtemplate4-4.0.8/src/org/stringtemplate/v4/gui/STViz.java000066400000000000000000000471651231426731300243070ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.gui; import org.antlr.runtime.CommonToken; import org.antlr.runtime.tree.CommonTree; import org.antlr.runtime.tree.CommonTreeAdaptor; import org.stringtemplate.v4.*; import org.stringtemplate.v4.debug.EvalExprEvent; import org.stringtemplate.v4.debug.EvalTemplateEvent; import org.stringtemplate.v4.debug.InterpEvent; import org.stringtemplate.v4.misc.*; import javax.swing.*; import javax.swing.border.Border; import javax.swing.event.*; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultHighlighter; import javax.swing.text.Highlighter; import javax.swing.text.JTextComponent; import javax.swing.tree.TreePath; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; public class STViz { protected static final String WINDOWS_LINE_ENDINGS = "WINDOWS_LINE_ENDINGS"; //public ST currentST; // current ST selected in template tree public EvalTemplateEvent root; public InterpEvent currentEvent; public InstanceScope currentScope; public List allEvents; public JTreeSTModel tmodel; public ErrorManager errMgr; public Interpreter interp; public String output; public List trace; public List errors; public STViewFrame viewFrame; private final AtomicInteger updateDepth = new AtomicInteger(); public STViz(ErrorManager errMgr, EvalTemplateEvent root, String output, Interpreter interp, List trace, List errors) { this.errMgr = errMgr; this.currentEvent = root; this.currentScope = root.scope; this.output = output; this.interp = interp; this.allEvents = interp.getEvents(); this.trace = trace; this.errors = errors; } public void open() { viewFrame = new STViewFrame(); updateStack(currentScope, viewFrame); updateAttributes(currentScope, viewFrame); List events = currentScope.events; tmodel = new JTreeSTModel(interp, (EvalTemplateEvent)events.get(events.size()-1)); viewFrame.tree.setModel(tmodel); viewFrame.tree.addTreeSelectionListener( new TreeSelectionListener() { @Override public void valueChanged(TreeSelectionEvent treeSelectionEvent) { int depth = updateDepth.incrementAndGet(); try { if (depth != 1) { return; } currentEvent = ((JTreeSTModel.Wrapper)viewFrame.tree.getLastSelectedPathComponent()).event; currentScope = currentEvent.scope; updateCurrentST(viewFrame); } finally { updateDepth.decrementAndGet(); } } } ); JTreeASTModel astModel = new JTreeASTModel(new CommonTreeAdaptor(), currentScope.st.impl.ast); viewFrame.ast.setModel(astModel); viewFrame.ast.addTreeSelectionListener( new TreeSelectionListener() { @Override public void valueChanged(TreeSelectionEvent treeSelectionEvent) { int depth = updateDepth.incrementAndGet(); try { if (depth != 1) { return; } TreePath path = treeSelectionEvent.getNewLeadSelectionPath(); if ( path==null ) return; CommonTree node = (CommonTree)treeSelectionEvent.getNewLeadSelectionPath().getLastPathComponent(); //System.out.println("select AST: "+node); CommonToken a = (CommonToken)currentScope.st.impl.tokens.get(node.getTokenStartIndex()); CommonToken b = (CommonToken)currentScope.st.impl.tokens.get(node.getTokenStopIndex()); highlight(viewFrame.template, a.getStartIndex(), b.getStopIndex()); } finally { updateDepth.decrementAndGet(); } } } ); // Track selection of attr but do nothing for now // viewFrame.attributes.addListSelectionListener( // new ListSelectionListener() { // public void valueChanged(ListSelectionEvent e) { // int minIndex = viewFrame.attributes.getMinSelectionIndex(); // int maxIndex = viewFrame.attributes.getMaxSelectionIndex(); // for (int i = minIndex; i <= maxIndex; i++) { // if (viewFrame.attributes.isSelectedIndex(i)) { // //System.out.println("index="+i); // } // } // } // } // ); CaretListener caretListenerLabel = new CaretListener() { @Override public void caretUpdate(CaretEvent e) { int depth = updateDepth.incrementAndGet(); try { if (depth != 1) { return; } int dot = toEventPosition((JTextComponent)e.getSource(), e.getDot()); currentEvent = findEventAtOutputLocation(allEvents, dot); if ( currentEvent==null ) currentScope = tmodel.root.event.scope; else currentScope = currentEvent.scope; // update tree view of template hierarchy // compute path from root to currentST, create TreePath for tree widget List stack = Interpreter.getEvalTemplateEventStack(currentScope, true); //System.out.println("\nselect path="+stack); Object[] path = new Object[stack.size()]; int j = 0; for (EvalTemplateEvent s : stack) { path[j++] = new JTreeSTModel.Wrapper(s); } TreePath p = new TreePath(path); viewFrame.tree.setSelectionPath(p); viewFrame.tree.scrollPathToVisible(p); updateCurrentST(viewFrame); } finally { updateDepth.decrementAndGet(); } } }; viewFrame.output.addCaretListener(caretListenerLabel); // ADD ERRORS if ( errors==null || errors.size()==0 ) { viewFrame.errorScrollPane.setVisible(false); // don't show unless errors } else { final DefaultListModel errorListModel = new DefaultListModel(); for (STMessage msg : errors) { errorListModel.addElement(msg); } viewFrame.errorList.setModel(errorListModel); } viewFrame.errorList.addListSelectionListener( new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { int depth = updateDepth.incrementAndGet(); try { if (depth != 1) { return; } int minIndex = viewFrame.errorList.getMinSelectionIndex(); int maxIndex = viewFrame.errorList.getMaxSelectionIndex(); int i = minIndex; while ( i <= maxIndex ) { if (viewFrame.errorList.isSelectedIndex(i)) break; i++; } ListModel model = viewFrame.errorList.getModel(); STMessage msg = (STMessage)model.getElementAt(i); if ( msg instanceof STRuntimeMessage ) { STRuntimeMessage rmsg = (STRuntimeMessage)msg; Interval I = rmsg.self.impl.sourceMap[rmsg.ip]; currentEvent = null; currentScope = ((STRuntimeMessage) msg).scope; updateCurrentST(viewFrame); if ( I!=null ) { // highlight template highlight(viewFrame.template, I.a, I.b); } } } finally { updateDepth.decrementAndGet(); } } } ); Border empty = BorderFactory.createEmptyBorder(); viewFrame.treeContentSplitPane.setBorder(empty); viewFrame.outputTemplateSplitPane.setBorder(empty); viewFrame.templateBytecodeTraceTabPanel.setBorder(empty); viewFrame.treeAttributesSplitPane.setBorder(empty); viewFrame.treeContentSplitPane.setOneTouchExpandable(true); viewFrame.outputTemplateSplitPane.setOneTouchExpandable(true); viewFrame.treeContentSplitPane.setDividerSize(10); viewFrame.outputTemplateSplitPane.setDividerSize(8); viewFrame.treeContentSplitPane.setContinuousLayout(true); viewFrame.treeAttributesSplitPane.setContinuousLayout(true); viewFrame.outputTemplateSplitPane.setContinuousLayout(true); viewFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); viewFrame.pack(); viewFrame.setSize(900, 700); setText(viewFrame.output, output); setText(viewFrame.template, currentScope.st.impl.template); setText(viewFrame.bytecode, currentScope.st.impl.disasm()); setText(viewFrame.trace, Misc.join(trace.iterator(), "\n")); viewFrame.setVisible(true); } public void waitForClose() throws InterruptedException { final Object lock = new Object(); Thread t = new Thread() { @Override public void run() { synchronized (lock) { while (viewFrame.isVisible()) { try { lock.wait(); } catch (InterruptedException e) { } } } } }; t.start(); viewFrame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent arg0) { synchronized (lock) { viewFrame.setVisible(false); lock.notify(); } } }); t.join(); } private void updateCurrentST(STViewFrame m) { // System.out.println("updateCurrentST(): currentScope.st="+currentScope.st); // update all views according to currentScope.st updateStack(currentScope, m); // STACK updateAttributes(currentScope, m); // ATTRIBUTES setText(m.bytecode, currentScope.st.impl.disasm()); // BYTECODE DIS. setText(m.template, currentScope.st.impl.template); // TEMPLATE SRC JTreeASTModel astModel = new JTreeASTModel(new CommonTreeAdaptor(), currentScope.st.impl.ast); viewFrame.ast.setModel(astModel); // highlight output text and, if {...} subtemplate, region in ST src // get last event for currentScope.st; it's the event that captures ST eval if (currentEvent instanceof EvalExprEvent) { EvalExprEvent exprEvent = (EvalExprEvent)currentEvent; highlight(m.output, exprEvent.outputStartChar, exprEvent.outputStopChar); highlight(m.template, exprEvent.exprStartChar, exprEvent.exprStopChar); } else { EvalTemplateEvent templateEvent; if (currentEvent instanceof EvalTemplateEvent) { templateEvent = (EvalTemplateEvent)currentEvent; } else { List events = currentScope.events; templateEvent = (EvalTemplateEvent)events.get(events.size() - 1); } if (templateEvent != null) { highlight(m.output, templateEvent.outputStartChar, templateEvent.outputStopChar); } if ( currentScope.st.isAnonSubtemplate() ) { Interval r = currentScope.st.impl.getTemplateRange(); //System.out.println("currentScope.st src range="+r); //m.template.moveCaretPosition(r.a); highlight(m.template, r.a, r.b); } } } protected void setText(JEditorPane component, String text) { List windowsLineEndingsList = new ArrayList(); for (int i = 0; i < text.length(); i += 2) { i = text.indexOf("\r\n", i); if (i < 0) { break; } windowsLineEndingsList.add(i); } int[] windowsLineEndings = new int[windowsLineEndingsList.size()]; for (int i = 0; i < windowsLineEndingsList.size(); i++) { windowsLineEndings[i] = windowsLineEndingsList.get(i); } component.setText(text); component.getDocument().putProperty(WINDOWS_LINE_ENDINGS, windowsLineEndings); } protected int toComponentPosition(JTextComponent component, int position) { int[] windowsLineEndings = (int[])component.getDocument().getProperty(WINDOWS_LINE_ENDINGS); if (windowsLineEndings == null || windowsLineEndings.length == 0) { return position; } int index = Arrays.binarySearch(windowsLineEndings, position); if (index >= 0) { return position - index; } return position - (-index - 1); } protected int toEventPosition(JTextComponent component, int position) { int result = position; while (toComponentPosition(component, result) < position) { result++; } return result; } protected final void highlight(JTextComponent comp, int i, int j) { highlight(comp, i, j, true); } protected void highlight(JTextComponent comp, int i, int j, boolean scroll) { Highlighter highlighter = comp.getHighlighter(); highlighter.removeAllHighlights(); try { i = toComponentPosition(comp, i); j = toComponentPosition(comp, j); highlighter.addHighlight(i, j+1, DefaultHighlighter.DefaultPainter); if (scroll) { if (comp.getCaretPosition() < i || comp.getCaretPosition() > j) { comp.moveCaretPosition(i); comp.scrollRectToVisible(comp.modelToView(i)); } } } catch (BadLocationException ble) { errMgr.internalError(tmodel.root.event.scope.st, "bad highlight location", ble); } } protected void updateAttributes(final InstanceScope scope, final STViewFrame m) { //System.out.println("updateAttributes: "+Interpreter.getEnclosingInstanceStackString(scope) ); m.attributes.setModel( new JTreeScopeStackModel(scope) ); m.attributes.setRootVisible(false); m.attributes.setShowsRootHandles(true); //System.out.println("add events="+ st.addAttrEvents); // ST st = scope.st; // final DefaultListModel attrModel = new DefaultListModel(); // final Map attrs = st.getAttributes(); // if ( attrs!=null ) { // for (String a : attrs.keySet()) { // if ( st.debugState!=null && st.debugState.addAttrEvents!=null ) { // List events = st.debugState.addAttrEvents.get(a); // StringBuilder locations = new StringBuilder(); // int i = 0; // if ( events!=null ) { // for (AddAttributeEvent ae : events) { // if ( i>0 ) locations.append(", "); // locations.append(ae.getFileName()+":"+ae.getLine()); // i++; // } // } // if ( locations.length()>0 ) { // attrModel.addElement(a+" = "+attrs.get(a)+" @ "+locations.toString()); // } // else { // attrModel.addElement(a+" = "+attrs.get(a)); // } // } // else { // attrModel.addElement(a+" = "+attrs.get(a)); // } // } // } // m.attributes.setModel(attrModel); } protected void updateStack(InstanceScope scope, STViewFrame m) { List stack = Interpreter.getEnclosingInstanceStack(scope, true); m.setTitle("STViz - ["+ Misc.join(stack.iterator()," ")+"]"); // // also do source stack // StackTraceElement[] trace = st.newSTEvent.stack.getStackTrace(); // StringWriter sw = new StringWriter(); // for (StackTraceElement e : trace) { // sw.write(e.toString()+"\n"); // } } public InterpEvent findEventAtOutputLocation(List events, int charIndex) { for (InterpEvent e : events) { if (e.scope.earlyEval) { continue; } if ( charIndex>=e.outputStartChar && charIndex<=e.outputStopChar) return e; } return null; } public static void main(String[] args) throws IOException { // test rig if ( args.length>0 && args[0].equals("1") ) test1(); else if ( args.length>0 && args[0].equals("2") ) test2(); else if ( args.length>0 && args[0].equals("3") ) test3(); else if ( args.length>0 && args[0].equals("4") ) test4(); } public static void test1() throws IOException { // test rig String templates = "method(type,name,locals,args,stats) ::= <<\n" + "public (}; separator=\", \">) {\n" + " int locals[];\n"+ " \n" + "}\n" + ">>\n"+ "assign(a,b) ::= \" = ;\"\n"+ "return(x) ::= <;>>\n" + "paren(x) ::= \"()\"\n"; String tmpdir = System.getProperty("java.io.tmpdir"); writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST st = group.getInstanceOf("method"); st.impl.dump(); st.add("type", "float"); st.add("name", "foo"); st.add("locals", 3); st.add("args", (Object)new String[] {"x", "y", "z"}); ST s1 = group.getInstanceOf("assign"); ST paren = group.getInstanceOf("paren"); paren.add("x", "x"); s1.add("a", paren); s1.add("b", "y"); ST s2 = group.getInstanceOf("assign"); s2.add("a", "y"); s2.add("b", "z"); ST s3 = group.getInstanceOf("return"); s3.add("x", "3.14159"); st.add("stats", s1); st.add("stats", s2); st.add("stats", s3); STViz viz = st.inspect(); System.out.println(st.render()); // should not mess up ST event lists } public static void test2() throws IOException { // test rig String templates = "t1(q1=\"Some\\nText\") ::= <<\n" + "\n" + ">>\n" + "\n" + "t2(p1) ::= <<\n" + "\n" + ">>\n" + "\n" + "main() ::= <<\n" + "START--END\n" + "\n" + "START--END\n" + ">>\n"; String tmpdir = System.getProperty("java.io.tmpdir"); writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST st = group.getInstanceOf("main"); STViz viz = st.inspect(); } public static void test3() throws IOException { String templates = "main() ::= <<\n" + "Foo: <{bar};format=\"lower\">\n" + ">>\n"; String tmpdir = System.getProperty("java.io.tmpdir"); writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST st = group.getInstanceOf("main"); st.inspect(); } public static void test4() throws IOException { String templates = "main(t) ::= <<\n" + "hi: \n" + ">>\n" + "foo(x,y={hi}) ::= \"\"\n" + "bar(x,y) ::= << >>\n" + "ignore(m) ::= \"\"\n"; STGroup group = new STGroupString(templates); ST st = group.getInstanceOf("main"); ST foo = group.getInstanceOf("foo"); st.add("t", foo); ST ignore = group.getInstanceOf("ignore"); ignore.add("m", foo); // embed foo twice! st.inspect(); st.render(); } public static void writeFile(String dir, String fileName, String content) { try { File f = new File(dir, fileName); if ( !f.getParentFile().exists() ) f.getParentFile().mkdirs(); FileWriter w = new FileWriter(f); BufferedWriter bw = new BufferedWriter(w); bw.write(content); bw.close(); w.close(); } catch (IOException ioe) { System.err.println("can't write file"); ioe.printStackTrace(System.err); } } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/000077500000000000000000000000001231426731300225575ustar00rootroot00000000000000stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/Aggregate.java000066400000000000000000000075121231426731300253150ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; import java.util.HashMap; /** An automatically created aggregate of properties. * *

I often have lists of things that need to be formatted, but the list * items are actually pieces of data that are not already in an object. I * need ST to do something like:

*

* Ter=3432
* Tom=32234
* ....

*

* using template:

*

* {@code $items:{it.name$=$it.type$}$}

*

* This example will call {@code getName()} on the objects in items attribute, but * what if they aren't objects? I have perhaps two parallel arrays * instead of a single array of objects containing two fields. One * solution is allow {@code Map}s to be handled like properties so that {@code it.name} * would fail {@code getName()} but then see that it's a {@code Map} and do * {@code it.get("name")} instead.

*

* This very clean approach is espoused by some, but the problem is that * it's a hole in my separation rules. People can put the logic in the * view because you could say: "go get bob's data" in the view:

*

* Bob's Phone: {@code $db.bob.phone$}

*

* A view should not be part of the program and hence should never be able * to go ask for a specific person's data.

*

* After much thought, I finally decided on a simple solution. I've * added setAttribute variants that pass in multiple property values, * with the property names specified as part of the name using a special * attribute name syntax: {@code "name.{propName1,propName2,...}"}. This * object is a special kind of {@code HashMap} that hopefully prevents people * from passing a subclass or other variant that they have created as * it would be a loophole. Anyway, the {@link AggregateModelAdaptor#getProperty} * method looks for {@code Aggregate} as a special case and does a {@link #get} instead * of {@code getPropertyName}.

*/ public class Aggregate { public HashMap properties = new HashMap(); /** Allow StringTemplate to add values, but prevent the end * user from doing so. */ protected void put(String propName, Object propValue) { properties.put(propName, propValue); } public Object get(String propName) { return properties.get(propName); } @Override public String toString() { return properties.toString(); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/AggregateModelAdaptor.java000066400000000000000000000040451231426731300276070ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; import org.stringtemplate.v4.Interpreter; import org.stringtemplate.v4.ST; import java.util.Map; /** Deal with structs created via {@link ST#addAggr}{@code ("structname.{prop1, prop2}", ...);}. */ public class AggregateModelAdaptor extends MapModelAdaptor { @Override public Object getProperty(Interpreter interp, ST self, Object o, Object property, String propertyName) throws STNoSuchPropertyException { Map map = ((Aggregate)o).properties; return super.getProperty(interp, self, map, property, propertyName); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/AmbiguousMatchException.java000066400000000000000000000036701231426731300302170ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2012 Terence Parr * Copyright (c) 2012 Sam Harwell * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; /** * * @author Sam Harwell */ public class AmbiguousMatchException extends RuntimeException { public AmbiguousMatchException() { super(); } public AmbiguousMatchException(String message) { super(message); } public AmbiguousMatchException(Throwable cause) { super(cause); } public AmbiguousMatchException(String message, Throwable cause) { super(message, cause); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/ArrayIterator.java000066400000000000000000000045641231426731300262230ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; import java.lang.reflect.Array; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; /** Iterator for an array so I don't have to copy the array to a {@link List} * just to make it implement {@link Iterator}. */ public class ArrayIterator implements Iterator { /** Index into the data array */ protected int i = -1; protected Object array = null; /** Arrays are fixed size; precompute. */ protected int n; public ArrayIterator(Object array) { this.array = array; n = Array.getLength(array); } @Override public boolean hasNext() { return (i+1)0; } @Override public Object next() { i++; // move to next element if ( i >= n ) { throw new NoSuchElementException(); } return Array.get(array, i); } @Override public void remove() { throw new UnsupportedOperationException(); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/Coordinate.java000066400000000000000000000036001231426731300255100ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; /** A line number and char position within a line. Used by the source * mapping stuff to map address to range within a template. */ public class Coordinate { public int line; public int charPosition; public Coordinate(int a, int b) { this.line=a; this.charPosition=b; } @Override public String toString() { return line+":"+charPosition; } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/ErrorBuffer.java000066400000000000000000000046641231426731300256570ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; import org.stringtemplate.v4.STErrorListener; import java.util.ArrayList; import java.util.List; /** Used during tests to track all errors. */ public class ErrorBuffer implements STErrorListener { public List errors = new ArrayList(); @Override public void compileTimeError(STMessage msg) { errors.add(msg); } @Override public void runTimeError(STMessage msg) { if ( msg.error != ErrorType.NO_SUCH_PROPERTY ) { // ignore these errors.add(msg); } } @Override public void IOError(STMessage msg) { errors.add(msg); } @Override public void internalError(STMessage msg) { errors.add(msg); } @Override public String toString() { StringBuilder buf = new StringBuilder(); for (STMessage m : errors) { buf.append(m.toString()+Misc.newline); } return buf.toString(); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/ErrorManager.java000066400000000000000000000144541231426731300260160ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; import org.antlr.runtime.CharStream; import org.antlr.runtime.RecognitionException; import org.antlr.runtime.Token; import org.stringtemplate.v4.InstanceScope; import org.stringtemplate.v4.Interpreter; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STErrorListener; public class ErrorManager { public static STErrorListener DEFAULT_ERROR_LISTENER = new STErrorListener() { @Override public void compileTimeError(STMessage msg) { System.err.println(msg); } @Override public void runTimeError(STMessage msg) { if ( msg.error != ErrorType.NO_SUCH_PROPERTY ) { // ignore these System.err.println(msg); } } @Override public void IOError(STMessage msg) { System.err.println(msg); } @Override public void internalError(STMessage msg) { System.err.println(msg); // throw new Error("internal error", msg.cause); } public void error(String s) { error(s, null); } public void error(String s, Throwable e) { System.err.println(s); if ( e!=null ) { e.printStackTrace(System.err); } } }; public final STErrorListener listener; public ErrorManager() { this(DEFAULT_ERROR_LISTENER); } public ErrorManager(STErrorListener listener) { this.listener = listener; } public void compileTimeError(ErrorType error, Token templateToken, Token t) { CharStream input = t.getInputStream(); String srcName = null; if ( input!=null ) { srcName = input.getSourceName(); if ( srcName!=null ) srcName = Misc.getFileName(srcName); } listener.compileTimeError( new STCompiletimeMessage(error,srcName,templateToken,t,null,t.getText()) ); } public void lexerError(String srcName, String msg, Token templateToken, RecognitionException e) { if ( srcName!=null ) srcName = Misc.getFileName(srcName); listener.compileTimeError( new STLexerMessage(srcName, msg, templateToken, e) ); } public void compileTimeError(ErrorType error, Token templateToken, Token t, Object arg) { String srcName = t.getInputStream().getSourceName(); if ( srcName!=null ) srcName = Misc.getFileName(srcName); listener.compileTimeError( new STCompiletimeMessage(error,srcName,templateToken,t,null,arg) ); } public void compileTimeError(ErrorType error, Token templateToken, Token t, Object arg, Object arg2) { String srcName = t.getInputStream().getSourceName(); if ( srcName!=null ) srcName = Misc.getFileName(srcName); listener.compileTimeError( new STCompiletimeMessage(error,srcName,templateToken,t,null,arg,arg2) ); } public void groupSyntaxError(ErrorType error, String srcName, RecognitionException e, String msg) { Token t = e.token; listener.compileTimeError( new STGroupCompiletimeMessage(error,srcName,e.token,e,msg) ); } public void groupLexerError(ErrorType error, String srcName, RecognitionException e, String msg) { listener.compileTimeError( new STGroupCompiletimeMessage(error,srcName,e.token,e,msg) ); } public void runTimeError(Interpreter interp, InstanceScope scope, ErrorType error) { listener.runTimeError(new STRuntimeMessage(interp, error, scope != null ? scope.ip : 0, scope)); } public void runTimeError(Interpreter interp, InstanceScope scope, ErrorType error, Object arg) { listener.runTimeError(new STRuntimeMessage(interp, error, scope != null ? scope.ip : 0, scope,arg)); } public void runTimeError(Interpreter interp, InstanceScope scope, ErrorType error, Throwable e, Object arg) { listener.runTimeError(new STRuntimeMessage(interp, error, scope != null ? scope.ip : 0, scope,e,arg)); } public void runTimeError(Interpreter interp, InstanceScope scope, ErrorType error, Object arg, Object arg2) { listener.runTimeError(new STRuntimeMessage(interp, error, scope != null ? scope.ip : 0, scope,null,arg,arg2)); } public void runTimeError(Interpreter interp, InstanceScope scope, ErrorType error, Object arg, Object arg2, Object arg3) { listener.runTimeError(new STRuntimeMessage(interp, error, scope != null ? scope.ip : 0, scope,null,arg,arg2,arg3)); } public void IOError(ST self, ErrorType error, Throwable e) { listener.IOError(new STMessage(error, self, e)); } public void IOError(ST self, ErrorType error, Throwable e, Object arg) { listener.IOError(new STMessage(error, self, e, arg)); } public void internalError(ST self, String msg, Throwable e) { listener.internalError(new STMessage(ErrorType.INTERNAL_ERROR, self, e, msg)); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/ErrorType.java000066400000000000000000000071461231426731300253650ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; /** All the errors that can happen and how to generate a message. */ public enum ErrorType { // RUNTIME SEMANTIC ERRORS NO_SUCH_TEMPLATE("no such template: %s"), NO_IMPORTED_TEMPLATE("no such template: super.%s"), NO_SUCH_ATTRIBUTE("attribute %s isn't defined"), NO_SUCH_ATTRIBUTE_PASS_THROUGH("could not pass through undefined attribute %s"), REF_TO_IMPLICIT_ATTRIBUTE_OUT_OF_SCOPE("implicitly-defined attribute %s not visible"), MISSING_FORMAL_ARGUMENTS("missing argument definitions"), NO_SUCH_PROPERTY("no such property or can't access: %s"), MAP_ARGUMENT_COUNT_MISMATCH("iterating through %s values in zip map but template has %s declared arguments"), ARGUMENT_COUNT_MISMATCH("passed %s arg(s) to template %s with %s declared arg(s)"), EXPECTING_STRING("function %s expects a string not %s"), WRITER_CTOR_ISSUE("%s(Writer) constructor doesn't exist"), CANT_IMPORT("can't find template(s) in import \"%s\""), // COMPILE-TIME SYNTAX/SEMANTIC ERRORS SYNTAX_ERROR("%s"), TEMPLATE_REDEFINITION("redefinition of template %s"), EMBEDDED_REGION_REDEFINITION("region %s is embedded and thus already implicitly defined"), REGION_REDEFINITION("redefinition of region %s"), MAP_REDEFINITION("redefinition of dictionary %s"), ALIAS_TARGET_UNDEFINED("cannot alias %s to undefined template: %s"), TEMPLATE_REDEFINITION_AS_MAP("redefinition of template %s as a map"), LEXER_ERROR("%s"), NO_DEFAULT_VALUE("missing dictionary default value"), NO_SUCH_FUNCTION("no such function: %s"), NO_SUCH_REGION("template %s doesn't have a region called %s"), NO_SUCH_OPTION("no such option: %s"), INVALID_TEMPLATE_NAME("invalid template name or path: %s"), ANON_ARGUMENT_MISMATCH("anonymous template has %s arg(s) but mapped across %s value(s)"), REQUIRED_PARAMETER_AFTER_OPTIONAL("required parameters (%s) must appear before optional parameters"), // INTERNAL ERRORS INTERNAL_ERROR("%s"), WRITE_IO_ERROR("error writing output caused by"), CANT_LOAD_GROUP_FILE("can't load group file %s"); public String message; ErrorType(String m) { message = m; } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/Interval.java000066400000000000000000000034761231426731300252200ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; /** An inclusive interval {@code a..b}. Used to track ranges in output and * template patterns (for debugging). */ public class Interval { public int a; public int b; public Interval(int a, int b) { this.a=a; this.b=b; } @Override public String toString() { return a+".."+b; } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/MapModelAdaptor.java000066400000000000000000000047321231426731300264410ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; import org.stringtemplate.v4.Interpreter; import org.stringtemplate.v4.ModelAdaptor; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; import java.util.Map; public class MapModelAdaptor implements ModelAdaptor { @Override public Object getProperty(Interpreter interp, ST self, Object o, Object property, String propertyName) throws STNoSuchPropertyException { Object value; Map map = (Map)o; if ( property==null ) value = map.get(STGroup.DEFAULT_KEY); else if ( property.equals("keys") ) value = map.keySet(); else if ( property.equals("values") ) value = map.values(); else if ( map.containsKey(property) ) value = map.get(property); else if ( map.containsKey(propertyName) ) { // if can't find the key, try toString version value = map.get(propertyName); } else value = map.get(STGroup.DEFAULT_KEY); // not found, use default if ( value == STGroup.DICT_KEY ) { value = property; } return value; } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/Misc.java000066400000000000000000000155051231426731300243230ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; import java.io.Closeable; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.JarURLConnection; import java.net.URL; import java.net.URLClassLoader; import java.net.URLConnection; import java.util.Iterator; public class Misc { public static final String newline = System.getProperty("line.separator"); /** Makes it clear when a comparison is intended as reference equality. */ public static boolean referenceEquals(Object x, Object y) { return x == y; } // Seriously: why isn't this built in to java? public static String join(Iterator iter, String separator) { StringBuilder buf = new StringBuilder(); while ( iter.hasNext() ) { buf.append(iter.next()); if ( iter.hasNext() ) { buf.append(separator); } } return buf.toString(); } // public static String join(Object[] a, String separator, int start, int stop) { // StringBuilder buf = new StringBuilder(); // for (int i = start; i < stop; i++) { // if ( i>start ) buf.append(separator); // buf.append(a[i].toString()); // } // return buf.toString(); // } public static String strip(String s, int n) { return s.substring(n, s.length()-n); } // public static String stripRight(String s, int n) { // return s.substring(0, s.length()-n); // } /** Strip a single newline character from the front of {@code s}. */ public static String trimOneStartingNewline(String s) { if ( s.startsWith("\r\n") ) s = s.substring(2); else if ( s.startsWith("\n") ) s = s.substring(1); return s; } /** Strip a single newline character from the end of {@code s}. */ public static String trimOneTrailingNewline(String s) { if ( s.endsWith("\r\n") ) s = s.substring(0, s.length()-2); else if ( s.endsWith("\n") ) s = s.substring(0, s.length()-1); return s; } /** Given, say, {@code file:/tmp/test.jar!/org/foo/templates/main.stg} * convert to {@code file:/tmp/test.jar!/org/foo/templates} */ public static String stripLastPathElement(String f) { int slash = f.lastIndexOf('/'); if ( slash<0 ) return f; return f.substring(0, slash); } public static String getFileNameNoSuffix(String f) { if (f==null) return null; f = getFileName(f); return f.substring(0,f.lastIndexOf('.')); } public static String getFileName(String fullFileName) { if (fullFileName==null) return null; File f = new File(fullFileName); // strip to simple name return f.getName(); } public static String getParent(String name) { //System.out.println("getParent("+name+")="+p); if (name==null) return null; int lastSlash=name.lastIndexOf('/'); if (lastSlash>0) return name.substring(0, lastSlash); if (lastSlash==0) return "/"; //System.out.println("getParent("+name+")="+p); return ""; } public static String getPrefix(String name) { if (name==null) return "/"; String parent = getParent(name); String prefix = parent; if ( !parent.endsWith("/") ) prefix += '/'; return prefix; } public static String replaceEscapes(String s) { s = s.replaceAll("\n", "\\\\n"); s = s.replaceAll("\r", "\\\\r"); s = s.replaceAll("\t", "\\\\t"); return s; } /** Replace >\> with >> in s. Replace \>> unless prefix of \>>> with >>. * Do NOT replace if it's <\\> */ public static String replaceEscapedRightAngle(String s) { StringBuilder buf = new StringBuilder(); int i = 0; while ( i") ) { buf.append("<\\\\>"); i += "<\\\\>".length(); continue; } if ( c=='>' && s.substring(i).startsWith(">\\>") ) { buf.append(">>"); i += ">\\>".length(); continue; } if ( c=='\\' && s.substring(i).startsWith("\\>>") && !s.substring(i).startsWith("\\>>>") ) { buf.append(">>"); i += "\\>>".length(); continue; } buf.append(c); i++; } return buf.toString(); } public static boolean urlExists(URL url) { try { URLConnection connection = url.openConnection(); if (connection instanceof JarURLConnection) { JarURLConnection jarURLConnection = (JarURLConnection)connection; URLClassLoader urlClassLoader = new URLClassLoader(new URL[] { jarURLConnection.getJarFileURL() }); try { return urlClassLoader.findResource(jarURLConnection.getEntryName()) != null; } finally { if (urlClassLoader instanceof Closeable) { ((Closeable)urlClassLoader).close(); } } } InputStream is = null; try { is = url.openStream(); } finally { if (is != null) { is.close(); } } return is != null; } catch (IOException ioe) { return false; } } /** * Given {@code index} into string {@code s}, compute the line and char * position in line. */ public static Coordinate getLineCharPosition(String s, int index) { int line = 1; int charPos = 0; int p = 0; while ( p < index ) { // don't care about s[index] itself; count before if ( s.charAt(p)=='\n' ) { line++; charPos=0; } else charPos++; p++; } return new Coordinate(line,charPos); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/MultiMap.java000066400000000000000000000036111231426731300251530ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; import java.util.*; /** A hash table that maps a key to a list of elements not just a single. */ public class MultiMap extends LinkedHashMap> { public void map(K key, V value) { List elementsForKey = get(key); if ( elementsForKey==null ) { elementsForKey = new ArrayList(); super.put(key, elementsForKey); } elementsForKey.add(value); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/ObjectModelAdaptor.java000066400000000000000000000120271231426731300271260ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; import org.stringtemplate.v4.Interpreter; import org.stringtemplate.v4.ModelAdaptor; import org.stringtemplate.v4.ST; import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; public class ObjectModelAdaptor implements ModelAdaptor { protected static final Member INVALID_MEMBER; static { Member invalidMember; try { invalidMember = ObjectModelAdaptor.class.getDeclaredField("INVALID_MEMBER"); } catch (NoSuchFieldException ex) { invalidMember = null; } catch (SecurityException ex) { invalidMember = null; } INVALID_MEMBER = invalidMember; } protected static final Map, Map> membersCache = new HashMap, Map>(); @Override public synchronized Object getProperty(Interpreter interp, ST self, Object o, Object property, String propertyName) throws STNoSuchPropertyException { if (o == null) { throw new NullPointerException("o"); } Class c = o.getClass(); if ( property==null ) { return throwNoSuchProperty(c, propertyName, null); } Member member = findMember(c, propertyName); if ( member!=null ) { try { if (member instanceof Method) { return ((Method)member).invoke(o); } else if (member instanceof Field) { return ((Field)member).get(o); } } catch (Exception e) { throwNoSuchProperty(c, propertyName, e); } } return throwNoSuchProperty(c, propertyName, null); } protected static Member findMember(Class clazz, String memberName) { if (clazz == null) { throw new NullPointerException("clazz"); } if (memberName == null) { throw new NullPointerException("memberName"); } synchronized (membersCache) { Map members = membersCache.get(clazz); Member member = null; if (members != null) { member = members.get(memberName); if (member != null) { return member != INVALID_MEMBER ? member : null; } } else { members = new HashMap(); membersCache.put(clazz, members); } // try getXXX and isXXX properties, look up using reflection String methodSuffix = Character.toUpperCase(memberName.charAt(0)) + memberName.substring(1, memberName.length()); member = tryGetMethod(clazz, "get" + methodSuffix); if (member == null) { member = tryGetMethod(clazz, "is" + methodSuffix); if (member == null) { member = tryGetMethod(clazz, "has" + methodSuffix); } } if (member == null) { // try for a visible field member = tryGetField(clazz, memberName); } members.put(memberName, member != null ? member : INVALID_MEMBER); return member; } } protected static Method tryGetMethod(Class clazz, String methodName) { try { Method method = clazz.getMethod(methodName); if (method != null) { method.setAccessible(true); } return method; } catch (NoSuchMethodException ex) { } catch (SecurityException ex) { } return null; } protected static Field tryGetField(Class clazz, String fieldName) { try { Field field = clazz.getField(fieldName); if (field != null) { field.setAccessible(true); } return field; } catch (NoSuchFieldException ex) { } catch (SecurityException ex) { } return null; } protected Object throwNoSuchProperty(Class clazz, String propertyName, Exception cause) { throw new STNoSuchPropertyException(cause, null, clazz.getName() + "." + propertyName); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/STCompiletimeMessage.java000066400000000000000000000074531231426731300274560ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; import org.antlr.runtime.RecognitionException; import org.antlr.runtime.Token; import org.stringtemplate.v4.compiler.GroupParser; /** Used for semantic errors that occur at compile time not during * interpretation. For ST parsing ONLY not group parsing. */ public class STCompiletimeMessage extends STMessage { /** overall token pulled from group file */ public Token templateToken; /** token inside template */ public Token token; public String srcName; public STCompiletimeMessage(ErrorType error, String srcName, Token templateToken, Token t) { this(error, srcName, templateToken, t, null); } public STCompiletimeMessage(ErrorType error, String srcName, Token templateToken, Token t, Throwable cause) { this(error, srcName, templateToken, t, cause, null); } public STCompiletimeMessage(ErrorType error, String srcName, Token templateToken, Token t, Throwable cause, Object arg) { this(error, srcName, templateToken, t, cause, arg, null); } public STCompiletimeMessage(ErrorType error, String srcName, Token templateToken, Token t, Throwable cause, Object arg, Object arg2) { super(error, null, cause, arg, arg2); this.templateToken = templateToken; this.token = t; this.srcName = srcName; } @Override public String toString() { RecognitionException re = (RecognitionException)cause; int line = 0; int charPos = -1; if ( token!=null ) { line = token.getLine(); charPos = token.getCharPositionInLine(); // check the input streams - if different then token is embedded in templateToken and we need to adjust the offset if ( templateToken!=null && !templateToken.getInputStream().equals(token.getInputStream()) ) { int templateDelimiterSize = 1; if ( templateToken.getType()== GroupParser.BIGSTRING || templateToken.getType()== GroupParser.BIGSTRING_NO_NL ) { templateDelimiterSize = 2; } line += templateToken.getLine() - 1; charPos += templateToken.getCharPositionInLine() + templateDelimiterSize; } } String filepos = line+":"+charPos; if ( srcName!=null ) { return srcName+" "+filepos+": "+String.format(error.message, arg, arg2); } return filepos+": "+String.format(error.message, arg, arg2); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/STGroupCompiletimeMessage.java000066400000000000000000000054601231426731300304670ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; import org.antlr.runtime.RecognitionException; import org.antlr.runtime.Token; /** */ public class STGroupCompiletimeMessage extends STMessage { /** token inside group file */ public Token token; public String srcName; public STGroupCompiletimeMessage(ErrorType error, String srcName, Token t, Throwable cause) { this(error, srcName, t, cause, null); } public STGroupCompiletimeMessage(ErrorType error, String srcName, Token t, Throwable cause, Object arg) { this(error, srcName, t, cause, arg, null); } public STGroupCompiletimeMessage(ErrorType error, String srcName, Token t, Throwable cause, Object arg, Object arg2) { super(error, null, cause, arg, arg2); this.token = t; this.srcName = srcName; } @Override public String toString() { RecognitionException re = (RecognitionException)cause; int line = 0; int charPos = -1; if ( token!=null ) { line = token.getLine(); charPos = token.getCharPositionInLine(); } else if ( re!=null ) { line = re.line; charPos = re.charPositionInLine; } String filepos = line+":"+charPos; if ( srcName!=null ) { return srcName+" "+filepos+": "+String.format(error.message, arg, arg2); } return filepos+": "+String.format(error.message, arg, arg2); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/STLexerMessage.java000066400000000000000000000052411231426731300262570ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; import org.antlr.runtime.RecognitionException; import org.antlr.runtime.Token; import org.stringtemplate.v4.compiler.GroupParser; /** */ public class STLexerMessage extends STMessage { public String msg; /** overall token pulled from group file */ public Token templateToken; public String srcName; public STLexerMessage(String srcName, String msg, Token templateToken, Throwable cause) { super(ErrorType.LEXER_ERROR, null, cause, null); this.msg = msg; this.templateToken = templateToken; this.srcName = srcName; } @Override public String toString() { RecognitionException re = (RecognitionException)cause; int line = re.line; int charPos = re.charPositionInLine; if ( templateToken!=null ) { int templateDelimiterSize = 1; if ( templateToken.getType()== GroupParser.BIGSTRING ) { templateDelimiterSize = 2; } line += templateToken.getLine() - 1; charPos += templateToken.getCharPositionInLine() + templateDelimiterSize; } String filepos = line+":"+charPos; if ( srcName!=null ) { return srcName+" "+filepos+": "+String.format(error.message, msg); } return filepos+": "+String.format(error.message, msg); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/STMessage.java000066400000000000000000000065701231426731300252650ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; import org.antlr.runtime.Token; import org.stringtemplate.v4.ST; import java.io.PrintWriter; import java.io.StringWriter; /** Upon error, ST creates an {@link STMessage} or subclass instance and notifies * the listener. This root class is used for IO and internal errors. * * @see STRuntimeMessage * @see STCompiletimeMessage */ public class STMessage { /** if in debug mode, has created instance, add attr events and eval * template events. */ public ST self; public ErrorType error; public Object arg; public Object arg2; public Object arg3; public Throwable cause; public STMessage(ErrorType error) { this.error = error; } public STMessage(ErrorType error, ST self) { this(error); this.self = self; } public STMessage(ErrorType error, ST self, Throwable cause) { this(error,self); this.cause = cause; } public STMessage(ErrorType error, ST self, Throwable cause, Object arg) { this(error,self,cause); this.arg = arg; } public STMessage(ErrorType error, ST self, Throwable cause, Token where, Object arg) { this(error,self,cause,where); this.arg = arg; } public STMessage(ErrorType error, ST self, Throwable cause, Object arg, Object arg2) { this(error,self,cause,arg); this.arg2 = arg2; } public STMessage(ErrorType error, ST self, Throwable cause, Object arg, Object arg2, Object arg3) { this(error,self,cause,arg,arg2); this.arg3 = arg3; } @Override public String toString() { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); String msg = String.format(error.message, arg, arg2, arg3); pw.print(msg); if ( cause!=null ) { pw.print("\nCaused by: "); cause.printStackTrace(pw); } return sw.toString(); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/STModelAdaptor.java000066400000000000000000000036221231426731300262470ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; import org.stringtemplate.v4.Interpreter; import org.stringtemplate.v4.ModelAdaptor; import org.stringtemplate.v4.ST; public class STModelAdaptor implements ModelAdaptor { @Override public Object getProperty(Interpreter interp, ST self, Object o, Object property, String propertyName) throws STNoSuchPropertyException { ST st = (ST)o; return st.getAttribute(propertyName); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/STNoSuchAttributeException.java000066400000000000000000000040511231426731300306330ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; import org.stringtemplate.v4.InstanceScope; import org.stringtemplate.v4.compiler.STException; /** {@code } where {@code name} is not found up the dynamic scoping chain. */ public class STNoSuchAttributeException extends STException { public InstanceScope scope; public String name; public STNoSuchAttributeException(String name, InstanceScope scope) { this.name = name; this.scope = scope; } @Override public String getMessage() { return "from template "+scope.st.getName()+" no attribute "+name+" is visible"; } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/STNoSuchPropertyException.java000066400000000000000000000041111231426731300305110ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; import org.stringtemplate.v4.compiler.STException; /** For {@code }, object {@code a} does not have a property {@code b}. */ public class STNoSuchPropertyException extends STException { public Object o; public String propertyName; public STNoSuchPropertyException(Exception e, Object o, String propertyName) { super(null, e); this.o = o; this.propertyName = propertyName; } @Override public String getMessage() { if ( o!=null ) return "object "+o.getClass()+" has no "+propertyName+" property"; else return "no such property: "+propertyName; } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/STRuntimeMessage.java000066400000000000000000000076111231426731300266260ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; import org.stringtemplate.v4.*; /** Used to track errors that occur in the ST interpreter. */ public class STRuntimeMessage extends STMessage { /** Which interpreter was executing? If {@code null}, can be IO error or * bad URL etc... */ final Interpreter interp; /** Where error occurred in bytecode memory. */ public final int ip; public final InstanceScope scope; //List enclosingStack; public STRuntimeMessage(Interpreter interp, ErrorType error, int ip) { this(interp, error, ip, null); } public STRuntimeMessage(Interpreter interp, ErrorType error, int ip, InstanceScope scope) { this(interp, error,ip,scope,null); } public STRuntimeMessage(Interpreter interp, ErrorType error, int ip, InstanceScope scope, Object arg) { this(interp, error, ip, scope, null, arg, null); } public STRuntimeMessage(Interpreter interp, ErrorType error, int ip, InstanceScope scope, Throwable e, Object arg) { this(interp, error, ip, scope, e, arg, null); } public STRuntimeMessage(Interpreter interp, ErrorType error, int ip, InstanceScope scope, Throwable e, Object arg, Object arg2) { this(interp, error, ip, scope, e, arg, arg2, null); } public STRuntimeMessage(Interpreter interp, ErrorType error, int ip, InstanceScope scope, Throwable e, Object arg, Object arg2, Object arg3) { super(error, scope != null ? scope.st : null, e, arg, arg2, arg3); this.interp = interp; this.ip = ip; this.scope = scope; } /** Given an IP (code location), get it's range in source template then * return it's template line:col. */ public String getSourceLocation() { if ( ip<0 || self.impl==null ) return null; Interval I = self.impl.sourceMap[ip]; if ( I==null ) return null; // get left edge and get line/col int i = I.a; Coordinate loc = Misc.getLineCharPosition(self.impl.template, i); return loc.toString(); } @Override public String toString() { StringBuilder buf = new StringBuilder(); String loc = getSourceLocation(); if ( self!=null ) { buf.append("context ["); if ( interp!=null ) { buf.append( Interpreter.getEnclosingInstanceStackString(scope) ); } buf.append("]"); } if ( loc!=null ) buf.append(" "+loc); buf.append(" "+super.toString()); return buf.toString(); } } stringtemplate4-4.0.8/src/org/stringtemplate/v4/misc/TypeRegistry.java000066400000000000000000000131651231426731300261020ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2012 Terence Parr * Copyright (c) 2012 Sam Harwell * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.misc; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; /** * * @author Sam Harwell */ public class TypeRegistry implements Map, V> { private final Map, V> backingStore = new HashMap, V>(); private final Map, Class> cache = new HashMap, Class>(); public int size() { return backingStore.size(); } public boolean isEmpty() { return backingStore.isEmpty(); } public boolean containsKey(Object key) { if (cache.containsKey(key)) { return true; } if (!(key instanceof Class)) { return false; } return get((Class)key) != null; } @SuppressWarnings("unchecked") public boolean containsValue(Object value) { return values().contains((V)value); } /** * {@inheritDoc} * * @throws AmbiguousMatchException if the registry contains more than value * mapped to a maximally-specific type from which {@code key} is derived. */ public V get(Object key) { V value = backingStore.get(key); if (value != null) { return value; } Class redirect = cache.get(key); if (redirect != null) { if (redirect == Void.TYPE) { return null; } else { return backingStore.get(redirect); } } if (!(key instanceof Class)) { return null; } Class keyClass = (Class)key; List> candidates = new ArrayList>(); for (Class clazz : backingStore.keySet()) { if (clazz.isAssignableFrom(keyClass)) { candidates.add(clazz); } } if (candidates.isEmpty()) { cache.put(keyClass, Void.TYPE); return null; } else if (candidates.size() == 1) { cache.put(keyClass, candidates.get(0)); return backingStore.get(candidates.get(0)); } else { for (int i = 0; i < candidates.size() - 1; i++) { if (candidates.get(i) == null) { continue; } for (int j = i + 1; j < candidates.size(); j++) { if (candidates.get(i).isAssignableFrom(candidates.get(j))) { candidates.set(i, null); break; } else if (candidates.get(j).isAssignableFrom(candidates.get(i))) { candidates.set(j, null); } } } int j = 0; for (int i = 0; i < candidates.size(); i++) { Class current = candidates.get(i); if (current == null) { continue; } if (i != j) { candidates.set(j, current); } j++; } assert j > 0; if (j != 1) { StringBuilder builder = new StringBuilder(); builder.append(String.format("The class '%s' does not match a single item in the registry. The %d ambiguous matches are:", keyClass.getName(), j)); for (int i = 0; i < j; i++) { builder.append(String.format("%n %s", candidates.get(j).getName())); } throw new AmbiguousMatchException(builder.toString()); } cache.put(keyClass, candidates.get(0)); return backingStore.get(candidates.get(0)); } } public V put(Class key, V value) { V result = get(key); backingStore.put(key, value); handleAlteration(key); return result; } public V remove(Object key) { if (!(key instanceof Class)) { return null; } Class clazz = (Class)key; V previous = get(clazz); if (backingStore.remove(clazz) != null) { handleAlteration(clazz); } return previous; } public void putAll(Map, ? extends V> m) { for (Map.Entry, ? extends V> entry : m.entrySet()) { put(entry.getKey(), entry.getValue()); } } public void clear() { backingStore.clear(); cache.clear(); } public Set> keySet() { return Collections.unmodifiableSet(backingStore.keySet()); } public Collection values() { return Collections.unmodifiableCollection(backingStore.values()); } public Set, V>> entrySet() { return Collections.unmodifiableSet(backingStore.entrySet()); } protected void handleAlteration(Class clazz) { for (Map.Entry, ?> entry : cache.entrySet()) { if (clazz.isAssignableFrom(entry.getKey())) { entry.setValue(null); } } } } stringtemplate4-4.0.8/test/000077500000000000000000000000001231426731300156325ustar00rootroot00000000000000stringtemplate4-4.0.8/test/org/000077500000000000000000000000001231426731300164215ustar00rootroot00000000000000stringtemplate4-4.0.8/test/org/stringtemplate/000077500000000000000000000000001231426731300214635ustar00rootroot00000000000000stringtemplate4-4.0.8/test/org/stringtemplate/v4/000077500000000000000000000000001231426731300220145ustar00rootroot00000000000000stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/000077500000000000000000000000001231426731300227735ustar00rootroot00000000000000stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/BaseTest.java000066400000000000000000000226631231426731300253610ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.antlr.runtime.*; import org.junit.Before; import org.stringtemplate.v4.*; import org.stringtemplate.v4.compiler.Compiler; import org.stringtemplate.v4.compiler.*; import org.stringtemplate.v4.misc.Misc; import java.io.*; import java.util.*; import static org.junit.Assert.assertEquals; public abstract class BaseTest { public static final String pathSep = System.getProperty("path.separator"); public static final String tmpdir = System.getProperty("java.io.tmpdir"); public static final boolean interactive = Boolean.parseBoolean(System.getProperty("test.interactive")); public static final String newline = Misc.newline; /** * When runnning from Maven, the junit tests are run via the surefire plugin. It sets the * classpath for the test environment into the following property. We need to pick this up * for the junit tests that are going to generate and try to run code. */ public static final String SUREFIRE_CLASSPATH = System.getProperty("surefire.test.class.path", ""); public static final String CLASSPATH = System.getProperty("java.class.path") + (SUREFIRE_CLASSPATH.equals("") ? "" : pathSep + SUREFIRE_CLASSPATH); public static class StreamVacuum implements Runnable { StringBuffer buf = new StringBuffer(); BufferedReader in; Thread sucker; public StreamVacuum(InputStream in) { this.in = new BufferedReader( new InputStreamReader(in) ); } public void start() { sucker = new Thread(this); sucker.start(); } @Override public void run() { try { String line = in.readLine(); while (line!=null) { buf.append(line); buf.append('\n'); line = in.readLine(); } } catch (IOException ioe) { System.err.println("can't read output from process"); } } /** wait for the thread to finish */ public void join() throws InterruptedException { sucker.join(); } @Override public String toString() { return buf.toString(); } } @Before public void setUp() { STGroup.defaultGroup = new STGroup(); Compiler.subtemplateCount = 0; } /** * Creates a file "Test.java" in the directory dirName containing a main * method with content starting as given by main. *

* The value of a variable 'result' defined in 'main' is written to * System.out, followed by a newline character.

*

* The final newline character is just the '\n' character, not the * system specific line separator ({@link #newline}).

* * @param main * @param dirName */ public void writeTestFile(String main, String dirName) { ST outputFileST = new ST( "import org.antlr.runtime.*;\n" + "import org.stringtemplate.v4.*;\n" + "import org.antlr.runtime.tree.*;\n" + "import java.io.*;\n" + "import java.net.*;\n" + "\n" + "public class Test {\n" + " public static void main(String[] args) throws Exception {\n" + " \n"+ " System.out.println(result);\n"+ " }\n" + "}" ); outputFileST.add("code", main); writeFile(dirName, "Test.java", outputFileST.render()); } public String java(String mainClassName, String extraCLASSPATH, String workingDirName) { String classpathOption = "-classpath"; String path = "."+pathSep+CLASSPATH; if ( extraCLASSPATH!=null ) path = "."+pathSep+extraCLASSPATH+pathSep+CLASSPATH; String[] args = new String[] { "java", classpathOption, path, mainClassName }; System.out.println("executing: "+Arrays.toString(args)); return exec(args, null, workingDirName); } public void jar(String fileName, String[] files, String workingDirName) { String[] cmd = { "jar", "cf", fileName }; // SO SAD FOR YOU JAVA!!!! List list = new ArrayList(); list.addAll(Arrays.asList(cmd)); list.addAll(Arrays.asList(files)); String[] a = new String[list.size()]; list.toArray(a); exec(a, null, workingDirName); // create jar } public void compile(String fileName, String workingDirName) { String classpathOption = "-classpath"; String[] args = new String[] { "javac", classpathOption, "."+pathSep+CLASSPATH, fileName }; exec(args, null, workingDirName); } public String exec(String[] args, String[] envp, String workingDirName) { String cmdLine = Arrays.toString(args); File workingDir = new File(workingDirName); try { Process process = Runtime.getRuntime().exec(args, envp, workingDir); StreamVacuum stdout = new StreamVacuum(process.getInputStream()); StreamVacuum stderr = new StreamVacuum(process.getErrorStream()); stdout.start(); stderr.start(); process.waitFor(); stdout.join(); stderr.join(); if ( stdout.toString().length()>0 ) { return stdout.toString(); } if ( stderr.toString().length()>0 ) { System.err.println("compile stderr from: "+cmdLine); System.err.println(stderr); } int ret = process.exitValue(); if ( ret!=0 ) System.err.println("failed"); } catch (Exception e) { System.err.println("can't exec compilation"); e.printStackTrace(System.err); } return null; } public static void writeFile(String dir, String fileName, String content) { try { File f = new File(dir, fileName); if ( !f.getParentFile().exists() ) f.getParentFile().mkdirs(); FileWriter w = new FileWriter(f); BufferedWriter bw = new BufferedWriter(w); bw.write(content); bw.close(); w.close(); } catch (IOException ioe) { System.err.println("can't write file"); ioe.printStackTrace(System.err); } } public void checkTokens(String template, String expected) { checkTokens(template, expected, '<', '>'); } public void checkTokens(String template, String expected, char delimiterStartChar, char delimiterStopChar) { STLexer lexer = new STLexer(STGroup.DEFAULT_ERR_MGR, new ANTLRStringStream(template), null, delimiterStartChar, delimiterStopChar); CommonTokenStream tokens = new CommonTokenStream(lexer); StringBuilder buf = new StringBuilder(); buf.append("["); int i = 1; Token t = tokens.LT(i); while ( t.getType()!=Token.EOF ) { if ( i>1 ) buf.append(", "); buf.append(t); i++; t = tokens.LT(i); } buf.append("]"); String result = buf.toString(); assertEquals(expected, result); } public static class User { public int id; public String name; public User(int id, String name) { this.id = id; this.name = name; } public boolean isManager() { return true; } public boolean hasParkingSpot() { return true; } public String getName() { return name; } } public static class HashableUser extends User { public HashableUser(int id, String name) { super(id, name); } @Override public int hashCode() { return id; } @Override public boolean equals(Object o) { if ( o instanceof HashableUser ) { HashableUser hu = (HashableUser)o; return this.id == hu.id && this.name.equals(hu.name); } return false; } } public static String getRandomDir() { String randomDir = tmpdir+"dir"+String.valueOf((int)(Math.random()*100000)); File f = new File(randomDir); f.mkdirs(); return randomDir; } /** * Removes the specified file or directory, and all subdirectories. * * Nothing if the file does not exists. * * @param file */ public static void deleteFile(File file) { if (file.exists()) { if (file.isDirectory()) { File[] dir = file.listFiles(); for (int i = 0; i < dir.length; i++) { deleteFile(dir[i]); } } if (!file.delete()) { throw new RuntimeException("Error when deleting file " + file.getAbsolutePath()); } } } /** * see {@link #deleteFile(File)} * * @param file */ public static void deleteFile(String file) { deleteFile(new File(file)); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/ErrorBufferAllErrors.java000066400000000000000000000004101231426731300277020ustar00rootroot00000000000000package org.stringtemplate.v4.test; import org.stringtemplate.v4.misc.ErrorBuffer; import org.stringtemplate.v4.misc.STMessage; public class ErrorBufferAllErrors extends ErrorBuffer { @Override public void runTimeError(STMessage msg) { errors.add(msg); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/Playground.java000066400000000000000000000006121231426731300257610ustar00rootroot00000000000000package org.stringtemplate.v4.test; import org.stringtemplate.v4.*; public class Playground { public static void main(String[] args) { ErrorBufferAllErrors errors = new ErrorBufferAllErrors(); STGroup g = new STGroupFile("/tmp/g.stg"); g.setListener(errors); ST t = g.getInstanceOf("u"); if ( t!=null ) System.out.println(t.render()); System.err.println("errors: "+errors); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestAggregates.java000066400000000000000000000063211231426731300265510ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.Test; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroupString; import static org.junit.Assert.assertEquals; /** */ public class TestAggregates extends BaseTest { @Test public void testApplyAnonymousTemplateToAggregateAttribute() throws Exception { ST st = new ST(": , \n}>"); // also testing wacky spaces in aggregate spec st.addAggr("items.{ firstName ,lastName, id }", "Ter", "Parr", 99); st.addAggr("items.{firstName, lastName ,id}", "Tom", "Burns", 34); String expecting = "99: Parr, Ter"+newline + "34: Burns, Tom"+newline; assertEquals(expecting, st.render()); } public static class Decl { String name; String type; public Decl(String name, String type) {this.name=name; this.type=type;} public String getName() {return name;} public String getType() {return type;} } @Test public void testComplicatedIndirectTemplateApplication() throws Exception { String templates = "group Java;"+newline + ""+newline + "file(variables) ::= <<\n" + "}; separator=\"\\n\">"+newline + ">>"+newline+ "intdecl(decl) ::= \"int = 0;\""+newline + "intarray(decl) ::= \"int[] = null;\""+newline ; STGroup group = new STGroupString(templates); ST f = group.getInstanceOf("file"); f.addAggr("variables.{ decl,format }", new Decl("i", "int"), "intdecl"); f.addAggr("variables.{decl , format}", new Decl("a", "int-array"), "intarray"); //System.out.println("f='"+f+"'"); String expecting = "int i = 0;" +newline+ "int[] a = null;"; assertEquals(expecting, f.render()); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestBuggyDefaultValueRaisesNPETest.java000066400000000000000000000020701231426731300324260ustar00rootroot00000000000000package org.stringtemplate.v4.test; import org.junit.Assert; import org.junit.Test; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroupFile; import org.stringtemplate.v4.misc.ErrorBuffer; public class TestBuggyDefaultValueRaisesNPETest extends BaseTest { /** * When the anonymous template specified as a default value for a formalArg * contains a syntax error ST 4.0.2 emits a NullPointerException error * (after the syntax error) * * @throws Exception */ @Test public void testHandleBuggyDefaultArgument() throws Exception { String templates = "main(a={(<\"\")>}) ::= \"\""; writeFile(tmpdir, "t.stg", templates); final ErrorBuffer errors = new ErrorBuffer(); STGroup group = new STGroupFile(tmpdir + "/t.stg"); group.setListener(errors); ST st = group.getInstanceOf("main"); String s = st.render(); // Check the errors. This contained an "NullPointerException" before Assert.assertEquals( "t.stg 1:12: mismatched input ')' expecting RDELIM"+newline, errors.toString()); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestCompiler.java000066400000000000000000000544751231426731300262670ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.*; import org.stringtemplate.v4.*; import org.stringtemplate.v4.compiler.*; import org.stringtemplate.v4.compiler.Compiler; import org.stringtemplate.v4.misc.*; import java.util.Arrays; import static org.junit.Assert.assertEquals; public class TestCompiler extends BaseTest { @Before @Override public void setUp() { org.stringtemplate.v4.compiler.Compiler.subtemplateCount = 0; } @Test public void testAttr() throws Exception { String template = "hi "; CompiledST code = new Compiler().compile(template); String asmExpected = "write_str 0, " + "load_attr 1, " + "write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[hi , name]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testInclude() throws Exception { String template = "hi "; CompiledST code = new Compiler().compile(template); String asmExpected = "write_str 0, new 1 0, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[hi , foo]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testIncludeWithPassThrough() throws Exception { String template = "hi "; CompiledST code = new Compiler().compile(template); String asmExpected = "write_str 0, args, passthru 1, new_box_args 1, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[hi , foo]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testIncludeWithPartialPassThrough() throws Exception { String template = "hi "; CompiledST code = new Compiler().compile(template); String asmExpected = "write_str 0, args, load_attr 1, store_arg 2, passthru 3, new_box_args 3, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[hi , y, x, foo]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testSuperInclude() throws Exception { String template = ""; CompiledST code = new Compiler().compile(template); String asmExpected = "super_new 0 0, write"; code.dump(); String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[foo]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testSuperIncludeWithArgs() throws Exception { String template = ""; CompiledST code = new Compiler().compile(template); String asmExpected = "load_attr 0, new 1 0, super_new 2 2, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[a, _sub1, foo]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testSuperIncludeWithNamedArgs() throws Exception { String template = ""; CompiledST code = new Compiler().compile(template); String asmExpected = "args, load_attr 0, store_arg 1, new 2 0, store_arg 3, super_new_box_args 4, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[a, x, _sub1, y, foo]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testIncludeWithArgs() throws Exception { String template = "hi "; CompiledST code = new org.stringtemplate.v4.compiler.Compiler().compile(template); String asmExpected = "write_str 0, load_attr 1, load_attr 2, new 3 2, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[hi , a, b, foo]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testAnonIncludeArgs() throws Exception { String template = "<({ a, b | })>"; CompiledST code = new Compiler().compile(template); String asmExpected = "new 0 0, tostr, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[_sub1]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testAnonIncludeArgMismatch() throws Exception { STErrorListener errors = new ErrorBuffer(); String template = ""; STGroup g = new STGroup(); g.errMgr = new ErrorManager(errors); CompiledST code = new Compiler(g).compile(template); String expected = "1:3: anonymous template has 0 arg(s) but mapped across 1 value(s)"+newline; assertEquals(expected, errors.toString()); } @Test public void testAnonIncludeArgMismatch2() throws Exception { STErrorListener errors = new ErrorBuffer(); String template = ""; STGroup g = new STGroup(); g.errMgr = new ErrorManager(errors); CompiledST code = new Compiler(g).compile(template); String expected = "1:5: anonymous template has 1 arg(s) but mapped across 2 value(s)"+newline; assertEquals(expected, errors.toString()); } @Test public void testAnonIncludeArgMismatch3() throws Exception { STErrorListener errors = new ErrorBuffer(); String template = ""; STGroup g = new STGroup(); g.errMgr = new ErrorManager(errors); CompiledST code = new Compiler(g).compile(template); String expected = "1:11: anonymous template has 0 arg(s) but mapped across 1 value(s)"+newline; assertEquals(expected, errors.toString()); } @Test public void testIndirectIncludeWitArgs() throws Exception { String template = "hi <(foo)(a,b)>"; CompiledST code = new Compiler().compile(template); String asmExpected = "write_str 0, load_attr 1, tostr, load_attr 2, load_attr 3, new_ind 2, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[hi , foo, a, b]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testProp() throws Exception { String template = "hi "; CompiledST code = new Compiler().compile(template); String asmExpected = "write_str 0, load_attr 1, load_prop 2, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[hi , a, b]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testProp2() throws Exception { String template = ": "; CompiledST code = new Compiler().compile(template); String asmExpected = "load_attr 0, load_prop 1, write, write_str 2, " + "load_attr 0, load_prop 3, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[u, id, : , name]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testMap() throws Exception { String template = ""; CompiledST code = new Compiler().compile(template); String asmExpected = "load_attr 0, null, new 1 1, map, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[name, bold]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testMapAsOption() throws Exception { String template = ""; CompiledST code = new Compiler().compile(template); String asmExpected = "load_attr 0, options, load_attr 1, null, new 2 1, map, " + "store_option 4, write_opt"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[a, name, bold]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testMapArg() throws Exception { String template = ""; CompiledST code = new Compiler().compile(template); String asmExpected = "load_attr 0, null, load_attr 1, new 2 2, map, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[name, x, bold]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testIndirectMapArg() throws Exception { String template = ""; CompiledST code = new Compiler().compile(template); String asmExpected = "load_attr 0, load_attr 1, tostr, null, load_attr 2, new_ind 2, map, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[name, t, x]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testRepeatedMap() throws Exception { String template = ""; CompiledST code = new Compiler().compile(template); String asmExpected = "load_attr 0, null, new 1 1, map, null, new 2 1, map, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[name, bold, italics]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testRepeatedMapArg() throws Exception { String template = ""; CompiledST code = new Compiler().compile(template); String asmExpected = "load_attr 0, null, load_attr 1, new 2 2, map, " + "null, load_attr 1, load_attr 3, new 4 3, map, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[name, x, bold, y, italics]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testRotMap() throws Exception { String template = ""; CompiledST code = new Compiler().compile(template); String asmExpected = "load_attr 0, null, new 1 1, null, new 2 1, rot_map 2, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[name, bold, italics]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testRotMapArg() throws Exception { String template = ""; CompiledST code = new Compiler().compile(template); String asmExpected = "load_attr 0, null, load_attr 1, new 2 2, null, new 3 1, rot_map 2, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[name, x, bold, italics]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testZipMap() throws Exception { String template = ""; CompiledST code = new Compiler().compile(template); String asmExpected = "load_attr 0, load_attr 1, null, null, new 2 2, zip_map 2, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[names, phones, bold]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testZipMapArg() throws Exception { String template = ""; CompiledST code = new Compiler().compile(template); String asmExpected = "load_attr 0, load_attr 1, null, null, load_attr 2, new 3 3, zip_map 2, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[names, phones, x, bold]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testAnonMap() throws Exception { String template = "}>"; CompiledST code = new Compiler().compile(template); String asmExpected = "load_attr 0, null, new 1 1, map, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[name, _sub1]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testAnonZipMap() throws Exception { String template = "}>"; CompiledST code = new Compiler().compile(template); String asmExpected = "load_attr 0, load_attr 1, null, null, new 2 2, zip_map 2, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[a, b, _sub1]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testIf() throws Exception { String template = "go: hi, foo"; CompiledST code = new Compiler().compile(template); String asmExpected = "write_str 0, load_attr 1, brf 12, write_str 2"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[go: , name, hi, foo]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testIfElse() throws Exception { String template = "go: hi, foobye"; CompiledST code = new Compiler().compile(template); String asmExpected = "write_str 0, " + "load_attr 1, " + "brf 15, " + "write_str 2, " + "br 18, " + "write_str 3"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[go: , name, hi, foo, bye]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testElseIf() throws Exception { String template = "go: hi, fooa user"; CompiledST code = new Compiler().compile(template); String asmExpected = "write_str 0, " + "load_attr 1, " + "brf 15, " + "write_str 2, " + "br 24, " + "load_attr 3, " + "brf 24, " + "write_str 4"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[go: , name, hi, foo, user, a user]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testElseIfElse() throws Exception { String template = "go: hi, fooa userbye"; CompiledST code = new Compiler().compile(template); String asmExpected = "write_str 0, " + "load_attr 1, " + "brf 15, " + "write_str 2, " + "br 30, " + "load_attr 3, " + "brf 27, " + "write_str 4, " + "br 30, " + "write_str 5"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[go: , name, hi, foo, user, a user, bye]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testOption() throws Exception { String template = "hi "; CompiledST code = new Compiler().compile(template); String asmExpected = "write_str 0, load_attr 1, options, load_str 2, store_option 3, write_opt"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[hi , name, x]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testOptionAsTemplate() throws Exception { String template = "hi "; CompiledST code = new Compiler().compile(template); String asmExpected = "write_str 0, load_attr 1, options, new 2 0, store_option 3, write_opt"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[hi , name, _sub1]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testOptions() throws Exception { String template = "hi "; CompiledST code = new Compiler().compile(template); String asmExpected = "write_str 0, " + "load_attr 1, " + "options, " + "load_str 2, " + "store_option 0, " + "new 3 0, " + "store_option 4, " + "load_str 4, " + "store_option 3, " + "write_opt"; String stringsExpected = // the ", , ," is the ", " separator string "[hi , name, true, foo, , ]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); } @Test public void testEmptyList() throws Exception { String template = "<[]>"; CompiledST code = new Compiler().compile(template); String asmExpected = "list, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testList() throws Exception { String template = "<[a,b]>"; CompiledST code = new Compiler().compile(template); String asmExpected = "list, load_attr 0, add, load_attr 1, add, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[a, b]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testEmbeddedRegion() throws Exception { String template = "<@r>foo<@end>"; // compile as if in root dir and in template 'a' CompiledST code = new Compiler().compile("a", template); String asmExpected = "new 0 0, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[/region__/a__r]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } @Test public void testRegion() throws Exception { String template = "x:<@r()>"; // compile as if in root dir and in template 'a' CompiledST code = new Compiler().compile("a", template); String asmExpected = "write_str 0, new 1 0, write"; String asmResult = code.instrs(); assertEquals(asmExpected, asmResult); String stringsExpected = "[x:, /region__/a__r]"; String stringsResult = Arrays.toString(code.strings); assertEquals(stringsExpected, stringsResult); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestCoreBasics.java000066400000000000000000001051271231426731300265210ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.Test; import org.stringtemplate.v4.AutoIndentWriter; import org.stringtemplate.v4.NoIndentWriter; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroupFile; import org.stringtemplate.v4.STGroupString; import org.stringtemplate.v4.misc.ErrorBuffer; import org.stringtemplate.v4.misc.STNoSuchPropertyException; import org.stringtemplate.v4.misc.STRuntimeMessage; import java.io.StringWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import static org.junit.Assert.assertEquals; public class TestCoreBasics extends BaseTest { @Test public void testNullAttr() throws Exception { String template = "hi !"; ST st = new ST(template); String expected = "hi !"; String result = st.render(); assertEquals(expected, result); } @Test public void testAttr() throws Exception { String template = "hi !"; ST st = new ST(template); st.add("name", "Ter"); String expected = "hi Ter!"; String result = st.render(); assertEquals(expected, result); } @Test public void testChainAttr() throws Exception { String template = ":!"; ST st = new ST(template); st.add("names", "Ter").add("names", "Tom").add("x", 1); String expected = "1:TerTom!"; String result = st.render(); assertEquals(expected, result); } @Test public void testSetUnknownAttr() throws Exception { String templates = "t() ::= <!>>\n"; ErrorBuffer errors = new ErrorBuffer(); writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); ST st = group.getInstanceOf("t"); String result = null; try { st.add("name", "Ter"); } catch (IllegalArgumentException iae) { result = iae.getMessage(); } String expected = "no such attribute: name"; assertEquals(expected, result); } @Test public void testMultiAttr() throws Exception { String template = "hi !"; ST st = new ST(template); st.add("name", "Ter"); st.add("name", "Tom"); String expected = "hi TerTom!"; String result = st.render(); assertEquals(expected, result); } @Test public void testAttrIsList() throws Exception { String template = "hi !"; ST st = new ST(template); List names = new ArrayList() {{add("Ter"); add("Tom");}}; st.add("name", names); st.add("name", "Sumana"); // shouldn't alter my version of names list! String expected = "hi TerTomSumana!"; // ST sees 3 names String result = st.render(); assertEquals(expected, result); assertEquals(2, names.size()); // my names list is still just 2 } @Test public void testAttrIsArray() throws Exception { String template = "hi !"; ST st = new ST(template); String[] names = new String[] {"Ter", "Tom"}; st.add("name", names); st.add("name", "Sumana"); // shouldn't alter my version of names list! String expected = "hi TerTomSumana!"; // ST sees 3 names String result = st.render(); assertEquals(expected, result); } @Test public void testProp() throws Exception { String template = ": "; // checks field and method getter ST st = new ST(template); st.add("u", new User(1, "parrt")); String expected = "1: parrt"; String result = st.render(); assertEquals(expected, result); } @Test public void testPropWithNoAttr() throws Exception { String template = ": "; ST st = new ST(template); st.add("foo", new HashMap() {{put("a","b");}}); String expected = "b: "; String result = st.render(); assertEquals(expected, result); } @Test public void testMapAcrossDictionaryUsesKeys() throws Exception { String template = "}>"; // checks field and method getter ST st = new ST(template); st.add("foo", new LinkedHashMap() {{put("a","b"); put("c","d");}}); String expected = "ac"; String result = st.render(); assertEquals(expected, result); } @Test public void testSTProp() throws Exception { String template = ""; // get x attr of template t ST st = new ST(template); ST t = new ST(""); t.add("x", "Ter"); st.add("t", t); String expected = "Ter"; String result = st.render(); assertEquals(expected, result); } @Test public void testBooleanISProp() throws Exception { String template = ""; // call isManager ST st = new ST(template); st.add("t", new User(32, "Ter")); String expected = "true"; String result = st.render(); assertEquals(expected, result); } @Test public void testBooleanHASProp() throws Exception { String template = ""; // call hasParkingSpot ST st = new ST(template); st.add("t", new User(32, "Ter")); String expected = "true"; String result = st.render(); assertEquals(expected, result); } @Test public void testNullAttrProp() throws Exception { String template = ": "; ST st = new ST(template); String expected = ": "; String result = st.render(); assertEquals(expected, result); } @Test public void testNoSuchProp() throws Exception { ErrorBufferAllErrors errors = new ErrorBufferAllErrors(); String template = ""; STGroup group = new STGroup(); group.setListener(errors); ST st = new ST(group, template); st.add("u", new User(1, "parrt")); String expected = ""; String result = st.render(); assertEquals(expected, result); STRuntimeMessage msg = (STRuntimeMessage)errors.errors.get(0); STNoSuchPropertyException e = (STNoSuchPropertyException)msg.cause; assertEquals("org.stringtemplate.v4.test.BaseTest$User.qqq", e.propertyName); } @Test public void testNullIndirectProp() throws Exception { ErrorBufferAllErrors errors = new ErrorBufferAllErrors(); STGroup group = new STGroup(); group.setListener(errors); String template = ""; ST st = new ST(group, template); st.add("u", new User(1, "parrt")); st.add("qqq", null); String expected = ""; String result = st.render(); assertEquals(expected, result); STRuntimeMessage msg = (STRuntimeMessage)errors.errors.get(0); STNoSuchPropertyException e = (STNoSuchPropertyException)msg.cause; assertEquals("org.stringtemplate.v4.test.BaseTest$User.null", e.propertyName); } @Test public void testPropConvertsToString() throws Exception { ErrorBufferAllErrors errors = new ErrorBufferAllErrors(); STGroup group = new STGroup(); group.setListener(errors); String template = ""; ST st = new ST(group, template); st.add("u", new User(1, "parrt")); st.add("name", 100); String expected = ""; String result = st.render(); assertEquals(expected, result); STRuntimeMessage msg = (STRuntimeMessage)errors.errors.get(0); STNoSuchPropertyException e = (STNoSuchPropertyException)msg.cause; assertEquals("org.stringtemplate.v4.test.BaseTest$User.100", e.propertyName); } @Test public void testInclude() throws Exception { String template = "load ;"; ST st = new ST(template); st.impl.nativeGroup.defineTemplate("box", "kewl" + newline + "daddy"); String expected = "load kewl"+newline+"daddy;"; String result = st.render(); assertEquals(expected, result); } @Test public void testIncludeWithArg() throws Exception { String template = "load ;"; ST st = new ST(template); st.impl.nativeGroup.defineTemplate("box", "x", "kewl daddy"); st.impl.dump(); st.add("name", "Ter"); String expected = "load kewl arg daddy;"; String result = st.render(); assertEquals(expected, result); } @Test public void testIncludeWithEmptySubtemplateArg() throws Exception { String template = "load ;"; ST st = new ST(template); st.impl.nativeGroup.defineTemplate("box", "x", "kewl daddy"); st.impl.dump(); st.add("name", "Ter"); String expected = "load kewl daddy;"; String result = st.render(); assertEquals(expected, result); } @Test public void testIncludeWithArg2() throws Exception { String template = "load ;"; ST st = new ST(template); st.impl.nativeGroup.defineTemplate("box", "x,y", "kewl daddy"); st.impl.nativeGroup.defineTemplate("foo", "blech"); st.add("name", "Ter"); String expected = "load kewl arg blech daddy;"; String result = st.render(); assertEquals(expected, result); } @Test public void testIncludeWithNestedArgs() throws Exception { String template = "load ;"; ST st = new ST(template); st.impl.nativeGroup.defineTemplate("box", "y", "kewl daddy"); st.impl.nativeGroup.defineTemplate("foo", "x", "blech "); st.add("name", "Ter"); String expected = "load kewl blech arg daddy;"; String result = st.render(); assertEquals(expected, result); } @Test public void testPassThru() throws Exception { String templates = "a(x,y) ::= \"\"\n" + "b(x,y) ::= \"\"\n"; STGroup group = new STGroupString(templates); ST a = group.getInstanceOf("a"); a.add("x", "x"); a.add("y", "y"); String expected = "xy"; String result = a.render(); assertEquals(expected, result); } @Test public void testPassThruWithDefaultValue() throws Exception { String templates = "a(x,y) ::= \"\"\n" + // should not set y when it sees "no value" from above "b(x,y={99}) ::= \"\"\n"; STGroup group = new STGroupString(templates); ST a = group.getInstanceOf("a"); a.add("x", "x"); String expected = "x99"; String result = a.render(); assertEquals(expected, result); } @Test public void testPassThruWithDefaultValueThatLacksDefinitionAbove() throws Exception { String templates = "a(x) ::= \"\"\n" + // should not set y when it sees "no definition" from above "b(x,y={99}) ::= \"\"\n"; STGroup group = new STGroupString(templates); ST a = group.getInstanceOf("a"); a.add("x", "x"); String expected = "x99"; String result = a.render(); assertEquals(expected, result); } @Test public void testPassThruPartialArgs() throws Exception { String templates = "a(x,y) ::= \"\"\n" + "b(x,y) ::= \"\"\n"; STGroup group = new STGroupString(templates); ST a = group.getInstanceOf("a"); a.add("x", "x"); a.add("y", "y"); String expected = "x99"; String result = a.render(); assertEquals(expected, result); } @Test public void testPassThruNoMissingArgs() throws Exception { String templates = "a(x,y) ::= \"\"\n" + "b(x,y) ::= \"\"\n"; STGroup group = new STGroupString(templates); ST a = group.getInstanceOf("a"); a.add("x", "x"); a.add("y", "y"); String expected = "199"; String result = a.render(); assertEquals(expected, result); } @Test public void testDefineTemplate() throws Exception { STGroup group = new STGroup(); group.defineTemplate("inc", "x", "+1"); group.defineTemplate("test", "name", "hi !"); ST st = group.getInstanceOf("test"); st.add("name", "Ter"); st.add("name", "Tom"); st.add("name", "Sumana"); String expected = "hi TerTomSumana!"; String result = st.render(); assertEquals(expected, result); } @Test public void testMap() throws Exception { STGroup group = new STGroup(); group.defineTemplate("inc", "x", "[]"); group.defineTemplate("test", "name", "hi !"); ST st = group.getInstanceOf("test"); st.add("name", "Ter"); st.add("name", "Tom"); st.add("name", "Sumana"); String expected = "hi [Ter][Tom][Sumana]!"; String result = st.render(); assertEquals(expected, result); } @Test public void testIndirectMap() throws Exception { STGroup group = new STGroup(); group.defineTemplate("inc", "x", "[]"); group.defineTemplate("test", "t,name", "!"); ST st = group.getInstanceOf("test"); st.add("t", "inc"); st.add("name", "Ter"); st.add("name", "Tom"); st.add("name", "Sumana"); String expected = "[Ter][Tom][Sumana]!"; String result = st.render(); assertEquals(expected, result); } @Test public void testMapWithExprAsTemplateName() throws Exception { String templates = "d ::= [\"foo\":\"bold\"]\n" + "test(name) ::= \"\"\n" + "bold(x) ::= <<**>>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST st = group.getInstanceOf("test"); st.add("name", "Ter"); st.add("name", "Tom"); st.add("name", "Sumana"); String expected = "*Ter**Tom**Sumana*"; String result = st.render(); assertEquals(expected, result); } @Test public void testParallelMap() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "names,phones", "hi :

;}>"); ST st = group.getInstanceOf("test"); st.add("names", "Ter"); st.add("names", "Tom"); st.add("names", "Sumana"); st.add("phones", "x5001"); st.add("phones", "x5002"); st.add("phones", "x5003"); String expected = "hi Ter:x5001;Tom:x5002;Sumana:x5003;"; String result = st.render(); assertEquals(expected, result); } @Test public void testParallelMapWith3Versus2Elements() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "names,phones", "hi :

;}>"); ST st = group.getInstanceOf("test"); st.add("names", "Ter"); st.add("names", "Tom"); st.add("names", "Sumana"); st.add("phones", "x5001"); st.add("phones", "x5002"); String expected = "hi Ter:x5001;Tom:x5002;Sumana:;"; String result = st.render(); assertEquals(expected, result); } @Test public void testParallelMapThenMap() throws Exception { STGroup group = new STGroup(); group.defineTemplate("bold", "x", "[]"); group.defineTemplate("test", "names,phones", "hi :

;}:bold()>"); ST st = group.getInstanceOf("test"); st.add("names", "Ter"); st.add("names", "Tom"); st.add("names", "Sumana"); st.add("phones", "x5001"); st.add("phones", "x5002"); String expected = "hi [Ter:x5001;][Tom:x5002;][Sumana:;]"; String result = st.render(); assertEquals(expected, result); } @Test public void testMapThenParallelMap() throws Exception { STGroup group = new STGroup(); group.defineTemplate("bold", "x", "[]"); group.defineTemplate("test", "names,phones", "hi <[names:bold()],phones:{n,p | :

;}>"); ST st = group.getInstanceOf("test"); st.add("names", "Ter"); st.add("names", "Tom"); st.add("names", "Sumana"); st.add("phones", "x5001"); st.add("phones", "x5002"); String expected = "hi [Ter]:x5001;[Tom]:x5002;[Sumana]:;"; String result = st.render(); assertEquals(expected, result); } @Test public void testMapIndexes() throws Exception { STGroup group = new STGroup(); group.defineTemplate("inc", "x,i", ":"); group.defineTemplate("test", "name", "}; separator=\", \">"); ST st = group.getInstanceOf("test"); st.add("name", "Ter"); st.add("name", "Tom"); st.add("name", null); // don't count this one st.add("name", "Sumana"); String expected = "1:Ter, 2:Tom, 3:Sumana"; String result = st.render(); assertEquals(expected, result); } @Test public void testMapIndexes2() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "name", ":}; separator=\", \">"); ST st = group.getInstanceOf("test"); st.add("name", "Ter"); st.add("name", "Tom"); st.add("name", null); // don't count this one. still can't apply subtemplate to null value st.add("name", "Sumana"); String expected = "1:Ter, 2:Tom, 3:Sumana"; String result = st.render(); assertEquals(expected, result); } @Test public void testMapSingleValue() throws Exception { STGroup group = new STGroup(); group.defineTemplate("a", "x", "[]"); group.defineTemplate("test", "name", "hi !"); ST st = group.getInstanceOf("test"); st.add("name", "Ter"); String expected = "hi [Ter]!"; String result = st.render(); assertEquals(expected, result); } @Test public void testMapNullValue() throws Exception { STGroup group = new STGroup(); group.defineTemplate("a", "x", "[]"); group.defineTemplate("test", "name", "hi !"); ST st = group.getInstanceOf("test"); String expected = "hi !"; String result = st.render(); assertEquals(expected, result); } @Test public void testMapNullValueInList() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "name", ""); ST st = group.getInstanceOf("test"); st.add("name", "Ter"); st.add("name", "Tom"); st.add("name", null); // don't print this one st.add("name", "Sumana"); String expected = "Ter, Tom, Sumana"; String result = st.render(); assertEquals(expected, result); } @Test public void testRepeatedMap() throws Exception { STGroup group = new STGroup(); group.defineTemplate("a", "x", "[]"); group.defineTemplate("b", "x", "()"); group.defineTemplate("test", "name", "hi !"); ST st = group.getInstanceOf("test"); st.add("name", "Ter"); st.add("name", "Tom"); st.add("name", "Sumana"); String expected = "hi ([Ter])([Tom])([Sumana])!"; String result = st.render(); assertEquals(expected, result); } @Test public void testRepeatedMapWithNullValue() throws Exception { STGroup group = new STGroup(); group.defineTemplate("a", "x", "[]"); group.defineTemplate("b", "x", "()"); group.defineTemplate("test", "name", "hi !"); ST st = group.getInstanceOf("test"); st.add("name", "Ter"); st.add("name", null); st.add("name", "Sumana"); String expected = "hi ([Ter])([Sumana])!"; String result = st.render(); assertEquals(expected, result); } @Test public void testRepeatedMapWithNullValueAndNullOption() throws Exception { STGroup group = new STGroup(); group.defineTemplate("a", "x", "[]"); group.defineTemplate("b", "x", "()"); group.defineTemplate("test", "name", "hi !"); ST st = group.getInstanceOf("test"); st.add("name", "Ter"); st.add("name", null); st.add("name", "Sumana"); String expected = "hi ([Ter])x([Sumana])!"; String result = st.render(); assertEquals(expected, result); } @Test public void testRoundRobinMap() throws Exception { STGroup group = new STGroup(); group.defineTemplate("a", "x", "[]"); group.defineTemplate("b", "x", "()"); group.defineTemplate("test", "name", "hi !"); ST st = group.getInstanceOf("test"); st.add("name", "Ter"); st.add("name", "Tom"); st.add("name", "Sumana"); String expected = "hi [Ter](Tom)[Sumana]!"; String result = st.render(); assertEquals(expected, result); } @Test public void testTrueCond() throws Exception { String template = "works"; ST st = new ST(template); st.add("name", "Ter"); String expected = "works"; String result = st.render(); assertEquals(expected, result); } @Test public void testEmptyIFTemplate() throws Exception { String template = "fail"; ST st = new ST(template); st.add("name", "Ter"); String expected = ""; String result = st.render(); assertEquals(expected, result); } @Test public void testCondParens() throws Exception { String template = "works"; ST st = new ST(template); String expected = "works"; String result = st.render(); assertEquals(expected, result); } @Test public void testFalseCond() throws Exception { String template = "works"; ST st = new ST(template); String expected = ""; String result = st.render(); assertEquals(expected, result); } @Test public void testFalseCond2() throws Exception { String template = "works"; ST st = new ST(template); st.add("name", null); String expected = ""; String result = st.render(); assertEquals(expected, result); } @Test public void testFalseCondWithFormalArgs() throws Exception { // insert of indent instr was not working; ok now String dir = getRandomDir(); String groupFile = "a(scope) ::= <<" +newline+ "foo" +newline+ " oops" +newline+ "bar" +newline+ ">>"; writeFile(dir, "group.stg", groupFile); STGroupFile group = new STGroupFile(dir+"/group.stg"); ST st = group.getInstanceOf("a"); st.impl.dump(); String expected = "foo" +newline+ "bar"; String result = st.render(); assertEquals(expected, result); } @Test public void testElseIf2() throws Exception { String template = "fail1fail2worksfail3"; ST st = new ST(template); st.add("z", "blort"); String expected = "works"; String result = st.render(); assertEquals(expected, result); } @Test public void testElseIf3() throws Exception { String template = "works"; ST st = new ST(template); st.add("z", "blort"); String expected = "works"; String result = st.render(); assertEquals(expected, result); } @Test public void testNotTrueCond() throws Exception { String template = "works"; ST st = new ST(template); st.add("name", "Ter"); String expected = ""; String result = st.render(); assertEquals(expected, result); } @Test public void testNotFalseCond() throws Exception { String template = "works"; ST st = new ST(template); String expected = "works"; String result = st.render(); assertEquals(expected, result); } @Test public void testParensInConditonal() throws Exception { String template = "works"; ST st = new ST(template); st.add("a", true); st.add("b", true); st.add("c", true); st.add("d", true); String expected = "works"; String result = st.render(); assertEquals(expected, result); } @Test public void testParensInConditonal2() throws Exception { String template = "brokenworks"; ST st = new ST(template); st.add("a", true); st.add("b", true); st.add("c", true); st.add("d", true); String expected = "works"; String result = st.render(); assertEquals(expected, result); } @Test public void testTrueCondWithElse() throws Exception { String template = "worksfail"; ST st = new ST(template); st.add("name", "Ter"); String expected = "works"; String result = st.render(); assertEquals(expected, result); } @Test public void testFalseCondWithElse() throws Exception { String template = "failworks"; ST st = new ST(template); String expected = "works"; String result = st.render(); assertEquals(expected, result); } @Test public void testElseIf() throws Exception { String template = "failworksfail"; ST st = new ST(template); st.add("id", "2DF3DF"); String expected = "works"; String result = st.render(); assertEquals(expected, result); } @Test public void testElseIfNoElseAllFalse() throws Exception { String template = "failfail"; ST st = new ST(template); String expected = ""; String result = st.render(); assertEquals(expected, result); } @Test public void testElseIfAllExprFalse() throws Exception { String template = "failfailworks"; ST st = new ST(template); String expected = "works"; String result = st.render(); assertEquals(expected, result); } @Test public void testOr() throws Exception { String template = "worksfail"; ST st = new ST(template); st.add("name", "Ter"); String expected = "works"; String result = st.render(); assertEquals(expected, result); } @Test public void testMapConditionAndEscapeInside() throws Exception { String template = "works \\\\"; ST st = new ST(template); Map m = new HashMap(); m.put("name", "Ter"); st.add("m", m); String expected = "works \\"; String result = st.render(); assertEquals(expected, result); } @Test public void testAnd() throws Exception { String template = "failworks"; ST st = new ST(template); st.add("name", "Ter"); String expected = "works"; String result = st.render(); assertEquals(expected, result); } @Test public void testAndNot() throws Exception { String template = "worksfail"; ST st = new ST(template); st.add("name", "Ter"); String expected = "works"; String result = st.render(); assertEquals(expected, result); } @Test public void testCharLiterals() throws Exception { ST st = new ST( "Foo <\\n><\\n><\\t> bar\n" ); StringWriter sw = new StringWriter(); st.write(new AutoIndentWriter(sw,"\n")); // force \n as newline String result = sw.toString(); String expecting ="Foo \n\n\t bar\n"; // expect \n in output assertEquals(expecting, result); st = new ST( "Foo <\\n><\\t> bar" +newline); sw = new StringWriter(); st.write(new AutoIndentWriter(sw,"\n")); // force \n as newline expecting ="Foo \n\t bar\n"; // expect \n in output result = sw.toString(); assertEquals(expecting, result); st = new ST( "Foo<\\ >bar<\\n>"); sw = new StringWriter(); st.write(new AutoIndentWriter(sw,"\n")); // force \n as newline result = sw.toString(); expecting ="Foo bar\n"; // forced \n assertEquals(expecting, result); } @Test public void testUnicodeLiterals() throws Exception { ST st = new ST( "Foo <\\uFEA5><\\n><\\u00C2> bar\n" ); String expecting ="Foo \ufea5"+newline+"\u00C2 bar"+newline; String result = st.render(); assertEquals(expecting, result); st = new ST( "Foo <\\uFEA5><\\n><\\u00C2> bar" +newline); expecting ="Foo \ufea5"+newline+"\u00C2 bar"+newline; result = st.render(); assertEquals(expecting, result); st = new ST( "Foo<\\ >bar<\\n>"); expecting ="Foo bar"+newline; result = st.render(); assertEquals(expecting, result); } @Test public void testSubtemplateExpr() throws Exception { String template = "<{name\n}>"; ST st = new ST(template); String expected = "name"+newline; String result = st.render(); assertEquals(expected, result); } @Test public void testSeparator() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "names", "}; separator=\", \">"); ST st = group.getInstanceOf("test"); st.add("names", "Ter"); st.add("names", "Tom"); String expected = "case Ter, case Tom"; String result = st.render(); assertEquals(expected, result); } @Test public void testSeparatorInList() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "names", "}; separator=\", \">"); ST st = group.getInstanceOf("test"); st.add("names", new ArrayList() {{ add("Ter"); add("Tom"); }}); String expected = "case Ter, case Tom"; String result = st.render(); assertEquals(expected, result); } @Test public void testSeparatorInList2() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "names", "}; separator=\", \">"); ST st = group.getInstanceOf("test"); st.add("names", "Ter"); st.add("names", new ArrayList() {{ add("Tom"); add("Sriram"); }}); String expected = "case Ter, case Tom, case Sriram"; String result = st.render(); assertEquals(expected, result); } @Test public void testSeparatorInArray() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "names", "}; separator=\", \">"); ST st = group.getInstanceOf("test"); st.add("names", new String[] { "Ter", "Tom" }); String expected = "case Ter, case Tom"; String result = st.render(); assertEquals(expected, result); } @Test public void testSeparatorInArray2() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "names", "}; separator=\", \">"); ST st = group.getInstanceOf("test"); st.add("names", "Ter"); st.add("names", new String[] { "Tom", "Sriram" }); String expected = "case Ter, case Tom, case Sriram"; String result = st.render(); assertEquals(expected, result); } @Test public void testSeparatorInPrimitiveArray() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "names", "}; separator=\", \">"); ST st = group.getInstanceOf("test"); st.add("names", new int[] { 0, 1 }); String expected = "case 0, case 1"; String result = st.render(); assertEquals(expected, result); } @Test public void testSeparatorInPrimitiveArray2() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "names", "}; separator=\", \">"); ST st = group.getInstanceOf("test"); st.add("names", 0); st.add("names", new int[] { 1, 2 }); String expected = "case 0, case 1, case 2"; String result = st.render(); assertEquals(expected, result); } /** (...) forces early eval to string. early eval {@code <(x)>} using new * STWriter derived from type of current STWriter. e.g., AutoIndentWriter. */ @Test public void testEarlyEvalIndent() throws Exception { String templates = "t() ::= << abc>>\n" + "main() ::= <<\n" + "\n" + "<(t())>\n" + // early eval ignores indents; mostly for simply strings " \n" + " <(t())>\n" + ">>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST st = group.getInstanceOf("main"); String result = st.render(); String expected = " abc" + newline + " abc" + newline + " abc" + newline + " abc"; assertEquals(expected, result); } @Test public void testEarlyEvalNoIndent() throws Exception { String templates = "t() ::= << abc>>\n" + "main() ::= <<\n" + "\n" + "<(t())>\n" + // early eval ignores indents; mostly for simply strings " \n" + " <(t())>\n" + ">>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST st = group.getInstanceOf("main"); StringWriter sw = new StringWriter(); NoIndentWriter w = new NoIndentWriter(sw); st.write(w); String result = sw.toString(); String expected = "abc" + newline + "abc" + newline + "abc" + newline + "abc"; assertEquals(expected, result); } @Test public void testArrayOfTemplates() throws Exception { String template = "!"; ST st = new ST(template); ST[] t = new ST[] {new ST("hi"), new ST("mom")}; st.add("foo", t); String expected = "himom!"; String result = st.render(); assertEquals(expected, result); } @Test public void testArrayOfTemplatesInTemplate() throws Exception { String template = "!"; ST st = new ST(template); ST[] t = new ST[] {new ST("hi"), new ST("mom")}; st.add("foo", t); ST wrapper = new ST(""); wrapper.add("x", st); String expected = "himom!"; String result = wrapper.render(); assertEquals(expected, result); } @Test public void testListOfTemplates() throws Exception { String template = "!"; ST st = new ST(template); List t = new ArrayList() {{add(new ST("hi")); add(new ST("mom"));}}; st.add("foo", t); String expected = "himom!"; String result = st.render(); assertEquals(expected, result); } @Test public void testListOfTemplatesInTemplate() throws Exception { String template = "!"; ST st = new ST(template); List t = new ArrayList() {{add(new ST("hi")); add(new ST("mom"));}}; st.add("foo", t); ST wrapper = new ST(""); wrapper.add("x", st); String expected = "himom!"; String result = wrapper.render(); assertEquals(expected, result); } @Test public void playing() throws Exception { String template = ""; ST st = new ST(template); st.impl.dump(); } @Test public void testPrototype() { ST prototype = new ST("simple template"); ST st = new ST(prototype); st.add("arg1", "value"); assertEquals("simple template", st.render()); ST st2 = new ST(prototype); st2.add("arg1", "value"); assertEquals("simple template", st2.render()); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestDebugEvents.java000066400000000000000000000121621231426731300267130ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.Test; import org.stringtemplate.v4.*; import org.stringtemplate.v4.debug.InterpEvent; import java.util.List; import static org.junit.Assert.assertEquals; public class TestDebugEvents extends BaseTest { @Test public void testString() throws Exception { String templates = "t() ::= <>" + newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST st = group.getInstanceOf("t"); List events = st.getEvents(); String expected = "[EvalExprEvent{self=/t(), expr='foo', exprStartChar=0, exprStopChar=2, start=0, stop=2}," + " EvalTemplateEvent{self=/t(), start=0, stop=2}]"; String result = events.toString(); assertEquals(expected, result); } @Test public void testAttribute() throws Exception { String templates = "t(x) ::= << >>" + newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST st = group.getInstanceOf("t"); List events = st.getEvents(); String expected = "[IndentEvent{self=/t(), expr=' ', exprStartChar=0, exprStopChar=0, start=0, stop=0}," + " EvalExprEvent{self=/t(), expr='', exprStartChar=1, exprStopChar=3, start=0, stop=-1}," + " EvalExprEvent{self=/t(), expr=' ', exprStartChar=4, exprStopChar=4, start=0, stop=0}," + " EvalTemplateEvent{self=/t(), start=0, stop=0}]"; String result = events.toString(); assertEquals(expected, result); } @Test public void testTemplateCall() throws Exception { String templates = "t(x) ::= <<[]>>\n" + "u() ::= << >>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST st = group.getInstanceOf("t"); group.getInstanceOf("u").impl.dump(); List events = st.getEvents(); String expected = "[EvalExprEvent{self=/t(), expr='[', exprStartChar=0, exprStopChar=0, start=0, stop=0}," + " IndentEvent{self=/u(), expr=' ', exprStartChar=0, exprStopChar=0, start=1, stop=1}," + " EvalExprEvent{self=/u(), expr='', exprStartChar=1, exprStopChar=3, start=1, stop=0}," + " EvalExprEvent{self=/u(), expr=' ', exprStartChar=4, exprStopChar=4, start=1, stop=1}," + " EvalTemplateEvent{self=/u(), start=1, stop=1}," + " EvalExprEvent{self=/t(), expr=''," + " exprStartChar=1, exprStopChar=5, start=1, stop=1}," + " EvalExprEvent{self=/t(), expr=']'," + " exprStartChar=6, exprStopChar=6, start=2, stop=2}," + " EvalTemplateEvent{self=/t(), start=0, stop=2}]"; String result = events.toString(); assertEquals(expected, result); } @Test public void testEvalExprEventForSpecialCharacter() throws Exception { String templates = "t() ::= <<[<\\n>]>>\n"; // 012 345 // Rendering t() emits: "[\n]" or "[\r\n]" (depends on line.separator) // 01 2 01 2 3 STGroupString g = new STGroupString(templates); ST st = g.getInstanceOf("t"); st.impl.dump(); List events = st.getEvents(); int n = newline.length(); String expected = "[EvalExprEvent{self=/t(), expr='[', exprStartChar=0, exprStopChar=0, start=0, stop=0}, " + "EvalExprEvent{self=/t(), expr='\\n', exprStartChar=2, exprStopChar=3, start=1, stop="+n+"}, " + "EvalExprEvent{self=/t(), expr=']', exprStartChar=5, exprStopChar=5, start="+(n+1)+", stop="+(n+1)+"}, " + "EvalTemplateEvent{self=/t(), start=0, stop="+(n+1)+"}]"; String result = events.toString(); assertEquals(expected, result); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestDictionaries.java000066400000000000000000000421311231426731300271140ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.Assert; import org.junit.Test; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroupFile; import org.stringtemplate.v4.STGroupString; import org.stringtemplate.v4.misc.ErrorBuffer; import java.io.File; import java.util.HashMap; import java.util.Map; import static org.junit.Assert.assertEquals; public class TestDictionaries extends BaseTest { @Test public void testDict() throws Exception { String templates = "typeInit ::= [\"int\":\"0\", \"float\":\"0.0\"] "+newline+ "var(type,name) ::= \" = ;\""+newline ; writeFile(tmpdir, "test.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"test.stg"); ST st = group.getInstanceOf("var"); st.add("type", "int"); st.add("name", "x"); String expecting = "int x = 0;"; String result = st.render(); assertEquals(expecting, result); } @Test public void testDictValuesAreTemplates() throws Exception { String templates = "typeInit ::= [\"int\":{0}, \"float\":{0.0}] "+newline+ "var(type,w,name) ::= \" = ;\""+newline ; writeFile(tmpdir, "test.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"test.stg"); ST st = group.getInstanceOf("var"); st.impl.dump(); st.add("w", "L"); st.add("type", "int"); st.add("name", "x"); String expecting = "int x = 0L;"; String result = st.render(); assertEquals(expecting, result); } @Test public void testDictKeyLookupViaTemplate() throws Exception { // Make sure we try rendering stuff to string if not found as regular object String templates = "typeInit ::= [\"int\":{0}, \"float\":{0.0}] "+newline+ "var(type,w,name) ::= \" = ;\""+newline ; writeFile(tmpdir, "test.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"test.stg"); ST st = group.getInstanceOf("var"); st.add("w", "L"); st.add("type", new ST("int")); st.add("name", "x"); String expecting = "int x = 0L;"; String result = st.render(); assertEquals(expecting, result); } @Test public void testDictKeyLookupAsNonToStringableObject() throws Exception { // Make sure we try rendering stuff to string if not found as regular object String templates = "foo(m,k) ::= \"\""+newline ; writeFile(tmpdir, "test.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"test.stg"); ST st = group.getInstanceOf("foo"); Map m = new HashMap(); m.put(new HashableUser(99,"parrt"), "first"); m.put(new HashableUser(172036,"tombu"), "second"); m.put(new HashableUser(391,"sriram"), "third"); st.add("m", m); st.add("k", new HashableUser(172036,"tombu")); String expecting = "second"; String result = st.render(); assertEquals(expecting, result); } @Test public void testDictMissingDefaultValueIsEmpty() throws Exception { String templates = "typeInit ::= [\"int\":\"0\", \"float\":\"0.0\"] "+newline+ "var(type,w,name) ::= \" = ;\""+newline ; writeFile(tmpdir, "test.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"test.stg"); ST st = group.getInstanceOf("var"); st.add("w", "L"); st.add("type", "double"); // double not in typeInit map st.add("name", "x"); String expecting = "double x = ;"; String result = st.render(); assertEquals(expecting, result); } @Test public void testDictMissingDefaultValueIsEmptyForNullKey() throws Exception { String templates = "typeInit ::= [\"int\":\"0\", \"float\":\"0.0\"] "+newline+ "var(type,w,name) ::= \" = ;\""+newline ; writeFile(tmpdir, "test.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"test.stg"); ST st = group.getInstanceOf("var"); st.add("w", "L"); st.add("type", null); // double not in typeInit map st.add("name", "x"); String expecting = " x = ;"; String result = st.render(); assertEquals(expecting, result); } @Test public void testDictHiddenByFormalArg() throws Exception { String templates = "typeInit ::= [\"int\":\"0\", \"float\":\"0.0\"] "+newline+ "var(typeInit,type,name) ::= \" = ;\""+newline ; writeFile(tmpdir, "test.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"test.stg"); ST st = group.getInstanceOf("var"); st.add("type", "int"); st.add("name", "x"); String expecting = "int x = ;"; String result = st.render(); assertEquals(expecting, result); } @Test public void testDictEmptyValueAndAngleBracketStrings() throws Exception { String templates = "typeInit ::= [\"int\":\"0\", \"float\":, \"double\":<<0.0L>>] "+newline+ "var(type,name) ::= \" = ;\""+newline ; writeFile(tmpdir, "test.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"test.stg"); ST st = group.getInstanceOf("var"); st.add("type", "float"); st.add("name", "x"); String expecting = "float x = ;"; String result = st.render(); assertEquals(expecting, result); } @Test public void testDictDefaultValue() throws Exception { String templates = "typeInit ::= [\"int\":\"0\", default:\"null\"] "+newline+ "var(type,name) ::= \" = ;\""+newline ; writeFile(tmpdir, "test.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"test.stg"); ST st = group.getInstanceOf("var"); st.add("type", "UserRecord"); st.add("name", "x"); String expecting = "UserRecord x = null;"; String result = st.render(); assertEquals(expecting, result); } @Test public void testDictNullKeyGetsDefaultValue() throws Exception { String templates = "typeInit ::= [\"int\":\"0\", default:\"null\"] "+newline+ "var(type,name) ::= \" = ;\""+newline ; writeFile(tmpdir, "test.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"test.stg"); ST st = group.getInstanceOf("var"); // missing or set to null: st.add("type", null); st.add("name", "x"); String expecting = " x = null;"; String result = st.render(); assertEquals(expecting, result); } @Test public void testDictEmptyDefaultValue() throws Exception { String templates = "typeInit ::= [\"int\":\"0\", default:] "+newline+ "var(type,name) ::= \" = ;\""+newline ; writeFile(tmpdir, "test.stg", templates); ErrorBuffer errors = new ErrorBuffer(); STGroupFile group = new STGroupFile(tmpdir+"/"+"test.stg"); group.setListener(errors); group.load(); String expected = "[test.stg 1:33: missing value for key at ']']"; String result = errors.errors.toString(); assertEquals(expected, result); } @Test public void testDictDefaultValueIsKey() throws Exception { String templates = "typeInit ::= [\"int\":\"0\", default:key] "+newline+ "var(type,name) ::= \" = ;\""+newline ; writeFile(tmpdir, "test.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"test.stg"); ST st = group.getInstanceOf("var"); st.add("type", "UserRecord"); st.add("name", "x"); String expecting = "UserRecord x = UserRecord;"; String result = st.render(); assertEquals(expecting, result); } /** * Test that a map can have only the default entry. */ @Test public void testDictDefaultStringAsKey() throws Exception { String templates = "typeInit ::= [\"default\":\"foo\"] "+newline+ "var(type,name) ::= \" = ;\""+newline ; writeFile(tmpdir, "test.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"test.stg"); ST st = group.getInstanceOf("var"); st.add("type", "default"); st.add("name", "x"); String expecting = "default x = foo;"; String result = st.render(); assertEquals(expecting, result); } /** * Test that a map can return a string with the word: default. */ @Test public void testDictDefaultIsDefaultString() throws Exception { String templates = "map ::= [default: \"default\"] "+newline+ "t() ::= << >>"+newline ; writeFile(tmpdir, "test.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"test.stg"); ST st = group.getInstanceOf("t"); String expecting = " default "; String result = st.render(); assertEquals(expecting, result); } @Test public void testDictViaEnclosingTemplates() throws Exception { String templates = "typeInit ::= [\"int\":\"0\", \"float\":\"0.0\"] "+newline+ "intermediate(type,name) ::= \"\""+newline+ "var(type,name) ::= \" = ;\""+newline ; writeFile(tmpdir, "test.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"test.stg"); ST st = group.getInstanceOf("intermediate"); st.add("type", "int"); st.add("name", "x"); String expecting = "int x = 0;"; String result = st.render(); assertEquals(expecting, result); } @Test public void testDictViaEnclosingTemplates2() throws Exception { String templates = "typeInit ::= [\"int\":\"0\", \"float\":\"0.0\"] "+newline+ "intermediate(stuff) ::= \"\""+newline+ "var(type,name) ::= \" = ;\""+newline ; writeFile(tmpdir, "test.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"test.stg"); ST interm = group.getInstanceOf("intermediate"); ST var = group.getInstanceOf("var"); var.add("type", "int"); var.add("name", "x"); interm.add("stuff", var); String expecting = "int x = 0;"; String result = interm.render(); assertEquals(expecting, result); } @Test public void TestAccessDictionaryFromAnonymousTemplate() { String dir = tmpdir; String g = "a() ::= <<[<[\"foo\",\"a\"]:{x|}>]>>\n" + "values ::= [\n" + " \"a\":false,\n" + " default:true\n" + "]\n"; writeFile(dir, "g.stg", g); STGroup group = new STGroupFile(tmpdir+"/"+"g.stg"); ST st = group.getInstanceOf("a"); String expected = "[foo]"; String result = st.render(); assertEquals(expected, result); } @Test public void TestAccessDictionaryFromAnonymousTemplateInRegion() { String dir = tmpdir; String g = "a() ::= <<[<@r()>]>>\n" + "@a.r() ::= <<\n" + "<[\"foo\",\"a\"]:{x|}>\n" + ">>\n" + "values ::= [\n" + " \"a\":false,\n" + " default:true\n" + "]\n"; writeFile(dir, "g.stg", g); STGroup group = new STGroupFile(tmpdir+"/"+"g.stg"); ST st = group.getInstanceOf("a"); String expected = "[foo]"; String result = st.render(); assertEquals(expected, result); } @Test public void testImportDictionary() throws Exception { String Root = "d ::= [\"a\":\"b\"]\n"; String Sub = "t() ::= <<\n" + "\n" + ">>\n"; STGroup r = new STGroupString(Root); STGroup s = new STGroupString(Sub); s.importTemplates(r); ST st = s.getInstanceOf("t"); // visible only if we can see inherited dicts String expected = "b"; String result = st.render(); assertEquals(expected, result); } @Test public void testStringsInDictionary() throws Exception { String templates = "auxMap ::= [\n" + " \"E\": \"electric \",\n" + " \"I\": \"in between\",\n" + " \"F\": \" force\",\n" + " default: \"\"\n" + "]\n" + "\n" + "makeTmpl(type, field) ::= <<\n" + "\n" + ">>\n" + "\n" + "top() ::= <<\n" + " \n" + " \n" + " \n" + ">>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir + File.separatorChar + "t.stg"); ST st = group.getInstanceOf("top"); Assert.assertNotNull(st); String expecting = " electric " + newline + " force" + newline + " in between"; Assert.assertEquals(expecting, st.render()); } @Test public void testTemplatesInDictionary() throws Exception { String templates = "auxMap ::= [\n" + " \"E\": {electric },\n" + " \"I\": {in between},\n" + " \"F\": { force},\n" + " default: {}\n" + "]\n" + "\n" + "makeTmpl(type, field) ::= <<\n" + "\n" + ">>\n" + "\n" + "top() ::= <<\n" + " \n" + " \n" + " \n" + ">>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir + File.separatorChar + "t.stg"); ST st = group.getInstanceOf("top"); Assert.assertNotNull(st); String expecting = " electric foo" + newline + " foo force" + newline + " in foo between"; Assert.assertEquals(expecting, st.render()); } @Test public void testDictionaryBehaviorTrue() throws Exception { String templates = "d ::= [\n" + " \"x\" : true,\n" + " default : false,\n" + "]\n" + "\n" + "t() ::= <<\n" + "+-\n" + ">>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir + File.separatorChar + "t.stg"); ST st = group.getInstanceOf("t"); String expected = "true+"; String result = st.render(); assertEquals(expected, result); } @Test public void testDictionaryBehaviorFalse() throws Exception { String templates = "d ::= [\n" + " \"x\" : false,\n" + " default : false,\n" + "]\n" + "\n" + "t() ::= <<\n" + "+-\n" + ">>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir + File.separatorChar + "t.stg"); ST st = group.getInstanceOf("t"); String expected = "false-"; String result = st.render(); assertEquals(expected, result); } @Test public void testDictionaryBehaviorEmptyTemplate() throws Exception { String templates = "d ::= [\n" + " \"x\" : {},\n" + " default : false,\n" + "]\n" + "\n" + "t() ::= <<\n" + "+-\n" + ">>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir + File.separatorChar + "t.stg"); ST st = group.getInstanceOf("t"); String expected = "+"; String result = st.render(); assertEquals(expected, result); } @Test public void testDictionaryBehaviorEmptyList() throws Exception { String templates = "d ::= [\n" + " \"x\" : [],\n" + " default : false\n" + "]\n" + "\n" + "t() ::= <<\n" + "+-\n" + ">>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir + File.separatorChar + "t.stg"); ST st = group.getInstanceOf("t"); String expected = "-"; String result = st.render(); assertEquals(expected, result); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestDollarDelimiters.java000066400000000000000000000231411231426731300277360ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2010 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.Assert; import org.junit.Test; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroupFile; import org.stringtemplate.v4.STGroupString; import static org.junit.Assert.assertEquals; public class TestDollarDelimiters extends BaseTest { @Test public void testAttr() throws Exception { String template = "hi $name$!"; ST st = new org.stringtemplate.v4.ST(template, '$', '$'); st.add("name", "Ter"); String expected = "hi Ter!"; String result = st.render(); assertEquals(expected, result); } @Test public void testParallelMap() throws Exception { STGroup group = new org.stringtemplate.v4.STGroup('$', '$'); group.defineTemplate("test", "names,phones", "hi $names,phones:{n,p | $n$:$p$;}$"); ST st = group.getInstanceOf("test"); st.add("names", "Ter"); st.add("names", "Tom"); st.add("names", "Sumana"); st.add("phones", "x5001"); st.add("phones", "x5002"); st.add("phones", "x5003"); String expected = "hi Ter:x5001;Tom:x5002;Sumana:x5003;"; String result = st.render(); assertEquals(expected, result); } @Test public void testRefToAnotherTemplateInSameGroup() throws Exception { String dir = getRandomDir(); String a = "a() ::= << <$b()$> >>\n"; String b = "b() ::= <>\n"; writeFile(dir, "a.st", a); writeFile(dir, "b.st", b); STGroup group = new org.stringtemplate.v4.STGroupDir(dir, '$', '$'); org.stringtemplate.v4.ST st = group.getInstanceOf("a"); String expected = " "; String result = st.render(); assertEquals(expected, result); } @Test public void testDefaultArgument() throws Exception { String templates = "method(name) ::= <<"+newline+ "$stat(name)$" +newline+ ">>"+newline+ "stat(name,value=\"99\") ::= \"x=$value$; // $name$\""+newline ; writeFile(tmpdir, "group.stg", templates); org.stringtemplate.v4.STGroup group = new STGroupFile(tmpdir+"/group.stg", '$', '$'); org.stringtemplate.v4.ST b = group.getInstanceOf("method"); b.add("name", "foo"); String expecting = "x=99; // foo"; String result = b.render(); assertEquals(expecting, result); } /** * This is part of a regression test for antlr/stringtemplate4#46. * https://github.com/antlr/stringtemplate4/issues/46 */ @Test public void testDelimitersClause() throws Exception { String templates = "delimiters \"$\", \"$\""+newline+ "method(name) ::= <<"+newline+ "$stat(name)$" +newline+ ">>"+newline+ "stat(name,value=\"99\") ::= \"x=$value$; // $name$\""+newline ; writeFile(tmpdir, "group.stg", templates); STGroup group = new STGroupFile(tmpdir+"/group.stg"); ST b = group.getInstanceOf("method"); b.add("name", "foo"); String expecting = "x=99; // foo"; String result = b.render(); assertEquals(expecting, result); } /** * This is part of a regression test for antlr/stringtemplate4#46. * https://github.com/antlr/stringtemplate4/issues/46 */ @Test public void testDelimitersClauseInGroupString() throws Exception { String templates = "delimiters \"$\", \"$\""+newline+ "method(name) ::= <<"+newline+ "$stat(name)$" +newline+ ">>"+newline+ "stat(name,value=\"99\") ::= \"x=$value$; // $name$\""+newline ; STGroup group = new STGroupString(templates); ST b = group.getInstanceOf("method"); b.add("name", "foo"); String expecting = "x=99; // foo"; String result = b.render(); assertEquals(expecting, result); } /** * This is part of a regression test for antlr/stringtemplate4#66. * https://github.com/antlr/stringtemplate4/issues/66 */ @Test public void testImportTemplatePreservesDelimiters() { String groupFile = "group GenerateHtml;" + newline + "import \"html.st\"" + newline + "entry() ::= <<" + newline + "$html()$" + newline + ">>" + newline; String htmlFile = "html() ::= <<" + newline + "" + newline + ">>" + newline; String dir = getRandomDir(); writeFile(dir, "GenerateHtml.stg", groupFile); writeFile(dir, "html.st", htmlFile); STGroup group = new STGroupFile(dir + "/GenerateHtml.stg", '$', '$'); // test html template directly ST st = group.getInstanceOf("html"); Assert.assertNotNull(st); String expected = "
"; String result = st.render(); assertEquals(expected, result); // test from entry template st = group.getInstanceOf("entry"); Assert.assertNotNull(st); expected = "
"; result = st.render(); assertEquals(expected, result); } /** * This is part of a regression test for antlr/stringtemplate4#66. * https://github.com/antlr/stringtemplate4/issues/66 */ @Test public void testImportGroupPreservesDelimiters() { String groupFile = "group GenerateHtml;" + newline + "import \"HtmlTemplates.stg\"" + newline + "entry() ::= <<" + newline + "$html()$" + newline + ">>" + newline; String htmlFile = "html() ::= <<" + newline + "
" + newline + ">>" + newline; String dir = getRandomDir(); writeFile(dir, "GenerateHtml.stg", groupFile); writeFile(dir, "HtmlTemplates.stg", htmlFile); STGroup group = new STGroupFile(dir + "/GenerateHtml.stg", '$', '$'); // test html template directly ST st = group.getInstanceOf("html"); Assert.assertNotNull(st); String expected = "
"; String result = st.render(); assertEquals(expected, result); // test from entry template st = group.getInstanceOf("entry"); Assert.assertNotNull(st); expected = "
"; result = st.render(); assertEquals(expected, result); } /** * This is part of a regression test for antlr/stringtemplate4#66. * https://github.com/antlr/stringtemplate4/issues/66 */ @Test public void testDelimitersClauseOverridesConstructorDelimiters() { String groupFile = "group GenerateHtml;" + newline + "delimiters \"$\", \"$\"" + newline + "import \"html.st\"" + newline + "entry() ::= <<" + newline + "$html()$" + newline + ">>" + newline; String htmlFile = "html() ::= <<" + newline + "
" + newline + ">>" + newline; String dir = getRandomDir(); writeFile(dir, "GenerateHtml.stg", groupFile); writeFile(dir, "html.st", htmlFile); STGroup group = new STGroupFile(dir + "/GenerateHtml.stg", '<', '>'); // test html template directly ST st = group.getInstanceOf("html"); Assert.assertNotNull(st); String expected = "
"; String result = st.render(); assertEquals(expected, result); // test from entry template st = group.getInstanceOf("entry"); Assert.assertNotNull(st); expected = "
"; result = st.render(); assertEquals(expected, result); } /** * This is part of a regression test for antlr/stringtemplate4#66. * https://github.com/antlr/stringtemplate4/issues/66 */ @Test public void testDelimitersClauseOverridesInheritedDelimiters() { String groupFile = "group GenerateHtml;" + newline + "delimiters \"<\", \">\"" + newline + "import \"HtmlTemplates.stg\"" + newline + "entry() ::= <<" + newline + "" + newline + ">>" + newline; String htmlFile = "delimiters \"$\", \"$\"" + newline + "html() ::= <<" + newline + "
" + newline + ">>" + newline; String dir = getRandomDir(); writeFile(dir, "GenerateHtml.stg", groupFile); writeFile(dir, "HtmlTemplates.stg", htmlFile); STGroup group = new STGroupFile(dir + "/GenerateHtml.stg"); // test html template directly ST st = group.getInstanceOf("html"); Assert.assertNotNull(st); String expected = "
"; String result = st.render(); assertEquals(expected, result); // test from entry template st = group.getInstanceOf("entry"); Assert.assertNotNull(st); expected = "
"; result = st.render(); assertEquals(expected, result); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestEarlyEvaluation.java000066400000000000000000000130631231426731300276050ustar00rootroot00000000000000package org.stringtemplate.v4.test; import org.junit.Assert; import org.junit.Test; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroupFile; import org.stringtemplate.v4.gui.STViz; import java.awt.*; import java.util.HashMap; public class TestEarlyEvaluation extends BaseTest { /** * @return true if at least one Window is visible */ public static boolean isAnyWindowVisible() { for (Window w : Window.getWindows()) { if (w.isVisible()) return true; } return false; } public static void waitUntilAnyWindowIsVisible(long maxWaitMillis) { long startMillis = System.currentTimeMillis(); while (!isAnyWindowVisible()) { if (System.currentTimeMillis() - startMillis > maxWaitMillis) { throw new RuntimeException("Timeout"); } try { Thread.sleep(100); } catch (InterruptedException e) { // Ignore } } } public static void waitUntilAllWindowsAreClosed() { while (isAnyWindowVisible()) { try { Thread.sleep(100); } catch (InterruptedException e) { // ignore } } } /** * see * http://www.antlr3.org/pipermail/stringtemplate-interest/2011-May/003476.html * * @throws Exception */ @Test public void testEarlyEval() throws Exception { String templates = "main() ::= <<\n*\n>>\n\n" + "f(p,q={<({a

})>}) ::= <<\n--\n>>"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir + "/t.stg"); ST st = group.getInstanceOf("main"); String s = st.render(); Assert.assertEquals("-ax-*-ay-", s); // Calling inspect led to an java.lang.ArrayIndexOutOfBoundsException in // 4.0.2 STViz viz = st.inspect(); if (interactive) { viz.waitForClose(); } else { waitUntilAnyWindowIsVisible(4000); viz.viewFrame.dispose(); waitUntilAllWindowsAreClosed(); } } /** * see * http://www.antlr.org/pipermail/stringtemplate-interest/2011-May/003476.html * * @throws Exception */ @Test public void testEarlyEval2() throws Exception { String templates = "main() ::= <<\n*\n>>\n\n" + "f(p,q={<({a

})>}) ::= <<\n--\n>>"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir + "/t.stg"); ST st = group.getInstanceOf("main"); String s = st.render(); Assert.assertEquals("-ax-*", s); // When is invoked only once inspect throws no Exception in // 4.0.2 STViz viz = st.inspect(); if (interactive) { viz.waitForClose(); } else { waitUntilAnyWindowIsVisible(4000); viz.viewFrame.dispose(); waitUntilAllWindowsAreClosed(); } } /** * see http://www.antlr3.org/pipermail/stringtemplate-interest/2011-August/003758.html * @throws Exception */ @Test public void testBugArrayIndexOutOfBoundsExceptionInSTRuntimeMessage_getSourceLocation() throws Exception { String templates = "main(doit = true) ::= " + "\"\"\n" + "t2() ::= \"Hello\"\n" // + "t(x={<(t2())>}) ::= \"\""; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir + "/t.stg"); ST st = group.getInstanceOf("main"); String s = st.render(); Assert.assertEquals("Hello", s); // Inspecting this template threw an ArrayIndexOutOfBoundsException // in 4.0.2. // With the default for x changed to {} (i.e. lazy eval) inspect // works fine. Also removing the " || other" and keeping the early eval // works fine with inspect. STViz viz = st.inspect(); if (interactive) { viz.waitForClose(); } else { waitUntilAnyWindowIsVisible(4000); viz.viewFrame.dispose(); waitUntilAllWindowsAreClosed(); } } @Test public void testEarlyEvalInIfExpr() throws Exception { String templates = "main(x) ::= << foobar >>"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir + "/t.stg"); ST st = group.getInstanceOf("main"); String s = st.render(); Assert.assertEquals(" bar ", s); st.add("x", "true"); s = st.render(); Assert.assertEquals(" foo ", s); } @Test public void testEarlyEvalOfSubtemplateInIfExpr() throws Exception { String templates = "main(x) ::= << b}))>foobar >>"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir + "/t.stg"); ST st = group.getInstanceOf("main"); String s = st.render(); Assert.assertEquals(" foo ", s); } @Test public void testEarlyEvalOfMapInIfExpr() throws Exception { String templates = "m ::= [\n"+ " \"parrt\": \"value\",\n"+ " default: \"other\"\n"+ "]\n" + "main(x) ::= << pt: t})>, t}))>ifelse >>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir + "/t.stg"); ST st = group.getInstanceOf("main"); st.add("x", null); String s = st.render(); Assert.assertEquals(" pt: other, if ", s); st.add("x", "arr"); s = st.render(); Assert.assertEquals(" parrt: value, if ", s); } @Test public void testEarlyEvalOfMapInIfExprPassInHashMap() throws Exception { String templates = "main(m,x) ::= << pt: t})>, t}))>ifelse >>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir + "/t.stg"); ST st = group.getInstanceOf("main"); st.add("m", new HashMap() {{put("parrt","value");}}); st.add("x", null); String s = st.render(); Assert.assertEquals(" pt: , else ", s); // m[null] has no default value so else clause st.add("x", "arr"); s = st.render(); Assert.assertEquals(" parrt: value, if ", s); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestFunctions.java000066400000000000000000000651711231426731300264600ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.*; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroupFile; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.junit.Assert.assertEquals; public class TestFunctions extends BaseTest { @Test public void testFirst() throws Exception { String template = ""; org.stringtemplate.v4.ST st = new ST(template); List names = new ArrayList() { {add("Ter"); add("Tom");} }; st.add("names", names); String expected = "Ter"; String result = st.render(); assertEquals(expected, result); } @Test public void testLength() throws Exception { String template = ""; org.stringtemplate.v4.ST st = new org.stringtemplate.v4.ST(template); List names = new ArrayList() { {add("Ter"); add("Tom");} }; st.add("names", names); String expected = "2"; String result = st.render(); assertEquals(expected, result); } @Test public void testLengthWithNullValues() throws Exception { String template = ""; org.stringtemplate.v4.ST st = new org.stringtemplate.v4.ST(template); List names = new ArrayList() { {add("Ter"); add(null); add("Tom"); add(null); } }; st.add("names", names); String expected = "4"; String result = st.render(); assertEquals(expected, result); } @Test public void testFirstOp() throws Exception { org.stringtemplate.v4.ST e = new org.stringtemplate.v4.ST( "" ); e.add("names", "Ter"); e.add("names", "Tom"); e.add("names", "Sriram"); String expecting = "Ter"; assertEquals(expecting, e.render()); } @Test public void testFirstOpList() throws Exception { ST e = new ST( "" ); e.add("names", Arrays.asList("Ter", "Tom", "Sriram")); String expecting = "Ter"; assertEquals(expecting, e.render()); } @Test public void testFirstOpArray() throws Exception { ST e = new ST( "" ); e.add("names", new String[] { "Ter", "Tom", "Sriram" }); String expecting = "Ter"; assertEquals(expecting, e.render()); } @Test public void testFirstOpPrimitiveArray() throws Exception { ST e = new ST( "" ); e.add("names", new int[] { 0, 1, 2 }); String expecting = "0"; assertEquals(expecting, e.render()); } @Test public void testTruncOp() throws Exception { org.stringtemplate.v4.ST e = new org.stringtemplate.v4.ST( "" ); e.add("names", "Ter"); e.add("names", "Tom"); e.add("names", "Sriram"); String expecting = "Ter, Tom"; assertEquals(expecting, e.render()); } @Test public void testTruncOpList() throws Exception { ST e = new ST( "" ); e.add("names", Arrays.asList("Ter", "Tom", "Sriram")); String expecting = "Ter, Tom"; assertEquals(expecting, e.render()); } @Test public void testTruncOpArray() throws Exception { ST e = new ST( "" ); e.add("names", new String[] { "Ter", "Tom", "Sriram" }); String expecting = "Ter, Tom"; assertEquals(expecting, e.render()); } @Test public void testTruncOpPrimitiveArray() throws Exception { ST e = new ST( "" ); e.add("names", new int[] { 0, 1, 2 }); String expecting = "0, 1"; assertEquals(expecting, e.render()); } @Test public void testRestOp() throws Exception { ST e = new org.stringtemplate.v4.ST( "" ); e.add("names", "Ter"); e.add("names", "Tom"); e.add("names", "Sriram"); String expecting = "Tom, Sriram"; assertEquals(expecting, e.render()); } @Test public void testRestOpList() throws Exception { ST e = new ST( "" ); e.add("names", Arrays.asList("Ter", "Tom", "Sriram")); String expecting = "Tom, Sriram"; assertEquals(expecting, e.render()); } @Test public void testRestOpArray() throws Exception { ST e = new ST( "" ); e.add("names", new String[] { "Ter", "Tom", "Sriram" }); String expecting = "Tom, Sriram"; assertEquals(expecting, e.render()); } @Test public void testRestOpPrimitiveArray() throws Exception { ST e = new ST( "" ); e.add("names", new int[] { 0, 1, 2 }); String expecting = "1, 2"; assertEquals(expecting, e.render()); } @Test public void testRestOpEmptyList() throws Exception { org.stringtemplate.v4.ST e = new org.stringtemplate.v4.ST( "" ); e.add("names", new ArrayList()); String expecting = ""; assertEquals(expecting, e.render()); } @Test public void testRestOpEmptyArray() throws Exception { ST e = new ST( "" ); e.add("names", new String[0]); String expecting = ""; assertEquals(expecting, e.render()); } @Test public void testRestOpEmptyPrimitiveArray() throws Exception { ST e = new ST( "" ); e.add("names", new int[0]); String expecting = ""; assertEquals(expecting, e.render()); } @Test public void testReUseOfRestResult() throws Exception { String templates = "a(names) ::= \"\""+newline+ "b(x) ::= \", \""+newline ; writeFile(tmpdir, "t.stg", templates); STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); org.stringtemplate.v4.ST e = group.getInstanceOf("a"); List names = new ArrayList(); names.add("Ter"); names.add("Tom"); e.add("names", names); String expecting = "Tom, Tom"; assertEquals(expecting, e.render()); } @Test public void testReUseOfRestPrimitiveArrayResult() throws Exception { String templates = "a(names) ::= \"\""+newline+ "b(x) ::= \", \""+newline ; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST e = group.getInstanceOf("a"); e.add("names", new int[] { 0, 1 }); String expecting = "1, 1"; assertEquals(expecting, e.render()); } @Test public void testLastOp() throws Exception { ST e = new ST( "" ); e.add("names", "Ter"); e.add("names", "Tom"); e.add("names", "Sriram"); String expecting = "Sriram"; assertEquals(expecting, e.render()); } @Test public void testLastOpList() throws Exception { ST e = new ST( "" ); e.add("names", Arrays.asList("Ter", "Tom", "Sriram")); String expecting = "Sriram"; assertEquals(expecting, e.render()); } @Test public void testLastOpArray() throws Exception { ST e = new ST( "" ); e.add("names", new String[] { "Ter", "Tom", "Sriram" }); String expecting = "Sriram"; assertEquals(expecting, e.render()); } @Test public void testLastOpPrimitiveArray() throws Exception { ST e = new ST( "" ); e.add("names", new int[] { 0, 1, 2 }); String expecting = "2"; assertEquals(expecting, e.render()); } @Test public void testStripOp() throws Exception { ST e = new org.stringtemplate.v4.ST( "" ); e.add("names", null); e.add("names", "Tom"); e.add("names", null); e.add("names", null); e.add("names", "Sriram"); e.add("names", null); String expecting = "TomSriram"; assertEquals(expecting, e.render()); } @Test public void testStripOpList() throws Exception { ST e = new ST( "" ); e.add("names", Arrays.asList(null, "Tom", null, null, "Sriram", null)); String expecting = "TomSriram"; assertEquals(expecting, e.render()); } @Test public void testStripOpArray() throws Exception { ST e = new ST( "" ); e.add("names", new String[] { null, "Tom", null, null, "Sriram", null }); String expecting = "TomSriram"; assertEquals(expecting, e.render()); } @Test public void testLengthStrip() throws Exception { ST e = new org.stringtemplate.v4.ST( "" ); e.add("names", null); e.add("names", "Tom"); e.add("names", null); e.add("names", null); e.add("names", "Sriram"); e.add("names", null); String expecting = "2"; assertEquals(expecting, e.render()); } @Test public void testLengthStripList() throws Exception { ST e = new ST( "" ); e.add("names", Arrays.asList(null, "Tom", null, null, "Sriram", null)); String expecting = "2"; assertEquals(expecting, e.render()); } @Test public void testLengthStripArray() throws Exception { ST e = new ST( "" ); e.add("names", new String[] { null, "Tom", null, null, "Sriram", null }); String expecting = "2"; assertEquals(expecting, e.render()); } @Test public void testCombinedOp() throws Exception { // replace first of yours with first of mine org.stringtemplate.v4.ST e = new org.stringtemplate.v4.ST( "<[first(mine),rest(yours)]; separator=\", \">" ); e.add("mine", "1"); e.add("mine", "2"); e.add("mine", "3"); e.add("yours", "a"); e.add("yours", "b"); String expecting = "1, b"; assertEquals(expecting, e.render()); } @Test public void testCombinedOpList() throws Exception { // replace first of yours with first of mine ST e = new ST( "<[first(mine),rest(yours)]; separator=\", \">" ); e.add("mine", Arrays.asList("1", "2", "3")); e.add("yours", "a"); e.add("yours", "b"); String expecting = "1, b"; assertEquals(expecting, e.render()); } @Test public void testCombinedOpArray() throws Exception { // replace first of yours with first of mine ST e = new ST( "<[first(mine),rest(yours)]; separator=\", \">" ); e.add("mine", new String[] { "1", "2", "3" }); e.add("yours", "a"); e.add("yours", "b"); String expecting = "1, b"; assertEquals(expecting, e.render()); } @Test public void testCombinedOpPrimitiveArray() throws Exception { // replace first of yours with first of mine ST e = new ST( "<[first(mine),rest(yours)]; separator=\", \">" ); e.add("mine", new int[] { 1, 2, 3 }); e.add("yours", "a"); e.add("yours", "b"); String expecting = "1, b"; assertEquals(expecting, e.render()); } @Test public void testCatListAndSingleAttribute() throws Exception { // replace first of yours with first of mine org.stringtemplate.v4.ST e = new org.stringtemplate.v4.ST( "<[mine,yours]; separator=\", \">" ); e.add("mine", "1"); e.add("mine", "2"); e.add("mine", "3"); e.add("yours", "a"); String expecting = "1, 2, 3, a"; assertEquals(expecting, e.render()); } @Test public void testCatListAndSingleAttribute2() throws Exception { // replace first of yours with first of mine ST e = new ST( "<[mine,yours]; separator=\", \">" ); e.add("mine", Arrays.asList("1", "2", "3")); e.add("yours", "a"); String expecting = "1, 2, 3, a"; assertEquals(expecting, e.render()); } @Test public void testCatArrayAndSingleAttribute() throws Exception { // replace first of yours with first of mine ST e = new ST( "<[mine,yours]; separator=\", \">" ); e.add("mine", new String[] { "1", "2", "3" }); e.add("yours", "a"); String expecting = "1, 2, 3, a"; assertEquals(expecting, e.render()); } @Test public void testCatPrimitiveArrayAndSingleAttribute() throws Exception { // replace first of yours with first of mine ST e = new ST( "<[mine,yours]; separator=\", \">" ); e.add("mine", new int[] { 1, 2, 3 }); e.add("yours", "a"); String expecting = "1, 2, 3, a"; assertEquals(expecting, e.render()); } @Test public void testReUseOfCat() throws Exception { String templates = "a(mine,yours) ::= \"\""+newline+ "b(x) ::= \", \""+newline ; writeFile(tmpdir, "t.stg", templates); STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); org.stringtemplate.v4.ST e = group.getInstanceOf("a"); List mine = new ArrayList(); mine.add("Ter"); mine.add("Tom"); e.add("mine", mine); List yours = new ArrayList(); yours.add("Foo"); e.add("yours", yours); String expecting = "TerTomFoo, TerTomFoo"; assertEquals(expecting, e.render()); } @Test public void testCatListAndEmptyAttributes() throws Exception { // + is overloaded to be cat strings and cat lists so the // two operands (from left to right) determine which way it // goes. In this case, x+mine is a list so everything from their // to the right becomes list cat. org.stringtemplate.v4.ST e = new org.stringtemplate.v4.ST( "<[x,mine,y,yours,z]; separator=\", \">" ); e.add("mine", "1"); e.add("mine", "2"); e.add("mine", "3"); e.add("yours", "a"); String expecting = "1, 2, 3, a"; assertEquals(expecting, e.render()); } @Test public void testCatListAndEmptyAttributes2() throws Exception { // + is overloaded to be cat strings and cat lists so the // two operands (from left to right) determine which way it // goes. In this case, x+mine is a list so everything from their // to the right becomes list cat. ST e = new ST( "<[x,mine,y,yours,z]; separator=\", \">" ); e.add("mine", Arrays.asList("1", "2", "3")); e.add("yours", "a"); String expecting = "1, 2, 3, a"; assertEquals(expecting, e.render()); } @Test public void testCatArrayAndEmptyAttributes2() throws Exception { // + is overloaded to be cat strings and cat lists so the // two operands (from left to right) determine which way it // goes. In this case, x+mine is a list so everything from their // to the right becomes list cat. ST e = new ST( "<[x,mine,y,yours,z]; separator=\", \">" ); e.add("mine", new String[] { "1", "2", "3" }); e.add("yours", "a"); String expecting = "1, 2, 3, a"; assertEquals(expecting, e.render()); } @Test public void testCatPrimitiveArrayAndEmptyAttributes() throws Exception { // + is overloaded to be cat strings and cat lists so the // two operands (from left to right) determine which way it // goes. In this case, x+mine is a list so everything from their // to the right becomes list cat. ST e = new ST( "<[x,mine,y,yours,z]; separator=\", \">" ); e.add("mine", new int[] { 1, 2, 3 }); e.add("yours", "a"); String expecting = "1, 2, 3, a"; assertEquals(expecting, e.render()); } @Test public void testNestedOp() throws Exception { ST e = new org.stringtemplate.v4.ST( "" // gets 2nd element ); e.add("names", "Ter"); e.add("names", "Tom"); e.add("names", "Sriram"); String expecting = "Tom"; assertEquals(expecting, e.render()); } @Test public void testNestedOpList() throws Exception { ST e = new ST( "" // gets 2nd element ); e.add("names", Arrays.asList("Ter", "Tom", "Sriram")); String expecting = "Tom"; assertEquals(expecting, e.render()); } @Test public void testNestedOpArray() throws Exception { ST e = new ST( "" // gets 2nd element ); e.add("names", new String[] { "Ter", "Tom", "Sriram" }); String expecting = "Tom"; assertEquals(expecting, e.render()); } @Test public void testNestedOpPrimitiveArray() throws Exception { ST e = new ST( "" // gets 2nd element ); e.add("names", new int[] { 0, 1, 2 }); String expecting = "1"; assertEquals(expecting, e.render()); } @Test public void testFirstWithOneAttributeOp() throws Exception { org.stringtemplate.v4.ST e = new org.stringtemplate.v4.ST( "" ); e.add("names", "Ter"); String expecting = "Ter"; assertEquals(expecting, e.render()); } @Test public void testLastWithOneAttributeOp() throws Exception { org.stringtemplate.v4.ST e = new org.stringtemplate.v4.ST( "" ); e.add("names", "Ter"); String expecting = "Ter"; assertEquals(expecting, e.render()); } @Test public void testLastWithLengthOneListAttributeOp() throws Exception { org.stringtemplate.v4.ST e = new ST( "" ); e.add("names", new ArrayList() {{add("Ter");}}); String expecting = "Ter"; assertEquals(expecting, e.render()); } @Test public void testLastWithLengthOneArrayAttributeOp() throws Exception { ST e = new ST( "" ); e.add("names", new String[] { "Ter" }); String expecting = "Ter"; assertEquals(expecting, e.render()); } @Test public void testLastWithLengthOnePrimitiveArrayAttributeOp() throws Exception { ST e = new ST( "" ); e.add("names", new int[] { 0 }); String expecting = "0"; assertEquals(expecting, e.render()); } @Test public void testRestWithOneAttributeOp() throws Exception { org.stringtemplate.v4.ST e = new org.stringtemplate.v4.ST( "" ); e.add("names", "Ter"); String expecting = ""; assertEquals(expecting, e.render()); } @Test public void testRestWithLengthOneListAttributeOp() throws Exception { org.stringtemplate.v4.ST e = new org.stringtemplate.v4.ST( "" ); e.add("names", new ArrayList() {{add("Ter");}}); String expecting = ""; assertEquals(expecting, e.render()); } @Test public void testRestWithLengthOneArrayAttributeOp() throws Exception { ST e = new ST( "" ); e.add("names", new String[] { "Ter" }); String expecting = ""; assertEquals(expecting, e.render()); } @Test public void testRestWithLengthOnePrimitiveArrayAttributeOp() throws Exception { ST e = new ST( "" ); e.add("names", new int[] { 0 }); String expecting = ""; assertEquals(expecting, e.render()); } @Test public void testRepeatedRestOp() throws Exception { org.stringtemplate.v4.ST e = new org.stringtemplate.v4.ST( ", " // gets 2nd element ); e.add("names", "Ter"); e.add("names", "Tom"); String expecting = "Tom, Tom"; assertEquals(expecting, e.render()); } @Test public void testRepeatedRestOpList() throws Exception { ST e = new ST( ", " // gets 2nd element ); e.add("names", Arrays.asList("Ter", "Tom")); String expecting = "Tom, Tom"; assertEquals(expecting, e.render()); } @Test public void testRepeatedRestOpArray() throws Exception { ST e = new ST( ", " // gets 2nd element ); e.add("names", new String[] { "Ter", "Tom" }); String expecting = "Tom, Tom"; assertEquals(expecting, e.render()); } @Test public void testRepeatedRestOpPrimitiveArray() throws Exception { ST e = new ST( ", " // gets 2nd element ); e.add("names", new int[] { 0, 1 }); String expecting = "1, 1"; assertEquals(expecting, e.render()); } @Test public void testIncomingLists() throws Exception { ST e = new org.stringtemplate.v4.ST( ", " // gets 2nd element ); e.add("names", "Ter"); e.add("names", "Tom"); String expecting = "Tom, Tom"; assertEquals(expecting, e.render()); } @Test public void testFirstWithCatAttribute() throws Exception { ST e = new org.stringtemplate.v4.ST( "" ); e.add("names", "Ter"); e.add("names", "Tom"); e.add("phones", "1"); e.add("phones", "2"); String expecting = "Ter"; assertEquals(expecting, e.render()); } @Test public void testFirstWithListOfMaps() throws Exception { org.stringtemplate.v4.ST e = new org.stringtemplate.v4.ST( "" ); final Map m1 = new HashMap(); final Map m2 = new HashMap(); m1.put("Ter", "x5707"); e.add("maps", m1); m2.put("Tom", "x5332"); e.add("maps", m2); String expecting = "x5707"; assertEquals(expecting, e.render()); List> list = new ArrayList>() {{add(m1); add(m2);}}; e.add("maps", list); expecting = "x5707"; assertEquals(expecting, e.render()); } @Test public void testFirstWithListOfMaps2() throws Exception { org.stringtemplate.v4.ST e = new org.stringtemplate.v4.ST( "!}>" ); final Map m1 = new HashMap(); final Map m2 = new HashMap(); m1.put("Ter", "x5707"); e.add("maps", m1); m2.put("Tom", "x5332"); e.add("maps", m2); String expecting = "Ter!"; assertEquals(expecting, e.render()); List> list = new ArrayList>() {{add(m1); add(m2);}}; e.add("maps", list); expecting = "Ter!"; assertEquals(expecting, e.render()); } @Test public void testTrim() throws Exception { ST e = new org.stringtemplate.v4.ST( "" ); e.add("name", " Ter \n"); String expecting = "Ter"; assertEquals(expecting, e.render()); } @Test public void testStrlen() throws Exception { org.stringtemplate.v4.ST e = new org.stringtemplate.v4.ST( "" ); e.add("name", "012345"); String expecting = "6"; assertEquals(expecting, e.render()); } @Test public void testReverse() throws Exception { org.stringtemplate.v4.ST e = new org.stringtemplate.v4.ST( "" ); e.add("names", "Ter"); e.add("names", "Tom"); e.add("names", "Sriram"); String expecting = "Sriram, Tom, Ter"; assertEquals(expecting, e.render()); } @Test public void testReverseList() throws Exception { ST e = new ST( "" ); e.add("names", Arrays.asList("Ter", "Tom", "Sriram")); String expecting = "Sriram, Tom, Ter"; assertEquals(expecting, e.render()); } @Test public void testReverseArray() throws Exception { ST e = new ST( "" ); e.add("names", new String[] { "Ter", "Tom", "Sriram" }); String expecting = "Sriram, Tom, Ter"; assertEquals(expecting, e.render()); } @Test public void testReversePrimitiveArray() throws Exception { ST e = new ST( "" ); e.add("names", new int[] { 0, 1, 2 }); String expecting = "2, 1, 0"; assertEquals(expecting, e.render()); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestGroupSyntax.java000066400000000000000000000230721231426731300270050ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.Test; import org.stringtemplate.v4.*; import org.stringtemplate.v4.misc.*; import static org.junit.Assert.assertEquals; import java.io.File; public class TestGroupSyntax extends BaseTest { @Test public void testSimpleGroup() throws Exception { String templates = "t() ::= <>" + Misc.newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); String expected = "t() ::= <<" + Misc.newline+ "foo" + Misc.newline+ ">>"+ Misc.newline; String result = group.show(); assertEquals(expected, result); } @Test public void testEscapedQuote() throws Exception { // setTest(ranges) ::= "" // has to unescape the strings. String templates = "setTest(ranges) ::= \"\"" + Misc.newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); String expected = "setTest(ranges) ::= <<"+Misc.newline+ "" +Misc.newline+ ">>"+ Misc.newline; String result = group.show(); assertEquals(expected, result); } @Test public void testMultiTemplates() throws Exception { String templates = "ta(x) ::= \"[]\"" + Misc.newline + "duh() ::= <>" + Misc.newline + "wow() ::= <>" + Misc.newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); String expected = "ta(x) ::= <<" +Misc.newline+ "[]" +Misc.newline+ ">>" +Misc.newline+ "duh() ::= <<" +Misc.newline+ "hi there" +Misc.newline+ ">>" +Misc.newline+ "wow() ::= <<" +Misc.newline+ "last" +Misc.newline+ ">>"+ Misc.newline; String result = group.show(); assertEquals(expected, result); } @Test public void testSetDefaultDelimiters() throws Exception { String templates = "delimiters \"<\", \">\"" + Misc.newline + "ta(x) ::= \"[]\"" + Misc.newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST st = group.getInstanceOf("ta"); st.add("x", "hi"); String expected = "[hi]"; String result = st.render(); assertEquals(expected, result); } @Test public void testSetNonDefaultDelimiters() throws Exception { String templates = "delimiters \"%\", \"%\"" + Misc.newline + "ta(x) ::= \"[%x%]\"" + Misc.newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST st = group.getInstanceOf("ta"); st.add("x", "hi"); String expected = "[hi]"; String result = st.render(); assertEquals(expected, result); } @Test public void testSingleTemplateWithArgs() throws Exception { String templates = "t(a,b) ::= \"[]\"" + Misc.newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); String expected = "t(a,b) ::= <<" + Misc.newline+ "[]" + Misc.newline+ ">>"+ Misc.newline; String result = group.show(); assertEquals(expected, result); } @Test public void testDefaultValues() throws Exception { String templates = "t(a={def1},b=\"def2\") ::= \"[]\"" + Misc.newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); String expected = "t(a={def1},b=\"def2\") ::= <<" + Misc.newline+ "[]" + Misc.newline+ ">>"+ Misc.newline; String result = group.show(); assertEquals(expected, result); } @Test public void testDefaultValues2() throws Exception { String templates = "t(x, y, a={def1}, b=\"def2\") ::= \"[]\"" + Misc.newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); String expected = "t(x,y,a={def1},b=\"def2\") ::= <<" + Misc.newline+ "[]" + Misc.newline+ ">>"+ Misc.newline; String result = group.show(); assertEquals(expected, result); } @Test public void testDefaultValueTemplateWithArg() throws Exception { String templates = "t(a={x | 2*}) ::= \"[]\"" + Misc.newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); String expected = "t(a={x | 2*}) ::= <<" + Misc.newline+ "[]" + Misc.newline+ ">>"+ Misc.newline; String result = group.show(); assertEquals(expected, result); } @Test public void testDefaultValueBehaviorTrue() throws Exception { String templates = "t(a=true) ::= <<\n" + "+-\n" + ">>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir + File.separatorChar + "t.stg"); ST st = group.getInstanceOf("t"); String expected = "true+"; String result = st.render(); assertEquals(expected, result); } @Test public void testDefaultValueBehaviorFalse() throws Exception { String templates = "t(a=false) ::= <<\n" + "+-\n" + ">>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir + File.separatorChar + "t.stg"); ST st = group.getInstanceOf("t"); String expected = "false-"; String result = st.render(); assertEquals(expected, result); } @Test public void testDefaultValueBehaviorEmptyTemplate() throws Exception { String templates = "t(a={}) ::= <<\n" + "+-\n" + ">>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir + File.separatorChar + "t.stg"); ST st = group.getInstanceOf("t"); String expected = "+"; String result = st.render(); assertEquals(expected, result); } @Test public void testDefaultValueBehaviorEmptyList() throws Exception { String templates = "t(a=[]) ::= <<\n" + "+-\n" + ">>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir + File.separatorChar + "t.stg"); ST st = group.getInstanceOf("t"); String expected = "-"; String result = st.render(); assertEquals(expected, result); } @Test public void testNestedTemplateInGroupFile() throws Exception { String templates = "t(a) ::= \"}>}>\"" + Misc.newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); String expected = "t(a) ::= <<" + newline + "}>}>" + newline + ">>"+ Misc.newline; String result = group.show(); assertEquals(expected, result); } @Test public void testNestedDefaultValueTemplate() throws Exception { String templates = "t(a={x | }>}) ::= \"ick\"" + Misc.newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); group.load(); String expected = "t(a={x | }>}) ::= <<" + newline + "ick" + newline + ">>"+ Misc.newline; String result = group.show(); assertEquals(expected, result); } @Test public void testNestedDefaultValueTemplateWithEscapes() throws Exception { String templates = "t(a={x | \\< \\}}>}) ::= \"[]\"" + Misc.newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); String expected = "t(a={x | \\< \\}}>}) ::= <<" + Misc.newline+ "[]" + Misc.newline+ ">>"+ Misc.newline; String result = group.show(); assertEquals(expected, result); } @Test public void testMessedUpTemplateDoesntCauseRuntimeError() throws Exception { String templates = "main(p) ::= <<\n" + "\n" + ">>\n" + "\n" + "f() ::= <<\n" + "\n" + ">>\n"; writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; ErrorBuffer errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); ST st = group.getInstanceOf("main"); st.render(); String expected = "[context [/main] 1:1 passed 1 arg(s) to template /f with 0 declared arg(s)," + " context [/main] 1:1 attribute x isn't defined," + " context [/main /f] 1:1 attribute x isn't defined]"; String result = errors.errors.toString(); assertEquals(expected, result); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestGroupSyntaxErrors.java000066400000000000000000000232021231426731300301750ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.Test; import org.stringtemplate.v4.STErrorListener; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroupFile; import org.stringtemplate.v4.misc.ErrorBuffer; import static org.junit.Assert.assertEquals; public class TestGroupSyntaxErrors extends BaseTest { @Test public void testMissingImportString() throws Exception { String templates = "import\n" + "foo() ::= <<>>\n"; writeFile(tmpdir, "t.stg", templates); STErrorListener errors = new ErrorBuffer(); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "t.stg 2:0: mismatched input 'foo' expecting STRING"+newline+ "t.stg 2:3: required (...)+ loop did not match anything at input '('"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testImportNotString() throws Exception { String templates = "import Super.stg\n" + "foo() ::= <<>>\n"; writeFile(tmpdir, "t.stg", templates); STErrorListener errors = new ErrorBuffer(); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "t.stg 1:7: mismatched input 'Super' expecting STRING"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testMissingTemplate() throws Exception { String templates = "foo() ::= \n"; writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; STErrorListener errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "t.stg 2:0: missing template at ''"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testUnclosedTemplate() throws Exception { String templates = "foo() ::= {"; writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; STErrorListener errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "t.stg 1:11: missing final '}' in {...} anonymous template" +newline+ "t.stg 1:10: no viable alternative at input '{'"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testParen() throws Exception { String templates = "foo( ::= << >>\n"; writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; STErrorListener errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "t.stg 1:5: no viable alternative at input '::='"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testNewlineInString() throws Exception { String templates = "foo() ::= \"\nfoo\"\n"; writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; STErrorListener errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "t.stg 1:11: \\n in string"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testParen2() throws Exception { String templates = "foo) ::= << >>\n" + "bar() ::= <>\n"; writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; STErrorListener errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "t.stg 1:0: garbled template definition starting at 'foo'"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testArg() throws Exception { String templates = "foo(a,) ::= << >>\n"; writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; STErrorListener errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "t.stg 1:6: missing ID at ')'"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testArg2() throws Exception { String templates = "foo(a,,) ::= << >>\n"; writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; ErrorBuffer errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "[t.stg 1:6: missing ID at ',', " + "t.stg 1:7: missing ID at ')']"; String result = errors.errors.toString(); assertEquals(expected, result); } @Test public void testArg3() throws Exception { String templates = "foo(a b) ::= << >>\n"; writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; ErrorBuffer errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "[t.stg 1:6: no viable alternative at input 'b']"; String result = errors.errors.toString(); assertEquals(expected, result); } @Test public void testDefaultArgsOutOfOrder() throws Exception { String templates = "foo(a={hi}, b) ::= << >>\n"; writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; ErrorBuffer errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "[t.stg 1:12: required parameters (b) must appear before optional parameters]"; String result = errors.errors.toString(); assertEquals(expected, result); } @Test public void testErrorWithinTemplate() throws Exception { String templates = "foo(a) ::= \"\"\n"; writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; ErrorBuffer errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "[t.stg 1:15: 'b' came as a complete surprise to me]"; String result = errors.errors.toString(); assertEquals(expected, result); } @Test public void testMap() throws Exception { String templates = "d ::= []\n"; writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; ErrorBuffer errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "[t.stg 1:7: missing dictionary entry at ']']"; String result = errors.errors.toString(); assertEquals(expected, result); } @Test public void testMap2() throws Exception { String templates = "d ::= [\"k\":]\n"; writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; ErrorBuffer errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "[t.stg 1:11: missing value for key at ']']"; String result = errors.errors.toString(); assertEquals(expected, result); } @Test public void testMap3() throws Exception { String templates = "d ::= [\"k\":{dfkj}}]\n"; // extra } writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; ErrorBuffer errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "[t.stg 1:17: invalid character '}']"; String result = errors.errors.toString(); assertEquals(expected, result); } @Test public void testUnterminatedString() throws Exception { String templates = "f() ::= \""; // extra } writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; ErrorBuffer errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "[t.stg 1:9: unterminated string, t.stg 1:9: missing template at '']"; String result = errors.errors.toString(); assertEquals(expected, result); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestGroups.java000066400000000000000000000653471231426731300257740ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.Assert; import org.junit.Test; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STErrorListener; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroupDir; import org.stringtemplate.v4.STGroupFile; import org.stringtemplate.v4.STGroupString; import org.stringtemplate.v4.misc.ErrorBuffer; import java.io.File; import java.util.Set; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; public class TestGroups extends BaseTest { @Test public void testSimpleGroup() throws Exception { String dir = getRandomDir(); writeFile(dir, "a.st", "a(x) ::= <>"); STGroup group = new STGroupDir(dir); ST st = group.getInstanceOf("a"); String expected = "foo"; String result = st.render(); assertEquals(expected, result); } @Test public void testEscapeOneRightAngle() throws Exception { String dir = getRandomDir(); writeFile(dir, "a.st", "a(x) ::= << > >>"); STGroup group = new STGroupDir(dir); ST st = group.getInstanceOf("a"); st.add("x", "parrt"); String expected = " > "; String result = st.render(); assertEquals(expected, result); } @Test public void testEscapeJavaRightShift() throws Exception { String dir = getRandomDir(); writeFile(dir, "a.st", "a(x) ::= << \\>> >>"); STGroup group = new STGroupDir(dir); ST st = group.getInstanceOf("a"); st.add("x", "parrt"); String expected = " >> "; String result = st.render(); assertEquals(expected, result); } @Test public void testEscapeJavaRightShift2() throws Exception { String dir = getRandomDir(); writeFile(dir, "a.st", "a(x) ::= << >\\> >>"); STGroup group = new STGroupDir(dir); ST st = group.getInstanceOf("a"); st.add("x", "parrt"); String expected = " >> "; String result = st.render(); assertEquals(expected, result); } @Test public void testEscapeJavaRightShiftAtRightEdge() throws Exception { String dir = getRandomDir(); writeFile(dir, "a.st", "a(x) ::= <<\\>>>"); // <<\>>> STGroup group = new STGroupDir(dir); ST st = group.getInstanceOf("a"); st.add("x", "parrt"); String expected = "\\>"; String result = st.render(); assertEquals(expected, result); } @Test public void testEscapeJavaRightShiftAtRightEdge2() throws Exception { String dir = getRandomDir(); writeFile(dir, "a.st", "a(x) ::= <<>\\>>>"); STGroup group = new STGroupDir(dir); ST st = group.getInstanceOf("a"); st.add("x", "parrt"); String expected = ">>"; String result = st.render(); assertEquals(expected, result); } @Test public void testSimpleGroupFromString() throws Exception { String g = "a(x) ::= <>\n"+ "b() ::= <>\n"; STGroup group = new STGroupString(g); ST st = group.getInstanceOf("a"); String expected = "foo"; String result = st.render(); assertEquals(expected, result); } @Test public void testGroupWithTwoTemplates() throws Exception { String dir = getRandomDir(); writeFile(dir, "a.st", "a(x) ::= <>"); writeFile(dir, "b.st", "b() ::= \"bar\""); STGroup group = new STGroupDir(dir); ST st1 = group.getInstanceOf("a"); ST st2 = group.getInstanceOf("b"); String expected = "foobar"; String result = st1.render()+st2.render(); assertEquals(expected, result); } @Test public void testSubdir() throws Exception { // /randomdir/a and /randomdir/subdir/b String dir = getRandomDir(); writeFile(dir, "a.st", "a(x) ::= <>"); writeFile(dir+"/subdir", "b.st", "b() ::= \"bar\""); STGroup group = new STGroupDir(dir); assertEquals("foo", group.getInstanceOf("a").render()); assertEquals("bar", group.getInstanceOf("/subdir/b").render()); assertEquals("bar", group.getInstanceOf("subdir/b").render()); } @Test public void testSubdirWithSubtemplate() throws Exception { // /randomdir/a and /randomdir/subdir/b String dir = getRandomDir(); writeFile(dir+"/subdir", "a.st", "a(x) ::= \"}>\""); STGroup group = new STGroupDir(dir); ST st = group.getInstanceOf("/subdir/a"); st.add("x", new String[] {"a", "b"}); assertEquals("ab", st.render()); } @Test public void testGroupFileInDir() throws Exception { // /randomdir/a and /randomdir/group.stg with b and c templates String dir = getRandomDir(); writeFile(dir, "a.st", "a(x) ::= <>"); String groupFile = "b() ::= \"bar\"\n"+ "c() ::= \"duh\"\n"; writeFile(dir, "group.stg", groupFile); STGroup group = new STGroupDir(dir); assertEquals("foo", group.getInstanceOf("a").render()); assertEquals("bar", group.getInstanceOf("/group/b").render()); assertEquals("duh", group.getInstanceOf("/group/c").render()); } @Test public void testSubSubdir() throws Exception { // /randomdir/a and /randomdir/subdir/b String dir = getRandomDir(); writeFile(dir, "a.st", "a(x) ::= <>"); writeFile(dir+"/sub1/sub2", "b.st", "b() ::= \"bar\""); STGroup group = new STGroupDir(dir); ST st1 = group.getInstanceOf("a"); ST st2 = group.getInstanceOf("/sub1/sub2/b"); String expected = "foobar"; String result = st1.render()+st2.render(); assertEquals(expected, result); } @Test public void testGroupFileInSubDir() throws Exception { // /randomdir/a and /randomdir/group.stg with b and c templates String dir = getRandomDir(); writeFile(dir, "a.st", "a(x) ::= <>"); String groupFile = "b() ::= \"bar\"\n"+ "c() ::= \"duh\"\n"; writeFile(dir, "subdir/group.stg", groupFile); STGroup group = new STGroupDir(dir); ST st1 = group.getInstanceOf("a"); ST st2 = group.getInstanceOf("subdir/group/b"); ST st3 = group.getInstanceOf("subdir/group/c"); String expected = "foobarduh"; String result = st1.render()+st2.render()+st3.render(); assertEquals(expected, result); } @Test public void testDupDef() throws Exception { String dir = getRandomDir(); String groupFile = "b() ::= \"bar\"\n"+ "b() ::= \"duh\"\n"; writeFile(dir, "group.stg", groupFile); STErrorListener errors = new ErrorBuffer(); STGroupFile group = new STGroupFile(dir+"/group.stg"); group.setListener(errors); group.load(); String expected = "group.stg 2:0: redefinition of template b"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testAlias() throws Exception { String dir = getRandomDir(); String groupFile = "a() ::= \"bar\"\n"+ "b ::= a\n"; writeFile(dir, "group.stg", groupFile); STGroupFile group = new STGroupFile(dir+"/group.stg"); ST st = group.getInstanceOf("b"); String expected = "bar"; String result = st.render(); assertEquals(expected, result); } @Test public void testAliasWithArgs() throws Exception { String dir = getRandomDir(); String groupFile = "a(x,y) ::= \"\"\n"+ "b ::= a\n"; writeFile(dir, "group.stg", groupFile); STGroupFile group = new STGroupFile(dir+"/group.stg"); ST st = group.getInstanceOf("b"); st.add("x", 1); st.add("y", 2); String expected = "12"; String result = st.render(); assertEquals(expected, result); } @Test public void testSimpleDefaultArg() throws Exception { String dir = getRandomDir(); String a = "a() ::= << >>\n"; String b = "b(x=\"foo\") ::= \"\"\n"; writeFile(dir, "a.st", a); writeFile(dir, "b.st", b); STGroup group = new STGroupDir(dir); ST st = group.getInstanceOf("a"); String expected = " foo "; String result = st.render(); assertEquals(expected, result); } @Test public void testDefaultArgument() throws Exception { String templates = "method(name) ::= <<"+newline+ "" +newline+ ">>"+newline+ "stat(name,value=\"99\") ::= \"x=; // \""+newline ; writeFile(tmpdir, "group.stg", templates); STGroup group = new STGroupFile(tmpdir+"/group.stg"); ST b = group.getInstanceOf("method"); b.add("name", "foo"); String expecting = "x=99; // foo"; String result = b.render(); assertEquals(expecting, result); } @Test public void testBooleanDefaultArguments() throws Exception { String templates = "method(name) ::= <<"+newline+ "" +newline+ ">>"+newline+ "stat(name,x=true,y=false) ::= \"; \""+newline ; writeFile(tmpdir, "group.stg", templates); STGroup group = new STGroupFile(tmpdir+"/group.stg"); ST b = group.getInstanceOf("method"); b.add("name", "foo"); String expecting = "foo; true false"; String result = b.render(); assertEquals(expecting, result); } @Test public void testDefaultArgument2() throws Exception { String templates = "stat(name,value=\"99\") ::= \"x=; // \""+newline ; writeFile(tmpdir, "group.stg", templates); STGroup group = new STGroupFile(tmpdir+"/group.stg"); ST b = group.getInstanceOf("stat"); b.add("name", "foo"); String expecting = "x=99; // foo"; String result = b.render(); assertEquals(expecting, result); } @Test public void testSubtemplateAsDefaultArgSeesOtherArgs() throws Exception { String templates = "t(x,y={}>},z=\"foo\") ::= <<\n" + "x: \n" + "y: \n" + ">>"+newline ; writeFile(tmpdir, "group.stg", templates); STGroup group = new STGroupFile(tmpdir+"/group.stg"); ST b = group.getInstanceOf("t"); b.add("x", "a"); String expecting = "x: a" +newline+ "y: afoo"; String result = b.render(); assertEquals(expecting, result); } @Test public void testEarlyEvalOfDefaultArgs() throws Exception { String templates = "s(x,y={<(x)>}) ::= \"\"\n"; // should see x in def arg STGroup group = new STGroupString(templates); ST b = group.getInstanceOf("s"); b.add("x", "a"); String expecting = "aa"; String result = b.render(); assertEquals(expecting, result); } @Test public void testDefaultArgumentAsSimpleTemplate() throws Exception { String templates = "stat(name,value={99}) ::= \"x=; // \""+newline ; writeFile(tmpdir, "group.stg", templates); STGroup group = new STGroupFile(tmpdir+"/group.stg"); ST b = group.getInstanceOf("stat"); b.add("name", "foo"); String expecting = "x=99; // foo"; String result = b.render(); assertEquals(expecting, result); } @Test public void testDefaultArgumentManuallySet() throws Exception { class Field { public String name = "parrt"; public int n = 0; @Override public String toString() { return "Field"; } } // set arg f manually for stat(f=f) String templates = "method(fields) ::= <<"+newline+ "}>" +newline+ ">>"+newline+ "stat(f,value={}) ::= \"x=; // \""+newline ; writeFile(tmpdir, "group.stg", templates); STGroup group = new STGroupFile(tmpdir+"/group.stg"); ST m = group.getInstanceOf("method"); m.add("fields", new Field()); String expecting = "x=parrt; // parrt"; String result = m.render(); assertEquals(expecting, result); } @Test public void testDefaultArgumentSeesVarFromDynamicScoping() throws Exception { class Field { public String name = "parrt"; public int n = 0; @Override public String toString() { return "Field"; } } String templates = "method(fields) ::= <<"+newline+ "}>" +newline+ ">>"+newline+ "stat(value={}) ::= \"x=; // \""+newline ; writeFile(tmpdir, "group.stg", templates); STGroup group = new STGroupFile(tmpdir+"/group.stg"); ST m = group.getInstanceOf("method"); m.add("fields", new Field()); String expecting = "x=parrt; // parrt"; String result = m.render(); assertEquals(expecting, result); } @Test public void testDefaultArgumentImplicitlySet2() throws Exception { class Field { public String name = "parrt"; public int n = 0; @Override public String toString() { return "Field"; } } // f of stat is implicit first arg String templates = "method(fields) ::= <<"+newline+ "}>" +newline+ ">>"+newline+ "stat(f,value={}) ::= \"x=; // \""+newline ; writeFile(tmpdir, "group.stg", templates); STGroup group = new STGroupFile(tmpdir+"/group.stg"); ST m = group.getInstanceOf("method"); m.add("fields", new Field()); String expecting = "x=parrt; // parrt"; String result = m.render(); assertEquals(expecting, result); } @Test public void testDefaultArgumentAsTemplate() throws Exception { String templates = "method(name,size) ::= <<"+newline+ "" +newline+ ">>"+newline+ "stat(name,value={}) ::= \"x=; // \""+newline ; writeFile(tmpdir, "group.stg", templates); STGroup group = new STGroupFile(tmpdir+"/group.stg"); ST b = group.getInstanceOf("method"); b.add("name", "foo"); b.add("size", "2"); String expecting = "x=foo; // foo"; String result = b.render(); //System.err.println("result='"+result+"'"); assertEquals(expecting, result); } @Test public void testDefaultArgumentAsTemplate2() throws Exception { String templates = "method(name,size) ::= <<"+newline+ "" +newline+ ">>"+newline+ "stat(name,value={ [] }) ::= \"x=; // \""+newline ; writeFile(tmpdir, "group.stg", templates); STGroup group = new STGroupFile(tmpdir+"/group.stg"); ST b = group.getInstanceOf("method"); b.add("name", "foo"); b.add("size", "2"); String expecting = "x=[foo] ; // foo"; // won't see ' ' after '=' since it's an indent not simple string String result = b.render(); //System.err.println("result='"+result+"'"); assertEquals(expecting, result); } @Test public void testDoNotUseDefaultArgument() throws Exception { String templates = "method(name) ::= <<"+newline+ "" +newline+ ">>"+newline+ "stat(name,value=\"99\") ::= \"x=; // \""+newline ; writeFile(tmpdir, "group.stg", templates); STGroup group = new STGroupFile(tmpdir+"/group.stg"); ST b = group.getInstanceOf("method"); b.add("name", "foo"); String expecting = "x=34; // foo"; String result = b.render(); assertEquals(expecting, result); } @Test public void testDefaultArgumentInParensToEvalEarly() throws Exception { class Counter { int n = 0; @Override public String toString() { return String.valueOf(n++); } } String templates = "A(x) ::= \"\""+newline+ "B(y={<(x)>}) ::= \" \""+newline ; writeFile(tmpdir, "group.stg", templates); STGroup group = new STGroupFile(tmpdir+"/group.stg"); ST a = group.getInstanceOf("A"); a.add("x", new Counter()); String expecting = "0 1 2 0"; // trace must be false to get these numbers String result = a.render(); //System.err.println("result='"+result+"'"); assertEquals(expecting, result); } @Test public void testTrueFalseArgs() throws Exception { String dir = getRandomDir(); String groupFile = "f(x,y) ::= \"\"\n" + "g() ::= \"\""; writeFile(dir, "group.stg", groupFile); STGroupFile group = new STGroupFile(dir+"/group.stg"); ST st = group.getInstanceOf("g"); String expected = "truea"; String result = st.render(); assertEquals(expected, result); } @Test public void testNamedArgsInOrder() throws Exception { String dir = getRandomDir(); String groupFile = "f(x,y) ::= \"\"\n" + "g() ::= \"\""; writeFile(dir, "group.stg", groupFile); STGroupFile group = new STGroupFile(dir+"/group.stg"); ST st = group.getInstanceOf("g"); String expected = "ab"; String result = st.render(); assertEquals(expected, result); } @Test public void testNamedArgsOutOfOrder() throws Exception { String dir = getRandomDir(); String groupFile = "f(x,y) ::= \"\"\n" + "g() ::= \"\""; writeFile(dir, "group.stg", groupFile); STGroupFile group = new STGroupFile(dir+"/group.stg"); ST st = group.getInstanceOf("g"); String expected = "ab"; String result = st.render(); assertEquals(expected, result); } @Test public void testUnknownNamedArg() throws Exception { String dir = getRandomDir(); String groupFile = "f(x,y) ::= \"\"\n" + "g() ::= \"\""; //012345678901234567 writeFile(dir, "group.stg", groupFile); STGroupFile group = new STGroupFile(dir+"/group.stg"); ErrorBuffer errors = new ErrorBuffer(); group.setListener(errors); ST st = group.getInstanceOf("g"); st.render(); String expected = "context [/g] 1:1 attribute z isn't defined"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testMissingNamedArg() throws Exception { String dir = getRandomDir(); String groupFile = "f(x,y) ::= \"\"\n" + "g() ::= \"\""; //01234567890123456789 writeFile(dir, "group.stg", groupFile); STGroupFile group = new STGroupFile(dir+"/group.stg"); ErrorBuffer errors = new ErrorBuffer(); group.setListener(errors); group.load(); String expected = "group.stg 2:18: mismatched input '{' expecting ELLIPSIS"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testNamedArgsNotAllowInIndirectInclude() throws Exception { String dir = getRandomDir(); String groupFile = "f(x,y) ::= \"\"\n" + //01234567890 1234567 8 9 "g(name) ::= \"<(name)(x={a},y={b})>\""; //012345678901 2345678901234567890123 4 writeFile(dir, "group.stg", groupFile); STGroupFile group = new STGroupFile(dir+"/group.stg"); ErrorBuffer errors = new ErrorBuffer(); group.setListener(errors); group.load(); String expected = "group.stg 2:22: '=' came as a complete surprise to me"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testCantSeeGroupDirIfGroupFileOfSameName() throws Exception { String dir = getRandomDir(); String a = "a() ::= <>\n"; writeFile(dir, "group/a.st", a); // can't see this file String groupFile = "b() ::= \"group file b\"\n"; writeFile(dir, "group.stg", groupFile); STGroup group1 = new STGroupDir(dir); ST st = group1.getInstanceOf("group/a"); // can't see assertEquals(null, st); } @Test public void testUnloadingSimpleGroup() throws Exception { String dir = getRandomDir(); String a = "a(x) ::= <>\n"; String b = "b() ::= <>\n"; writeFile(dir, "a.st", a); writeFile(dir, "b.st", b); STGroup group = new STGroupDir(dir); group.load(); // force load ST st = group.getInstanceOf("a"); int originalHashCode = System.identityHashCode(st); group.unload(); // blast cache st = group.getInstanceOf("a"); int newHashCode = System.identityHashCode(st); assertEquals(originalHashCode==newHashCode, false); // diff objects String expected = "foo"; String result = st.render(); assertEquals(expected, result); st = group.getInstanceOf("b"); expected = "bar"; result = st.render(); assertEquals(expected, result); } @Test public void testUnloadingGroupFile() throws Exception { String dir = getRandomDir(); String a = "a(x) ::= <>\n" + "b() ::= <>\n"; writeFile(dir, "a.stg", a); STGroup group = new STGroupFile(dir+"/a.stg"); group.load(); // force load ST st = group.getInstanceOf("a"); int originalHashCode = System.identityHashCode(st); group.unload(); // blast cache st = group.getInstanceOf("a"); int newHashCode = System.identityHashCode(st); assertEquals(originalHashCode==newHashCode, false); // diff objects String expected = "foo"; String result = st.render(); assertEquals(expected, result); st = group.getInstanceOf("b"); expected = "bar"; result = st.render(); assertEquals(expected, result); } @Test public void testGroupFileImport() throws Exception { // /randomdir/group1.stg (a template) and /randomdir/group2.stg with b. // group1 imports group2, a includes b String dir = getRandomDir(); String groupFile1 = "import \"group2.stg\"\n"+ "a(x) ::= <<\n"+ "foo\n"+ ">>\n"; writeFile(dir, "group1.stg", groupFile1); String groupFile2 = "b() ::= \"bar\"\n"; writeFile(dir, "group2.stg", groupFile2); STGroup group1 = new STGroupFile(dir+"/group1.stg"); // Is the imported template b found? ST stb = group1.getInstanceOf("b"); assertEquals("bar", stb.render()); // Is the include of b() resolved? ST sta = group1.getInstanceOf("a"); assertEquals("foobar", sta.render()); // Are the correct "ThatCreatedThisInstance" groups assigned assertEquals("group1",sta.groupThatCreatedThisInstance.getName()); assertEquals("group1",stb.groupThatCreatedThisInstance.getName()); // Are the correct (native) groups assigned for the templates assertEquals("group1",sta.impl.nativeGroup.getName()); assertEquals("group2",stb.impl.nativeGroup.getName()); } @Test public void testGetTemplateNames() throws Exception { String templates = "t() ::= \"foo\"\n" + "main() ::= \"\""; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir + "/t.stg"); // try to get an undefined template. // This will add an entry to the "templates" field in STGroup, however // this should not be returned. group.lookupTemplate("t2"); Set names = group.getTemplateNames(); // Should only contain "t" and "main" (not "t2") assertEquals(2, names.size()); assertTrue(names.contains("/t")); assertTrue(names.contains("/main")); } @Test public void testUnloadWithImports() throws Exception { writeFile(tmpdir, "t.stg", "import \"g1.stg\"\n\nmain() ::= <<\nv1-\n>>"); writeFile(tmpdir, "g1.stg", "f() ::= \"g1\""); writeFile(tmpdir, "g2.stg", "f() ::= \"g2\"\nf2() ::= \"f2\"\n"); STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir + "/t.stg"); ST st = group.getInstanceOf("main"); Assert.assertEquals("v1-g1", st.render()); // Change the text of group t, including the imports. writeFile(tmpdir, "t.stg", "import \"g2.stg\"\n\nmain() ::= <<\nv2-;\n>>"); group.unload(); st = group.getInstanceOf("main"); Assert.assertEquals("v2-g2;f2", st.render()); } @Test public void testLineBreakInGroup() throws Exception { String templates = "t() ::= <<"+newline+ "Foo <\\\\>"+newline+ " \t bar"+newline+ ">>"+newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir + File.separatorChar + "t.stg"); ST st = group.getInstanceOf("t"); Assert.assertNotNull(st); String expecting ="Foo bar"; Assert.assertEquals(expecting, st.render()); } @Test public void testLineBreakInGroup2() throws Exception { String templates = "t() ::= <<"+newline+ "Foo <\\\\> "+newline+ " \t bar"+newline+ ">>"+newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir + File.separatorChar + "t.stg"); ST st = group.getInstanceOf("t"); Assert.assertNotNull(st); String expecting ="Foo bar"; Assert.assertEquals(expecting, st.render()); } @Test public void testLineBreakMissingTrailingNewline() throws Exception { writeFile(tmpdir, "t.stg", "a(x) ::= <<<\\\\>\r\n>>"); // that is <<<\\>>> not an escaped >> ErrorBuffer errors = new ErrorBuffer(); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); ST st = group.getInstanceOf("a"); assertEquals("t.stg 1:15: Missing newline after newline escape <\\\\>" + newline, errors.toString()); st.add("x", "parrt"); String expected = ""; String result = st.render(); assertEquals(expected, result); } @Test public void testLineBreakWithScarfedTrailingNewline() throws Exception { writeFile(tmpdir, "t.stg", "a(x) ::= <<<\\\\>\r\n>>"); // \r\n removed as trailing whitespace ErrorBuffer errors = new ErrorBuffer(); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); ST st = group.getInstanceOf("a"); assertEquals("t.stg 1:15: Missing newline after newline escape <\\\\>" + newline, errors.toString()); st.add("x", "parrt"); String expected = ""; String result = st.render(); assertEquals(expected, result); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestImports.java000066400000000000000000000511441231426731300261400ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.Test; import org.stringtemplate.v4.*; import org.stringtemplate.v4.misc.ErrorBuffer; import static org.junit.Assert.*; import java.io.File; import java.net.URL; import java.net.URLClassLoader; public class TestImports extends BaseTest { @Test public void testImportDir() throws Exception { /* dir1 g.stg has a() that imports dir2 with absolute path dir2 a.st b.st */ String dir1 = getRandomDir()+"/dir1"; String dir2 = getRandomDir()+"/dir2"; String gstr = "import \""+dir2+"\"\n" + "a() ::= <>\n"; writeFile(dir1, "g.stg", gstr); String a = "a() ::= <>\n"; String b = "b() ::= <>\n"; writeFile(dir2, "a.st", a); writeFile(dir2, "b.st", b); STGroup group = new STGroupFile(dir1+"/g.stg"); ST st = group.getInstanceOf("b"); // visible only if import worked String expected = "dir2 b"; String result = st.render(); assertEquals(expected, result); } @Test public void testImportDirInJarViaCLASSPATH() throws Exception { /* sub g.stg has a() and imports base via classpath base a.st b.st */ String root = getRandomDir(); String sub = root +"/sub"; String base = root +"/base"; String gstr = "import \"base\"\n" + "a() ::= <>\n"; writeFile(sub, "g.stg", gstr); writeFile(base, "a.st", "a() ::= <>\n"); writeFile(base, "b.st", "b() ::= <>\n"); writeTestFile( "STGroup group = new STGroupFile(\"sub/g.stg\");\n" + "ST st = group.getInstanceOf(\"b\");\n"+ // visible only if import worked "String result = st.render();\n", root); compile("Test.java", root); // jar has sub, base as dirs in CLASSPATH jar("test.jar", new String[]{"sub", "base", "Test.class"}, root); deleteFile(root+"/sub"); deleteFile(root+"/base"); String result = java("Test", "test.jar", root); String expected = "base b\n"; assertEquals(expected, result); } @Test public void testImportGroupAtSameLevelInJar() throws Exception { /* org/foo/templates main.stg imports lib.stg lib.stg */ String root = getRandomDir(); System.out.println(root); String dir = root+"/org/foo/templates"; String main = "import \"lib.stg\"\n" + // should see in same dir as main.stg "a() ::= <
!>>\n"+ "b() ::= <
>\n"; writeFile(dir, "main.stg", main); String lib = "bold() ::= <>\n"; writeFile(dir, "lib.stg", lib); writeTestFile( "STGroup group = new STGroupFile(\"org/foo/templates/main.stg\");\n" + "ST st = group.getInstanceOf(\"a\");\n"+ "String result = st.render();\n", root); compile("Test.java", root); jar("test.jar", new String[] {"org", "Test.class"}, root); deleteFile(root+"/org"); String result = java("Test", "test.jar", root); String expected = "main a calls lib bold!\n"; assertEquals(expected, result); } @Test public void testImportGroupAtSameLevelInJar2() throws Exception { /* org/foo/templates main.stg imports lib.stg lib.stg */ String root = getRandomDir(); System.out.println(root); String dir = root+"/org/foo/templates"; String main = "import \"lib.stg\"\n" + // should see in same dir as main.stg "a() ::= <
!>>\n"+ "b() ::= <
>\n"; writeFile(dir, "main.stg", main); String lib = "bold() ::= <>\n"; writeFile(dir, "lib.stg", lib); writeTestFile( "URL url = new STGroup().getURL(\"org/foo/templates/main.stg\");\n" + "STGroup group = new STGroupFile(url,\"UTF-8\",'<','>');\n" + "ST st = group.getInstanceOf(\"a\");\n"+ "String result = st.render();\n", root); compile("Test.java", root); jar("test.jar", new String[] {"org", "Test.class"}, root); deleteFile(root+"/org"); String result = java("Test", "test.jar", root); String expected = "main a calls lib bold!\n"; assertEquals(expected, result); } @Test public void testImportGroupInJarViaCLASSPATH() throws Exception { /* org/foo/templates main.stg imports org/foo/lib/lib.stg org/foo/lib lib.stg */ String root = getRandomDir(); System.out.println(root); String dir = root+"/org/foo/templates"; String main = "import \"org/foo/lib/lib.stg\"\n" + "a() ::= <
!>>\n"+ "b() ::= <
>\n"; writeFile(dir, "main.stg", main); String lib = "bold() ::= <>\n"; dir = root+"/org/foo/lib"; writeFile(dir, "lib.stg", lib); writeTestFile( "STGroup group = new STGroupFile(\"org/foo/templates/main.stg\");\n" + "ST st = group.getInstanceOf(\"a\");\n"+ "String result = st.render();\n", root); compile("Test.java", root); jar("test.jar", new String[] {"org", "Test.class"}, root); deleteFile(root+"/org"); String result = java("Test", "test.jar", root); String expected = "main a calls lib bold!\n"; assertEquals(expected, result); } @Test public void testImportTemplateFileInJarViaCLASSPATH() throws Exception { /* org/foo/templates main.stg imports foo.st foo.st */ String root = getRandomDir(); System.out.println(root); String dir = root+"/org/foo/templates"; String main = "import \"foo.st\"\n" + // should see in same dir as main.stg "a() ::= <
!>>\n"+ "b() ::= <
>\n"; writeFile(dir, "main.stg", main); String foo = "foo() ::= <>\n"; writeFile(root, "foo.st", foo); writeTestFile( "STGroup group = new STGroupFile(\"org/foo/templates/main.stg\");\n" + "ST st = group.getInstanceOf(\"a\");\n"+ "String result = st.render();\n", root); compile("Test.java", root); jar("test.jar", new String[] {"org", "Test.class"}, root); deleteFile(root+"/org"); String result = java("Test", "test.jar", root); String expected = "main a calls foo!\n"; assertEquals(expected, result); } @Test public void testImportRelativeDir() throws Exception { /* dir g.stg has a() that imports subdir with relative path subdir a.st b.st c.st */ String dir = getRandomDir(); String gstr = "import \"subdir\"\n" + // finds subdir in dir "a() ::= <>\n"; writeFile(dir, "g.stg", gstr); String a = "a() ::= <>\n"; String b = "b() ::= <>\n"; String c = "c() ::= <>\n"; writeFile(dir, "subdir/a.st", a); writeFile(dir, "subdir/b.st", b); writeFile(dir, "subdir/c.st", c); STGroup group = new STGroupFile(dir +"/g.stg"); ST st = group.getInstanceOf("b"); // visible only if import worked String expected = "subdir b"; String result = st.render(); assertEquals(expected, result); st = group.getInstanceOf("c"); result = st.render(); expected = "subdir c"; assertEquals(expected, result); } @Test public void testImportRelativeDirInJarViaCLASSPATH() throws Exception { /* org/foo/templates g.stg has a() that imports subdir with relative path subdir a.st b.st c.st */ String root = getRandomDir(); System.out.println(root); String dir = root+"/org/foo/templates"; String gstr = "import \"subdir\"\n" + // finds subdir in dir "a() ::= <>\n"; writeFile(dir, "g.stg", gstr); String a = "a() ::= <>\n"; String b = "b() ::= <>\n"; String c = "c() ::= <>\n"; writeFile(dir, "subdir/a.st", a); writeFile(dir, "subdir/b.st", b); writeFile(dir, "subdir/c.st", c); jar("test.jar", new String[] {"org"}, root); deleteFile(root + "/org"); File path = new File(root + File.separatorChar + "test.jar"); assertTrue(path.isFile()); URLClassLoader loader = new URLClassLoader(new URL[] { path.toURI().toURL() }); STGroup group = new STGroupFile(loader.getResource("org/foo/templates/g.stg"), "UTF-8", '<', '>'); ST st = group.getInstanceOf("b"); String result = st.render(); String expected = "subdir b"; assertEquals(expected, result); } @Test public void testEmptyGroupImportGroupFileSameDir() throws Exception { /* dir group1.stg that imports group2.stg in same dir with just filename group2.stg has c() */ String dir = getRandomDir(); String groupFile = "import \"group2.stg\"\n"; writeFile(dir, "group1.stg", groupFile); groupFile = "c() ::= \"g2 c\"\n"; writeFile(dir, "group2.stg", groupFile); STGroup group1 = new STGroupFile(dir+"/group1.stg"); ST st = group1.getInstanceOf("c"); // should see c() String expected = "g2 c"; String result = st.render(); assertEquals(expected, result); } @Test public void testImportGroupFileSameDir() throws Exception { /* dir group1.stg that imports group2.stg in same dir with just filename group2.stg has c() */ String dir = getRandomDir(); String groupFile = "import \"group2.stg\"\n" + "a() ::= \"g1 a\"\n"+ "b() ::= \"\"\n"; writeFile(dir, "group1.stg", groupFile); groupFile = "c() ::= \"g2 c\"\n"; writeFile(dir, "group2.stg", groupFile); STGroup group1 = new STGroupFile(dir+"/group1.stg"); ST st = group1.getInstanceOf("c"); // should see c() String expected = "g2 c"; String result = st.render(); assertEquals(expected, result); } @Test public void testImportRelativeGroupFile() throws Exception { /* dir group1.stg that imports group2.stg in same dir with just filename subdir group2.stg has c() */ String dir = getRandomDir(); String groupFile = "import \"subdir/group2.stg\"\n" + "a() ::= \"g1 a\"\n"+ "b() ::= \"\"\n"; writeFile(dir, "group1.stg", groupFile); groupFile = "c() ::= \"g2 c\"\n"; writeFile(dir, "subdir/group2.stg", groupFile); STGroup group1 = new STGroupFile(dir+"/group1.stg"); ST st = group1.getInstanceOf("c"); // should see c() String expected = "g2 c"; String result = st.render(); assertEquals(expected, result); } @Test public void testImportTemplateFileSameDir() throws Exception { /* dir group1.stg (that imports c.st) c.st */ String dir = getRandomDir(); String groupFile = "import \"c.st\"\n" + "a() ::= \"g1 a\"\n"+ "b() ::= \"\"\n"; writeFile(dir, "group1.stg", groupFile); writeFile(dir, "c.st", "c() ::= \"c\"\n"); STGroup group1 = new STGroupFile(dir+"/group1.stg"); ST st = group1.getInstanceOf("c"); // should see c() String expected = "c"; String result = st.render(); assertEquals(expected, result); } @Test public void testImportRelativeTemplateFile() throws Exception { /* dir group1.stg that imports c.st subdir c.st */ String dir = getRandomDir(); String groupFile = "import \"subdir/c.st\"\n" + "a() ::= \"g1 a\"\n"+ "b() ::= \"\"\n"; writeFile(dir, "group1.stg", groupFile); String stFile = "c() ::= \"c\"\n"; writeFile(dir, "subdir/c.st", stFile); STGroup group1 = new STGroupFile(dir+"/group1.stg"); ST st = group1.getInstanceOf("c"); // should see c() String expected = "c"; String result = st.render(); assertEquals(expected, result); } @Test public void testImportTemplateFromAnotherGroupObject() throws Exception { /* dir1 a.st b.st dir2 a.st */ String dir1 = getRandomDir(); String a = "a() ::= <>\n"; String b = "b() ::= <>\n"; writeFile(dir1, "a.st", a); writeFile(dir1, "b.st", b); String dir2 = getRandomDir(); a = "a() ::= << >>\n"; writeFile(dir2, "a.st", a); STGroup group1 = new STGroupDir(dir1); STGroup group2 = new STGroupDir(dir2); group2.importTemplates(group1); ST st = group2.getInstanceOf("b"); String expected = "dir1 b"; String result = st.render(); assertEquals(expected, result); // do it again, but make a template ref imported template st = group2.getInstanceOf("a"); expected = " dir1 b "; result = st.render(); assertEquals(expected, result); } @Test public void testImportTemplateInGroupFileFromDir() throws Exception { /* dir x a.st y group.stg has b, c */ String dir = getRandomDir(); writeFile(dir, "x/a.st", "a() ::= << >>"); String groupFile = "b() ::= \"group file b\"\n"+ "c() ::= \"group file c\"\n"; writeFile(dir, "y/group.stg", groupFile); STGroup group1 = new STGroupDir(dir+"/x"); STGroup group2 = new STGroupFile(dir+"/y/group.stg"); group1.importTemplates(group2); ST st = group1.getInstanceOf("a"); String expected = " group file b "; String result = st.render(); assertEquals(expected, result); } @Test public void testImportTemplateInGroupFileFromGroupFile() throws Exception { String dir = getRandomDir(); String groupFile = "a() ::= \"g1 a\"\n"+ "b() ::= \"\"\n"; writeFile(dir, "x/group.stg", groupFile); groupFile = "b() ::= \"g2 b\"\n"+ "c() ::= \"g2 c\"\n"; writeFile(dir, "y/group.stg", groupFile); STGroup group1 = new STGroupFile(dir+"/x/group.stg"); STGroup group2 = new STGroupFile(dir+"/y/group.stg"); group1.importTemplates(group2); ST st = group1.getInstanceOf("b"); String expected = "g2 c"; String result = st.render(); assertEquals(expected, result); } @Test public void testImportTemplateFromSubdir() throws Exception { // /randomdir/x/subdir/a and /randomdir/y/subdir/b String dir = getRandomDir(); writeFile(dir, "x/subdir/a.st", "a() ::= << >>"); writeFile(dir, "y/subdir/b.st", "b() ::= <>"); STGroup group1 = new STGroupDir(dir+"/x"); STGroup group2 = new STGroupDir(dir+"/y"); group1.importTemplates(group2); ST st = group1.getInstanceOf("/subdir/a"); String expected = " x's subdir/b "; String result = st.render(); assertEquals(expected, result); } @Test public void testImportTemplateFromGroupFile() throws Exception { // /randomdir/x/subdir/a and /randomdir/y/subdir.stg which has a and b String dir = getRandomDir(); writeFile(dir, "x/subdir/a.st", "a() ::= << >>"); String groupFile = "a() ::= \"group file: a\"\n"+ "b() ::= \"group file: b\"\n"; writeFile(dir, "y/subdir.stg", groupFile); STGroup group1 = new STGroupDir(dir+"/x"); STGroup group2 = new STGroupDir(dir+"/y"); group1.importTemplates(group2); ST st = group1.getInstanceOf("subdir/a"); String expected = " group file: b "; String result = st.render(); assertEquals(expected, result); } @Test public void testPolymorphicTemplateReference() throws Exception { String dir1 = getRandomDir(); String b = "b() ::= <>\n"; writeFile(dir1, "b.st", b); String dir2 = getRandomDir(); String a = "a() ::= << >>\n"; b = "b() ::= <>\n"; writeFile(dir2, "a.st", a); writeFile(dir2, "b.st", b); STGroup group1 = new STGroupDir(dir1); STGroup group2 = new STGroupDir(dir2); group1.importTemplates(group2); // normal lookup; a created from dir2 calls dir2.b ST st = group2.getInstanceOf("a"); String expected = " dir2 b "; String result = st.render(); assertEquals(expected, result); // polymorphic lookup; a created from dir1 calls dir2.a which calls dir1.b st = group1.getInstanceOf("a"); expected = " dir1 b "; result = st.render(); assertEquals(expected, result); } @Test public void testSuper() throws Exception { String dir1 = getRandomDir(); String a = "a() ::= <>\n"; String b = "b() ::= <>\n"; writeFile(dir1, "a.st", a); writeFile(dir1, "b.st", b); String dir2 = getRandomDir(); a = "a() ::= << [] >>\n"; writeFile(dir2, "a.st", a); STGroup group1 = new STGroupDir(dir1); STGroup group2 = new STGroupDir(dir2); group2.importTemplates(group1); ST st = group2.getInstanceOf("a"); String expected = " [dir1 a] "; String result = st.render(); assertEquals(expected, result); } @Test public void testUnloadImportedTemplate() throws Exception { String dir1 = getRandomDir(); String a = "a() ::= <>\n"; String b = "b() ::= <>\n"; writeFile(dir1, "a.st", a); writeFile(dir1, "b.st", b); String dir2 = getRandomDir(); a = "a() ::= << >>\n"; writeFile(dir2, "a.st", a); STGroup group1 = new STGroupDir(dir1); STGroup group2 = new STGroupDir(dir2); group2.importTemplates(group1); ST st = group2.getInstanceOf("a"); ST st2 = group2.getInstanceOf("b"); int originalHashCode = System.identityHashCode(st); int originalHashCode2 = System.identityHashCode(st2); group1.unload(); // blast cache st = group2.getInstanceOf("a"); int newHashCode = System.identityHashCode(st); assertEquals(originalHashCode==newHashCode, false); // diff objects String expected = " dir1 b "; String result = st.render(); assertEquals(expected, result); st = group2.getInstanceOf("b"); int newHashCode2 = System.identityHashCode(st); assertEquals(originalHashCode2==newHashCode2, false); // diff objects result = st.render(); expected = "dir1 b"; assertEquals(expected, result); } @Test public void testUnloadImportedTemplatedSpecifiedInGroupFile() throws Exception { writeFile(tmpdir, "t.stg", "import \"g1.stg\"\n\nmain() ::= <<\nv1-\n>>"); writeFile(tmpdir, "g1.stg", "f() ::= \"g1\""); writeFile(tmpdir, "g2.stg", "f() ::= \"g2\"\nf2() ::= \"f2\"\n"); STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir + "/t.stg"); ST st = group.getInstanceOf("main"); assertEquals("v1-g1", st.render()); // Change the imports of group t. writeFile(tmpdir, "t.stg", "import \"g2.stg\"\n\nmain() ::= <<\nv2-;\n>>"); group.unload(); // will also unload already imported groups st = group.getInstanceOf("main"); assertEquals("v2-g2;f2", st.render()); } /** Cannot import from a group file unless it's the root. */ @Test public void testGroupFileInDirImportsAnotherGroupFile() throws Exception { // /randomdir/group.stg with a() imports /randomdir/imported.stg with b() // can't have groupdir then groupfile inside that imports String dir = getRandomDir(); String groupFile = "import \"imported.stg\"\n" + "a() ::= \"a: \"\n"; writeFile(dir, "group.stg", groupFile); String importedFile = "b() ::= \"b\"\n"; writeFile(dir, "imported.stg", importedFile); STErrorListener errors = new ErrorBuffer(); STGroup group = new STGroupDir(dir); group.setListener(errors); group.getInstanceOf("/group/a"); String result = errors.toString(); String expecting = "import illegal in group files embedded in STGroupDirs; import \"imported.stg\" in STGroupDir"; assertTrue(result.contains(expecting)); } @Test public void testGroupFileInDirImportsAGroupDir() throws Exception { /* dir g.stg has a() that imports subdir with relative path subdir b.st c.st */ String dir = getRandomDir(); String gstr = "import \"subdir\"\n" + // finds subdir in dir "a() ::= \"a: \"\n"; writeFile(dir, "g.stg", gstr); writeFile(dir, "subdir/b.st", "b() ::= \"b: \"\n"); writeFile(dir, "subdir/c.st", "c() ::= <>\n"); STGroup group = new STGroupFile(dir +"/g.stg"); ST st = group.getInstanceOf("a"); String expected = "a: b: subdir c"; String result = st.render(); assertEquals(expected, result); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestIndentation.java000066400000000000000000000241531231426731300267570ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.*; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroupFile; import static org.junit.Assert.assertEquals; public class TestIndentation extends BaseTest { @Test public void testIndentInFrontOfTwoExpr() throws Exception { String templates = "list(a,b) ::= <<" + " "+newline+ ">>"+newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST t = group.getInstanceOf("list"); t.impl.dump(); t.add("a", "Terence"); t.add("b", "Jim"); String expecting = " TerenceJim"; assertEquals(expecting, t.render()); } @Test public void testSimpleIndentOfAttributeList() throws Exception { String templates = "list(names) ::= <<" + " "+newline+ ">>"+newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST t = group.getInstanceOf("list"); t.add("names", "Terence"); t.add("names", "Jim"); t.add("names", "Sriram"); String expecting = " Terence"+newline+ " Jim"+newline+ " Sriram"; assertEquals(expecting, t.render()); } @Test public void testIndentOfMultilineAttributes() throws Exception { String templates = "list(names) ::= <<" + " "+newline+ ">>"+newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST t = group.getInstanceOf("list"); t.add("names", "Terence\nis\na\nmaniac"); t.add("names", "Jim"); t.add("names", "Sriram\nis\ncool"); String expecting = " Terence"+newline+ " is"+newline+ " a"+newline+ " maniac"+newline+ " Jim"+newline+ " Sriram"+newline+ " is"+newline+ " cool"; assertEquals(expecting, t.render()); } @Test public void testIndentOfMultipleBlankLines() throws Exception { String templates = "list(names) ::= <<" + " "+newline+ ">>"+newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST t = group.getInstanceOf("list"); t.add("names", "Terence\n\nis a maniac"); String expecting = " Terence"+newline+ ""+newline+ // no indent on blank line " is a maniac"; assertEquals(expecting, t.render()); } @Test public void testIndentBetweenLeftJustifiedLiterals() throws Exception { String templates = "list(names) ::= <<" + "Before:"+newline + " "+newline+ "after" +newline+ ">>"+newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST t = group.getInstanceOf("list"); t.add("names", "Terence"); t.add("names", "Jim"); t.add("names", "Sriram"); String expecting = "Before:" +newline+ " Terence"+newline+ " Jim"+newline+ " Sriram"+newline+ "after"; assertEquals(expecting, t.render()); } @Test public void testNestedIndent() throws Exception { String templates = "method(name,stats) ::= <<" + "void () {"+newline + "\t"+newline+ "}" +newline+ ">>"+newline+ "ifstat(expr,stats) ::= <<"+newline + "if () {"+newline + " "+newline + "}" + ">>"+newline + "assign(lhs,expr) ::= \"=;\""+newline ; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST t = group.getInstanceOf("method"); t.add("name", "foo"); ST s1 = group.getInstanceOf("assign"); s1.add("lhs", "x"); s1.add("expr", "0"); ST s2 = group.getInstanceOf("ifstat"); s2.add("expr", "x>0"); ST s2a = group.getInstanceOf("assign"); s2a.add("lhs", "y"); s2a.add("expr", "x+y"); ST s2b = group.getInstanceOf("assign"); s2b.add("lhs", "z"); s2b.add("expr", "4"); s2.add("stats", s2a); s2.add("stats", s2b); t.add("stats", s1); t.add("stats", s2); String expecting = "void foo() {"+newline+ "\tx=0;"+newline+ "\tif (x>0) {"+newline+ "\t y=x+y;"+newline+ "\t z=4;"+newline+ "\t}"+newline+ "}"; assertEquals(expecting, t.render()); } @Test public void testIndentedIFWithValueExpr() throws Exception { ST t = new ST( "begin"+newline+ " foo"+newline+ "end"+newline); t.add("x", "x"); String expecting="begin"+newline+" foo"+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testIndentedIFWithElse() throws Exception { ST t = new ST( "begin"+newline+ " foobar"+newline+ "end"+newline); t.add("x", "x"); String expecting="begin"+newline+" foo"+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testIndentedIFWithElse2() throws Exception { ST t = new ST( "begin"+newline+ " foobar"+newline+ "end"+newline); t.add("x", false); String expecting="begin"+newline+" bar"+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testIndentedIFWithNewlineBeforeText() throws Exception { STGroup group = new STGroup(); group.defineTemplate("t", "x", "begin"+newline+ " \n" + "foo\n" + // no indent; ignore IF indent " "+newline+ // ignore indent on if-tags on line by themselves "end"+newline); ST t = group.getInstanceOf("t"); t.add("x", "x"); String expecting="begin"+newline+"foo"+newline+"end"; String result = t.render(); assertEquals(expecting, result); } @Test public void testIndentedIFWithEndifNextLine() throws Exception { STGroup group = new STGroup(); group.defineTemplate("t", "x", "begin"+newline+ " foo\n" + // use indent and keep newline " "+newline+ // ignore indent on if-tags on line by themselves "end"+newline); ST t = group.getInstanceOf("t"); t.add("x", "x"); String expecting="begin"+newline+" foo"+newline+"end"; String result = t.render(); assertEquals(expecting, result); } @Test public void testIFWithIndentOnMultipleLines() throws Exception { ST t = new ST( "begin"+newline+ " "+newline+ " foo"+newline+ " "+newline+ " bar"+newline+ " "+newline+ "end"+newline); String expecting="begin"+newline+" bar"+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testIFWithIndentAndExprOnMultipleLines() throws Exception { ST t = new ST( "begin"+newline+ " "+newline+ " "+newline+ " "+newline+ " "+newline+ " "+newline+ "end"+newline); t.add("y", "y"); String expecting="begin"+newline+" y"+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testIFWithIndentAndExprWithIndentOnMultipleLines() throws Exception { ST t = new ST( "begin"+newline+ " "+newline+ " "+newline+ " "+newline+ " "+newline+ " "+newline+ "end"+newline); t.add("y", "y"); String expecting="begin"+newline+" y"+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testNestedIFWithIndentOnMultipleLines() throws Exception { ST t = new ST( "begin"+newline+ " "+newline+ " "+newline+ " foo"+newline+ " "+newline+ " "+newline+ " "+newline+ " foo"+newline+ " "+newline+ " "+newline+ "end"+newline); t.add("x", "x"); t.add("y", "y"); String expecting="begin"+newline+" foo"+newline+"end"+newline; // no indent String result = t.render(); assertEquals(expecting, result); } @Test public void testIFInSubtemplate() throws Exception { ST t = new ST( ""+newline+ " "+newline+ " "+newline+ " "+newline+ " "+newline+ "}>"+newline); t.add("names", "Ter"); t.add("y", "y"); String expecting=" y"+newline+newline; String result = t.render(); assertEquals(expecting, result); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestIndirectionAndEarlyEval.java000066400000000000000000000122241231426731300311760ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.Test; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroupFile; import org.stringtemplate.v4.misc.ErrorBuffer; import java.util.HashMap; import java.util.Map; import static org.junit.Assert.*; public class TestIndirectionAndEarlyEval extends BaseTest { @Test public void testEarlyEval() throws Exception { String template = "<(name)>"; ST st = new ST(template); st.add("name", "Ter"); String expected = "Ter"; String result = st.render(); assertEquals(expected, result); } @Test public void testIndirectTemplateInclude() throws Exception { STGroup group = new STGroup(); group.defineTemplate("foo", "bar"); String template = "<(name)()>"; group.defineTemplate("test", "name", template); ST st = group.getInstanceOf("test"); st.add("name", "foo"); String expected = "bar"; String result = st.render(); assertEquals(expected, result); } @Test public void testIndirectTemplateIncludeWithArgs() throws Exception { STGroup group = new STGroup(); group.defineTemplate("foo", "x,y", ""); String template = "<(name)({1},{2})>"; group.defineTemplate("test", "name", template); ST st = group.getInstanceOf("test"); st.add("name", "foo"); String expected = "12"; String result = st.render(); assertEquals(expected, result); } @Test public void testIndirectCallWithPassThru() throws Exception { // pass-through for dynamic template invocation is not supported by the // bytecode representation writeFile(tmpdir, "t.stg", "t1(x) ::= \"\"\n" + "main(x=\"hello\",t=\"t1\") ::= <<\n" + "<(t)(...)>\n" + ">>"); STGroup group = new STGroupFile(tmpdir + "/t.stg"); ErrorBuffer errors = new ErrorBuffer(); group.setListener(errors); ST st = group.getInstanceOf("main"); assertEquals("t.stg 2:34: mismatched input '...' expecting RPAREN" + newline, errors.toString()); assertNull(st); } @Test public void testIndirectTemplateIncludeViaTemplate() throws Exception { STGroup group = new STGroup(); group.defineTemplate("foo", "bar"); group.defineTemplate("tname", "foo"); String template = "<(tname())()>"; group.defineTemplate("test", "name", template); ST st = group.getInstanceOf("test"); String expected = "bar"; String result = st.render(); assertEquals(expected, result); } @Test public void testIndirectProp() throws Exception { String template = ": "; ST st = new ST(template); st.add("u", new TestCoreBasics.User(1, "parrt")); st.add("propname", "id"); String expected = "1: parrt"; String result = st.render(); assertEquals(expected, result); } @Test public void testIndirectMap() throws Exception { STGroup group = new STGroup(); group.defineTemplate("a", "x", "[]"); group.defineTemplate("test", "names,templateName", "hi !"); ST st = group.getInstanceOf("test"); st.add("names", "Ter"); st.add("names", "Tom"); st.add("names", "Sumana"); st.add("templateName", "a"); String expected = "hi [Ter][Tom][Sumana]!"; String result = st.render(); assertEquals(expected, result); } @Test public void testNonStringDictLookup() throws Exception { String template = ""; ST st = new ST(template); Map m = new HashMap(); m.put(36, "foo"); st.add("m", m); st.add("intkey", 36); String expected = "foo"; String result = st.render(); assertEquals(expected, result); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestInterptimeErrors.java000066400000000000000000000211761231426731300300220ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.Test; import org.stringtemplate.v4.*; import org.stringtemplate.v4.misc.*; import static org.junit.Assert.assertEquals; public class TestInterptimeErrors extends BaseTest { public static class UserHiddenName { protected String name; public UserHiddenName(String name) { this.name = name; } protected String getName() { return name; } } public static class UserHiddenNameField { protected String name; public UserHiddenNameField(String name) { this.name = name; } } @Test public void testMissingEmbeddedTemplate() throws Exception { ErrorBuffer errors = new ErrorBuffer(); String templates = "t() ::= \"\"" + Misc.newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); ST st = group.getInstanceOf("t"); st.render(); String expected = "context [/t] 1:1 no such template: /foo"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testMissingSuperTemplate() throws Exception { ErrorBuffer errors = new ErrorBuffer(); String templates = "t() ::= \"\"" + Misc.newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); String templates2 = "u() ::= \"blech\"" + Misc.newline; writeFile(tmpdir, "t2.stg", templates2); STGroup group2 = new STGroupFile(tmpdir+"/"+"t2.stg"); group.importTemplates(group2); ST st = group.getInstanceOf("t"); st.render(); String expected = "context [/t] 1:1 no such template: super.t"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testNoPropertyNotError() throws Exception { ErrorBuffer errors = new ErrorBuffer(); String templates = "t(u) ::= \"\"" + Misc.newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); ST st = group.getInstanceOf("t"); st.add("u", new User(32, "parrt")); st.render(); String expected = ""; String result = errors.toString(); assertEquals(expected, result); } @Test public void testHiddenPropertyNotError() throws Exception { ErrorBuffer errors = new ErrorBuffer(); String templates = "t(u) ::= \"\"" + Misc.newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); ST st = group.getInstanceOf("t"); st.add("u", new UserHiddenName("parrt")); st.render(); String expected = ""; String result = errors.toString(); assertEquals(expected, result); } @Test public void testHiddenFieldNotError() throws Exception { ErrorBuffer errors = new ErrorBuffer(); String templates = "t(u) ::= \"\"" + Misc.newline; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); ST st = group.getInstanceOf("t"); st.add("u", new UserHiddenNameField("parrt")); st.render(); String expected = ""; String result = errors.toString(); assertEquals(expected, result); } @Test public void testSoleArg() throws Exception { ErrorBuffer errors = new ErrorBuffer(); String templates = "t() ::= \"\"\n"+ "u(x,y) ::= \"\"\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); ST st = group.getInstanceOf("t"); st.render(); String expected = "context [/t] 1:1 passed 1 arg(s) to template /u with 2 declared arg(s)"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testSoleArgUsingApplySyntax() throws Exception { ErrorBuffer errors = new ErrorBuffer(); String templates = "t() ::= \"<{9}:u()>\"\n"+ "u(x,y) ::= \"\"\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); ST st = group.getInstanceOf("t"); String expected = "9"; String result = st.render(); assertEquals(expected, result); expected = "context [/t] 1:5 passed 1 arg(s) to template /u with 2 declared arg(s)"+newline; result = errors.toString(); assertEquals(expected, result); } @Test public void testUndefinedAttr() throws Exception { ErrorBuffer errors = new ErrorBuffer(); String templates = "t() ::= \"\"\n"+ "u() ::= \"\"\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); ST st = group.getInstanceOf("t"); st.render(); String expected = "context [/t /u] 1:1 attribute x isn't defined"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testParallelAttributeIterationWithMissingArgs() throws Exception { ErrorBuffer errors = new ErrorBuffer(); STGroup group = new STGroup(); group.setListener(errors); ST e = new ST(group, "@

}; separator=\", \">" ); e.add("names", "Ter"); e.add("names", "Tom"); e.add("phones", "1"); e.add("phones", "2"); e.add("salaries", "big"); e.render(); String errorExpecting = "1:23: anonymous template has 2 arg(s) but mapped across 3 value(s)" + newline + "context [anonymous] 1:23 passed 3 arg(s) to template /_sub1 with 2 declared arg(s)" + newline + "context [anonymous] 1:1 iterating through 3 values in zip map but template has 2 declared arguments" + newline; assertEquals(errorExpecting, errors.toString()); String expecting = "Ter@1, Tom@2"; assertEquals(expecting, e.render()); } @Test public void testStringTypeMismatch() throws Exception { ErrorBuffer errors = new ErrorBuffer(); STGroup group = new STGroup(); group.setListener(errors); ST e = new ST(group, ""); e.add("s", 34); e.render(); // generate the error String errorExpecting = "context [anonymous] 1:1 function trim expects a string not java.lang.Integer"+newline; assertEquals(errorExpecting, errors.toString()); } @Test public void testStringTypeMismatch2() throws Exception { ErrorBuffer errors = new ErrorBuffer(); STGroup group = new STGroup(); group.setListener(errors); ST e = new ST(group, ""); e.add("s", 34); e.render(); // generate the error String errorExpecting = "context [anonymous] 1:1 function strlen expects a string not java.lang.Integer"+newline; assertEquals(errorExpecting, errors.toString()); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestLexer.java000066400000000000000000000255641231426731300255710ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.Test; public class TestLexer extends BaseTest { @Test public void testOneExpr() throws Exception { String template = ""; String expected = "[[@0,0:0='<',,1:0], [@1,1:4='name',,1:1], " + "[@2,5:5='>',,1:5]]"; checkTokens(template, expected); } @Test public void testOneExprSurrounded() throws Exception { String template = "hi mom"; String expected = "[[@0,0:2='hi ',,1:0], [@1,3:3='<',,1:3], " + "[@2,4:7='name',,1:4], [@3,8:8='>',,1:8], " + "[@4,9:12=' mom',,1:9]]"; checkTokens(template, expected); } @Test public void testEscDelim() throws Exception { String template = "hi \\"; String expected = "[[@0,0:9='hi ',,1:0]]"; checkTokens(template, expected); } @Test public void testEscEsc() throws Exception { String template = "hi \\\\ foo"; String expected = "[[@0,0:8='hi \\ foo',,1:0]]"; checkTokens(template, expected); } @Test public void testEscDelimHasCorrectStartChar() throws Exception { String template = "\\,1:3]]"; checkTokens(template, expected); } @Test public void testEscChar() throws Exception { String template = "hi \\x"; String expected = "[[@0,0:4='hi \\x',,1:0]]"; checkTokens(template, expected); } @Test public void testString() throws Exception { String template = "hi \")>"; String expected = "[[@0,0:2='hi ',,1:0], [@1,3:3='<',,1:3], " + "[@2,4:6='foo',,1:4], [@3,7:7='(',,1:7], " + "[@4,8:8='a',,1:8], [@5,9:9='=',,1:9], " + "[@6,10:12='\">\"',,1:10], [@7,13:13=')',,1:13], " + "[@8,14:14='>',,1:14]]"; checkTokens(template, expected); } @Test public void testEscInString() throws Exception { String template = "hi \\\"\")>"; String expected = "[[@0,0:2='hi ',,1:0], [@1,3:3='<',,1:3], [@2,4:6='foo',,1:4], " + "[@3,7:7='(',,1:7], [@4,8:8='a',,1:8], [@5,9:9='=',,1:9], " + "[@6,10:14='\">\"\"',,1:10], [@7,15:15=')',,1:15], " + "[@8,16:16='>',,1:16]]"; checkTokens(template, expected); } @Test public void testSubtemplate() throws Exception { String template = "hi }>"; String expected = "[[@0,0:2='hi ',,1:0], [@1,3:3='<',,1:3], [@2,4:8='names',,1:4], [@3,9:9=':',,1:9], [@4,10:10='{',,1:10], [@5,11:11='n',,1:11], [@6,13:13='|',,1:13], [@7,15:15='<',,1:15], [@8,16:16='n',,1:16], [@9,17:17='>',,1:17], [@10,18:18='}',,1:18], [@11,19:19='>',,1:19]]"; checkTokens(template, expected); } @Test public void testSubtemplateNoArg() throws Exception { String template = "hi }>"; String expected = "[[@0,0:2='hi ',,1:0], [@1,3:3='<',,1:3], [@2,4:8='names',,1:4], [@3,9:9=':',,1:9], [@4,10:10='{',,1:10], [@5,11:11='n',,1:11], [@6,13:13='|',,1:13], [@7,15:15='<',,1:15], [@8,16:16='n',,1:16], [@9,17:17='>',,1:17], [@10,18:18='}',,1:18], [@11,19:19='>',,1:19]]"; checkTokens(template, expected); } @Test public void testSubtemplateMultiArgs() throws Exception { String template = "hi }>"; // semantically bogus String expected = "[[@0,0:2='hi ',,1:0], [@1,3:3='<',,1:3], [@2,4:8='names',,1:4], [@3,9:9=':',,1:9], [@4,10:10='{',,1:10], [@5,11:11='x',,1:11], [@6,12:12=',',,1:12], [@7,13:13='y',,1:13], [@8,15:15='|',,1:15], [@9,17:17='<',,1:17], [@10,18:18='x',,1:18], [@11,19:19='>',,1:19], [@12,20:20='<',,1:20], [@13,21:21='y',,1:21], [@14,22:22='>',,1:22], [@15,23:23='}',,1:23], [@16,24:24='>',,1:24]]"; checkTokens(template, expected); } @Test public void testNestedSubtemplate() throws Exception { String template = "hi }>}>"; String expected = "[[@0,0:2='hi ',,1:0], [@1,3:3='<',,1:3], [@2,4:8='names',,1:4], [@3,9:9=':',,1:9], [@4,10:10='{',,1:10], [@5,11:11='n',,1:11], [@6,13:13='|',,1:13], [@7,15:15='<',,1:15], [@8,16:16='n',,1:16], [@9,17:17=':',,1:17], [@10,18:18='{',,1:18], [@11,19:19='x',,1:19], [@12,20:20='|',,1:20], [@13,21:21='<',,1:21], [@14,22:22='x',,1:22], [@15,23:23='>',,1:23], [@16,24:24='}',,1:24], [@17,25:25='>',,1:25], [@18,26:26='}',,1:26], [@19,27:27='>',,1:27]]"; checkTokens(template, expected); } @Test public void testNestedList() throws Exception { String template = "*<[names, [\"foo\",\"bar\"]:{x|!},phones]; separator=\", \">*"; //01234567890123456 String expected = "[[@0,0:0='*',,1:0], [@1,1:1='<',,1:1], [@2,2:2='[',,1:2], [@3,3:7='names',,1:3], [@4,8:8=',',,1:8], [@5,10:10='[',,1:10], [@6,11:15='\"foo\"',,1:11], [@7,16:16=',',,1:16], [@8,17:21='\"bar\"',,1:17], [@9,22:22=']',,1:22], [@10,23:23=':',,1:23], [@11,24:24='{',,1:24], [@12,25:25='x',,1:25], [@13,26:26='|',,1:26], [@14,27:27='<',,1:27], [@15,28:28='x',,1:28], [@16,29:29='>',,1:29], [@17,30:30='!',,1:30], [@18,31:31='}',,1:31], [@19,32:32=',',,1:32], [@20,33:38='phones',,1:33], [@21,39:39=']',,1:39], [@22,40:40=';',,1:40], [@23,42:50='separator',,1:42], [@24,51:51='=',,1:51], [@25,52:55='\", \"',,1:52], [@26,56:56='>',,1:56], [@27,57:57='*',,1:57]]"; checkTokens(template, expected); } @Test public void testIF() throws Exception { String template = "works"; String expected = "[[@0,0:0='<',,1:0], [@1,1:2='if',,1:1], [@2,3:3='(',,1:3], " + "[@3,4:4='!',,1:4], [@4,5:8='name',,1:5], [@5,9:9=')',,1:9], " + "[@6,10:10='>',,1:10], [@7,11:15='works',,1:11], " + "[@8,16:16='<',,1:16], [@9,17:21='endif',,1:17], " + "[@10,22:22='>',,1:22]]"; checkTokens(template, expected); } @Test public void testIFNot() throws Exception { String template = "works"; String expected = "[[@0,0:0='<',,1:0], [@1,1:2='if',,1:1], [@2,3:3='(',,1:3], " + "[@3,4:4='!',,1:4], [@4,5:8='name',,1:5], [@5,9:9=')',,1:9], " + "[@6,10:10='>',,1:10], [@7,11:15='works',,1:11], " + "[@8,16:16='<',,1:16], [@9,17:21='endif',,1:17], " + "[@10,22:22='>',,1:22]]"; checkTokens(template, expected); } @Test public void testIFELSE() throws Exception { String template = "worksfail"; String expected = "[[@0,0:0='<',,1:0], [@1,1:2='if',,1:1], [@2,3:3='(',,1:3], " + "[@3,4:7='name',,1:4], [@4,8:8=')',,1:8], [@5,9:9='>',,1:9], " + "[@6,10:14='works',,1:10], [@7,15:15='<',,1:15], " + "[@8,16:19='else',,1:16], [@9,20:20='>',,1:20], " + "[@10,21:24='fail',,1:21], [@11,25:25='<',,1:25], " + "[@12,26:30='endif',,1:26], [@13,31:31='>',,1:31]]"; checkTokens(template, expected); } @Test public void testELSEIF() throws Exception { String template = "failworksfail"; String expected = "[[@0,0:0='<',,1:0], [@1,1:2='if',,1:1], [@2,3:3='(',,1:3], " + "[@3,4:7='name',,1:4], [@4,8:8=')',,1:8], [@5,9:9='>',,1:9], " + "[@6,10:13='fail',,1:10], [@7,14:14='<',,1:14], " + "[@8,15:20='elseif',,1:15], [@9,21:21='(',,1:21], " + "[@10,22:23='id',,1:22], [@11,24:24=')',,1:24], " + "[@12,25:25='>',,1:25], [@13,26:30='works',,1:26], " + "[@14,31:31='<',,1:31], [@15,32:35='else',,1:32], " + "[@16,36:36='>',,1:36], [@17,37:40='fail',,1:37], " + "[@18,41:41='<',,1:41], [@19,42:46='endif',,1:42], " + "[@20,47:47='>',,1:47]]"; checkTokens(template, expected); } @Test public void testEmbeddedRegion() throws Exception { String template = "<@r>foo<@end>"; String expected = "[[@0,0:0='<',,1:0], [@1,1:1='@',,1:1], [@2,2:2='r',,1:2], " + "[@3,3:3='>',,1:3], [@4,4:6='foo',,1:4], [@5,7:7='<',,1:7], " + "[@6,8:11='@end',,1:8], [@7,12:12='>',,1:12]]"; checkTokens(template, expected); } @Test public void testRegion() throws Exception { String template = "<@r()>"; String expected = "[[@0,0:0='<',,1:0], [@1,1:1='@',,1:1], [@2,2:2='r',,1:2], " + "[@3,3:3='(',,1:3], [@4,4:4=')',,1:4], [@5,5:5='>',,1:5]]"; checkTokens(template, expected); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestLineWrap.java000066400000000000000000000373061231426731300262300ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.Test; import java.io.StringWriter; import java.util.ArrayList; import static org.junit.Assert.assertEquals; public class TestLineWrap extends BaseTest { @Test public void testLineWrap() throws Exception { String templates = "array(values) ::= < };>>"+newline; writeFile(tmpdir, "t.stg", templates); org.stringtemplate.v4.STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); org.stringtemplate.v4.ST a = group.getInstanceOf("array"); a.add("values", new int[] {3,9,20,2,1,4,6,32,5,6,77,888,2,1,6,32,5,6,77, 4,9,20,2,1,4,63,9,20,2,1,4,6,32,5,6,77,6,32,5,6,77, 3,9,20,2,1,4,6,32,5,6,77,888,1,6,32,5}); String expecting = "int[] a = { 3,9,20,2,1,4,6,32,5,6,77,888," + newline + "2,1,6,32,5,6,77,4,9,20,2,1,4,63,9,20,2,1," + newline + "4,6,32,5,6,77,6,32,5,6,77,3,9,20,2,1,4,6," + newline + "32,5,6,77,888,1,6,32,5 };"; StringWriter sw = new StringWriter(); org.stringtemplate.v4.STWriter stw = new org.stringtemplate.v4.AutoIndentWriter(sw,newline); // force \n as newline stw.setLineWidth(40); a.write(stw); String result = sw.toString(); assertEquals(expecting, result); } @Test public void testLineWrapAnchored() throws Exception { String templates = "array(values) ::= < };>>"+newline; writeFile(tmpdir, "t.stg", templates); org.stringtemplate.v4.STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); org.stringtemplate.v4.ST a = group.getInstanceOf("array"); a.add("values", new int[] {3,9,20,2,1,4,6,32,5,6,77,888,2,1,6,32,5,6,77, 4,9,20,2,1,4,63,9,20,2,1,4,6,32,5,6,77,6,32,5,6,77, 3,9,20,2,1,4,6,32,5,6,77,888,1,6,32,5}); String expecting = "int[] a = { 3,9,20,2,1,4,6,32,5,6,77,888," + newline + " 2,1,6,32,5,6,77,4,9,20,2,1,4," + newline + " 63,9,20,2,1,4,6,32,5,6,77,6," + newline + " 32,5,6,77,3,9,20,2,1,4,6,32," + newline + " 5,6,77,888,1,6,32,5 };"; assertEquals(expecting, a.render(40)); } @Test public void testSubtemplatesAnchorToo() throws Exception { String templates = "array(values) ::= <<{ }>>"+newline; writeFile(tmpdir, "t.stg", templates); org.stringtemplate.v4.STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); final org.stringtemplate.v4.ST x = new org.stringtemplate.v4.ST("<\\n>{ }<\\n>"); x.groupThatCreatedThisInstance = group; x.add("stuff", "1"); x.add("stuff", "2"); x.add("stuff", "3"); org.stringtemplate.v4.ST a = group.getInstanceOf("array"); a.add("values", new ArrayList() {{ add("a"); add(x); add("b"); }}); String expecting = "{ a, " + newline + " { 1," + newline + " 2," + newline + " 3 }" + newline + " , b }"; assertEquals(expecting, a.render(40)); } @Test public void testFortranLineWrap() throws Exception { String templates = "func(args) ::= << FUNCTION line( )>>"+newline; writeFile(tmpdir, "t.stg", templates); org.stringtemplate.v4.STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); org.stringtemplate.v4.ST a = group.getInstanceOf("func"); a.add("args", new String[]{"a", "b", "c", "d", "e", "f"}); String expecting = " FUNCTION line( a,b,c,d," + newline + " ce,f )"; assertEquals(expecting, a.render(30)); } @Test public void testLineWrapWithDiffAnchor() throws Exception { String templates = "array(values) ::= <}; anchor> };>>"+newline; writeFile(tmpdir, "t.stg", templates); org.stringtemplate.v4.STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); org.stringtemplate.v4.ST a = group.getInstanceOf("array"); a.add("values", new int[] {3,9,20,2,1,4,6,32,5,6,77,888,2,1,6,32,5,6,77, 4,9,20,2,1,4,63,9,20,2,1,4,6}); String expecting = "int[] a = { 1,9,2,3,9,20,2,1,4," + newline + " 6,32,5,6,77,888,2," + newline + " 1,6,32,5,6,77,4,9," + newline + " 20,2,1,4,63,9,20,2," + newline + " 1,4,6 };"; assertEquals(expecting, a.render(30)); } @Test public void testLineWrapEdgeCase() throws Exception { String templates = "duh(chars) ::= \"}>\""+newline; writeFile(tmpdir, "t.stg", templates); org.stringtemplate.v4.STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); org.stringtemplate.v4.ST a = group.getInstanceOf("duh"); a.add("chars", new String[]{"a", "b", "c", "d", "e"}); // lineWidth==3 implies that we can have 3 characters at most String expecting = "abc" + newline + "de"; assertEquals(expecting, a.render(3)); } @Test public void testLineWrapLastCharIsNewline() throws Exception { String templates = "duh(chars) ::= <<" + newline + "" + newline + ">>"+newline; writeFile(tmpdir, "t.stg", templates); org.stringtemplate.v4.STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); org.stringtemplate.v4.ST a = group.getInstanceOf("duh"); a.add("chars", new String[]{"a", "b", newline, "d", "e"}); // don't do \n if it's last element anyway String expecting = "ab" + newline+ "de"; assertEquals(expecting,a.render(3)); } @Test public void testLineWrapCharAfterWrapIsNewline() throws Exception { String templates = "duh(chars) ::= <<" + newline + "" + newline + ">>"+newline; writeFile(tmpdir, "t.stg", templates); org.stringtemplate.v4.STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); org.stringtemplate.v4.ST a = group.getInstanceOf("duh"); a.add("chars", new String[]{"a", "b", "c", newline, "d", "e"}); // Once we wrap, we must dump chars as we see them. A newline right // after a wrap is just an "unfortunate" event. People will expect // a newline if it's in the data. String expecting = "abc" + newline + "" + newline + "de"; assertEquals(expecting, a.render(3)); } @Test public void testLineWrapForList() throws Exception { String templates = "duh(data) ::= <!>>"+newline; writeFile(tmpdir, "t.stg", templates); org.stringtemplate.v4.STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); org.stringtemplate.v4.ST a = group.getInstanceOf("duh"); a.add("data", new int[] {1,2,3,4,5,6,7,8,9}); String expecting = "!123" + newline + "4567" + newline + "89!"; assertEquals(expecting,a.render(4)); } @Test public void testLineWrapForAnonTemplate() throws Exception { String templates = "duh(data) ::= <]}; wrap>!>>"+newline; writeFile(tmpdir, "t.stg", templates); org.stringtemplate.v4.STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); org.stringtemplate.v4.ST a = group.getInstanceOf("duh"); a.add("data", new int[] {1,2,3,4,5,6,7,8,9}); String expecting = "![1][2][3]" + newline + // width=9 is the 3 char; don't break til after ] "[4][5][6]" + newline + "[7][8][9]!"; assertEquals(expecting,a.render(9)); } @Test public void testLineWrapForAnonTemplateAnchored() throws Exception { String templates = "duh(data) ::= <]}; anchor, wrap>!>>"+newline; writeFile(tmpdir, "t.stg", templates); org.stringtemplate.v4.STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); org.stringtemplate.v4.ST a = group.getInstanceOf("duh"); a.add("data", new int[] {1,2,3,4,5,6,7,8,9}); String expecting = "![1][2][3]" + newline + " [4][5][6]" + newline + " [7][8][9]!"; assertEquals(expecting, a.render(9)); } @Test public void testLineWrapForAnonTemplateComplicatedWrap() throws Exception { String templates = "top(s) ::= << .>>"+ "str(data) ::= <]}; wrap=\"!+\\n!\">!>>"+newline; writeFile(tmpdir, "t.stg", templates); org.stringtemplate.v4.STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); org.stringtemplate.v4.ST t = group.getInstanceOf("top"); org.stringtemplate.v4.ST s = group.getInstanceOf("str"); s.add("data", new int[] {1,2,3,4,5,6,7,8,9}); t.add("s", s); String expecting = " ![1][2]!+" + newline + " ![3][4]!+" + newline + " ![5][6]!+" + newline + " ![7][8]!+" + newline + " ![9]!."; assertEquals(expecting,t.render(9)); } @Test public void testIndentBeyondLineWidth() throws Exception { String templates = "duh(chars) ::= <<" +newline+ " " + newline + ">>"+newline; writeFile(tmpdir, "t.stg", templates); org.stringtemplate.v4.STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); org.stringtemplate.v4.ST a = group.getInstanceOf("duh"); a.add("chars", new String[]{"a", "b", "c", "d", "e"}); // String expecting = " a" + newline + " b" + newline + " c" + newline + " d" + newline + " e"; assertEquals(expecting, a.render(2)); } @Test public void testIndentedExpr() throws Exception { String templates = "duh(chars) ::= <<" +newline+ " " +newline+ ">>"+newline; writeFile(tmpdir, "t.stg", templates); org.stringtemplate.v4.STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); org.stringtemplate.v4.ST a = group.getInstanceOf("duh"); a.add("chars", new String[]{"a", "b", "c", "d", "e"}); // String expecting = " ab" + newline + " cd" + newline + " e"; // width=4 spaces + 2 char. assertEquals(expecting, a.render(6)); } @Test public void testNestedIndentedExpr() throws Exception { String templates = "top(d) ::= << !>>"+newline+ "duh(chars) ::= <<" +newline+ " " + newline+ ">>"+newline; writeFile(tmpdir, "t.stg", templates); org.stringtemplate.v4.STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); org.stringtemplate.v4.ST top = group.getInstanceOf("top"); org.stringtemplate.v4.ST duh = group.getInstanceOf("duh"); duh.add("chars", new String[]{"a", "b", "c", "d", "e"}); top.add("d", duh); String expecting = " ab" + newline + " cd" + newline + " e!"; // width=4 spaces + 2 char. assertEquals(expecting, top.render(6)); } @Test public void testNestedWithIndentAndTrackStartOfExpr() throws Exception { String templates = "top(d) ::= << !>>"+newline+ "duh(chars) ::= <<" +newline+ "x: " +newline+ ">>"+newline; writeFile(tmpdir, "t.stg", templates); org.stringtemplate.v4.STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); org.stringtemplate.v4.ST top = group.getInstanceOf("top"); org.stringtemplate.v4.ST duh = group.getInstanceOf("duh"); duh.add("chars", new String[]{"a", "b", "c", "d", "e"}); top.add("d", duh); // String expecting = " x: ab" + newline + " cd" + newline + " e!"; assertEquals(expecting, top.render(7)); } @Test public void testLineDoesNotWrapDueToLiteral() throws Exception { String templates = "m(args,body) ::= <<@Test public voidfoo() throws Ick { }>>"+newline; writeFile(tmpdir, "t.stg", templates); org.stringtemplate.v4.STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); org.stringtemplate.v4.ST a = group.getInstanceOf("m"); a.add("args", new String[]{"a", "b", "c"}); a.add("body", "i=3;"); // make it wrap because of ") throws Ick { " literal int n = "@Test public voidfoo(a, b, c".length(); String expecting = "@Test public voidfoo(a, b, c) throws Ick { i=3; }"; assertEquals(expecting, a.render(n)); } @Test public void testSingleValueWrap() throws Exception { String templates = "m(args,body) ::= <<{ }>>"+newline; writeFile(tmpdir, "t.stg", templates); org.stringtemplate.v4.STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); org.stringtemplate.v4.ST m = group.getInstanceOf("m"); m.add("body", "i=3;"); // make it wrap because of ") throws Ick { " literal String expecting = "{ " + newline+ " i=3; }"; assertEquals(expecting, m.render(2)); } @Test public void testLineWrapInNestedExpr() throws Exception { String templates = "top(arrays) ::= <done>>"+newline+ "array(values) ::= <%int[] a = { };<\\n>%>"+newline; writeFile(tmpdir, "t.stg", templates); org.stringtemplate.v4.STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir+"/"+"t.stg"); org.stringtemplate.v4.ST top = group.getInstanceOf("top"); org.stringtemplate.v4.ST a = group.getInstanceOf("array"); a.add("values", new int[] {3,9,20,2,1,4,6,32,5,6,77,888,2,1,6,32,5,6,77, 4,9,20,2,1,4,63,9,20,2,1,4,6,32,5,6,77,6,32,5,6,77, 3,9,20,2,1,4,6,32,5,6,77,888,1,6,32,5}); top.add("arrays", a); top.add("arrays", a); // add twice String expecting = "Arrays: int[] a = { 3,9,20,2,1,4,6,32,5," + newline + " 6,77,888,2,1,6,32,5," + newline + " 6,77,4,9,20,2,1,4,63," + newline + " 9,20,2,1,4,6,32,5,6," + newline + " 77,6,32,5,6,77,3,9,20," + newline + " 2,1,4,6,32,5,6,77,888," + newline + " 1,6,32,5 };" + newline + "int[] a = { 3,9,20,2,1,4,6,32,5,6,77,888," + newline + " 2,1,6,32,5,6,77,4,9,20,2,1,4," + newline + " 63,9,20,2,1,4,6,32,5,6,77,6," + newline + " 32,5,6,77,3,9,20,2,1,4,6,32," + newline + " 5,6,77,888,1,6,32,5 };" + newline + "done"; assertEquals(expecting, top.render(40)); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestLists.java000066400000000000000000000145421231426731300256020ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.Test; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroupFile; import static org.junit.Assert.assertEquals; public class TestLists extends BaseTest { @Test public void testJustCat() throws Exception { ST e = new ST( "<[names,phones]>" ); e.add("names", "Ter"); e.add("names", "Tom"); e.add("phones", "1"); e.add("phones", "2"); String expecting = "TerTom12"; assertEquals(expecting, e.render()); } @Test public void testListLiteralWithEmptyElements() throws Exception { ST e = new ST( "<[\"Ter\",,\"Jesse\"]:{n | :}; separator=\", \", null={foo}>" ); String expecting = "1:Ter, foo, 2:Jesse"; assertEquals(expecting, e.render()); } @Test public void testListLiteralWithEmptyFirstElement() throws Exception { ST e = new ST( "<[,\"Ter\",\"Jesse\"]:{n | :}; separator=\", \", null={foo}>" ); String expecting = "foo, 1:Ter, 2:Jesse"; assertEquals(expecting, e.render()); } @Test public void testLength() throws Exception { ST e = new ST( "" ); e.add("names", "Ter"); e.add("names", "Tom"); e.add("phones", "1"); e.add("phones", "2"); String expecting = "4"; assertEquals(expecting, e.render()); } @Test public void testCat2Attributes() throws Exception { ST e = new ST( "<[names,phones]; separator=\", \">" ); e.add("names", "Ter"); e.add("names", "Tom"); e.add("phones", "1"); e.add("phones", "2"); String expecting = "Ter, Tom, 1, 2"; assertEquals(expecting, e.render()); } @Test public void testCat2AttributesWithApply() throws Exception { ST e = new ST( "<[names,phones]:{a|.}>" ); e.add("names", "Ter"); e.add("names", "Tom"); e.add("phones", "1"); e.add("phones", "2"); String expecting = "Ter.Tom.1.2."; assertEquals(expecting, e.render()); } @Test public void testCat3Attributes() throws Exception { ST e = new ST( "<[names,phones,salaries]; separator=\", \">" ); e.add("names", "Ter"); e.add("names", "Tom"); e.add("phones", "1"); e.add("phones", "2"); e.add("salaries", "big"); e.add("salaries", "huge"); String expecting = "Ter, Tom, 1, 2, big, huge"; assertEquals(expecting, e.render()); } @Test public void testCatWithTemplateApplicationAsElement() throws Exception { ST e = new ST( "<[names:{n|!},phones]; separator=\", \">" ); e.add("names", "Ter"); e.add("names", "Tom"); e.add("phones" , "1"); e.add("phones", "2"); String expecting = "Ter!, Tom!, 1, 2"; assertEquals(expecting, e.render()); } @Test public void testCatWithIFAsElement() throws Exception { ST e = new ST( "<[{doh},phones]; separator=\", \">" ); e.add("names", "Ter"); e.add("names", "Tom"); e.add("phones" , "1"); e.add("phones", "2"); String expecting = "doh, 1, 2"; assertEquals(expecting, e.render()); } @Test public void testCatNullValues() throws Exception { // [a, b] must behave like ; if a==b==null, blank output // unless null argument. ST e = new ST( "<[no,go]; null=\"foo\", separator=\", \">" ); e.add("phones", "1"); e.add("phones", "2"); String expecting = "foo, foo"; assertEquals(expecting, e.render()); } @Test public void testCatWithNullTemplateApplicationAsElement() throws Exception { ST e = new ST( "<[names:{n|!},\"foo\"]:{a|x}; separator=\", \">" ); e.add("phones", "1"); e.add("phones", "2"); String expecting = "x"; // only one since template application gives nothing assertEquals(expecting, e.render()); } @Test public void testCatWithNestedTemplateApplicationAsElement() throws Exception { ST e = new ST( "<[names, [\"foo\",\"bar\"]:{x | !},phones]; separator=\", \">" ); e.add("names", "Ter"); e.add("names", "Tom"); e.add("phones", "1"); e.add("phones", "2"); String expecting = "Ter, Tom, foo!, bar!, 1, 2"; assertEquals(expecting, e.render()); } @Test public void testListAsTemplateArgument() throws Exception { String templates = "test(names,phones) ::= \"\""+newline+ "foo(items) ::= \"*}>\""+newline ; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); ST e = group.getInstanceOf("test"); e.add("names", "Ter"); e.add("names", "Tom"); e.add("phones", "1"); e.add("phones", "2"); String expecting = "*Ter**Tom**1**2*"; String result = e.render(); assertEquals(expecting, result); } @Test public void testListWithTwoEmptyListsCollapsesToEmptyList() throws Exception { ST e = new ST( "<[[],[]]:{x | !}; separator=\", \">" ); e.add("names", "Ter"); e.add("names", "Tom"); String expecting = ""; assertEquals(expecting, e.render()); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestModelAdaptors.java000066400000000000000000000107241231426731300272400ustar00rootroot00000000000000package org.stringtemplate.v4.test; import org.junit.*; import org.stringtemplate.v4.*; import org.stringtemplate.v4.misc.STNoSuchPropertyException; import org.stringtemplate.v4.misc.STRuntimeMessage; import static org.junit.Assert.assertEquals; public class TestModelAdaptors extends BaseTest { static class UserAdaptor implements ModelAdaptor { @Override public Object getProperty(Interpreter interp, ST self, Object o, Object property, String propertyName) throws STNoSuchPropertyException { if ( propertyName.equals("id") ) return ((User)o).id; if ( propertyName.equals("name") ) return ((User)o).getName(); throw new STNoSuchPropertyException(null, o, "User."+propertyName); } } static class UserAdaptorConst implements ModelAdaptor { @Override public Object getProperty(Interpreter interp, ST self, Object o, Object property, String propertyName) throws STNoSuchPropertyException { if ( propertyName.equals("id") ) return "const id value"; if ( propertyName.equals("name") ) return "const name value"; throw new STNoSuchPropertyException(null, o, "User."+propertyName); } } static class SuperUser extends User { int bitmask; public SuperUser(int id, String name) { super(id, name); bitmask = 0x8080; } @Override public String getName() { return "super "+super.getName(); } } @Test public void testSimpleAdaptor() throws Exception { String templates = "foo(x) ::= \": \"\n"; writeFile(tmpdir, "foo.stg", templates); STGroup group = new STGroupFile(tmpdir+"/foo.stg"); group.registerModelAdaptor(User.class, new UserAdaptor()); ST st = group.getInstanceOf("foo"); st.add("x", new User(100, "parrt")); String expecting = "100: parrt"; String result = st.render(); assertEquals(expecting, result); } @Test public void testAdaptorAndBadProp() throws Exception { ErrorBufferAllErrors errors = new ErrorBufferAllErrors(); String templates = "foo(x) ::= \"\"\n"; writeFile(tmpdir, "foo.stg", templates); STGroup group = new STGroupFile(tmpdir+"/foo.stg"); group.setListener(errors); group.registerModelAdaptor(User.class, new UserAdaptor()); ST st = group.getInstanceOf("foo"); st.add("x", new User(100, "parrt")); String expecting = ""; String result = st.render(); assertEquals(expecting, result); STRuntimeMessage msg = (STRuntimeMessage)errors.errors.get(0); STNoSuchPropertyException e = (STNoSuchPropertyException)msg.cause; assertEquals("User.qqq", e.propertyName); } @Test public void testAdaptorCoversSubclass() throws Exception { String templates = "foo(x) ::= \": \"\n"; writeFile(tmpdir, "foo.stg", templates); STGroup group = new STGroupFile(tmpdir+"/foo.stg"); group.registerModelAdaptor(User.class, new UserAdaptor()); ST st = group.getInstanceOf("foo"); st.add("x", new SuperUser(100, "parrt")); // create subclass of User String expecting = "100: super parrt"; String result = st.render(); assertEquals(expecting, result); } @Test public void testWeCanResetAdaptorCacheInvalidatedUponAdaptorReset() throws Exception { String templates = "foo(x) ::= \": \"\n"; writeFile(tmpdir, "foo.stg", templates); STGroup group = new STGroupFile(tmpdir+"/foo.stg"); group.registerModelAdaptor(User.class, new UserAdaptor()); group.getModelAdaptor(User.class); // get User, SuperUser into cache group.getModelAdaptor(SuperUser.class); group.registerModelAdaptor(User.class, new UserAdaptorConst()); // cache should be reset so we see new adaptor ST st = group.getInstanceOf("foo"); st.add("x", new User(100, "parrt")); String expecting = "const id value: const name value"; // sees UserAdaptorConst String result = st.render(); assertEquals(expecting, result); } @Test public void testSeesMostSpecificAdaptor() throws Exception { String templates = "foo(x) ::= \": \"\n"; writeFile(tmpdir, "foo.stg", templates); STGroup group = new STGroupFile(tmpdir+"/foo.stg"); group.registerModelAdaptor(User.class, new UserAdaptor()); group.registerModelAdaptor(SuperUser.class, new UserAdaptorConst()); // most specific ST st = group.getInstanceOf("foo"); st.add("x", new User(100, "parrt")); String expecting = "100: parrt"; String result = st.render(); assertEquals(expecting, result); st.remove("x"); st.add("x", new SuperUser(100, "parrt")); expecting = "const id value: const name value"; // sees UserAdaptorConst result = st.render(); assertEquals(expecting, result); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestNoNewlineTemplates.java000066400000000000000000000113501231426731300302530ustar00rootroot00000000000000/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.Test; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroupFile; import org.stringtemplate.v4.STGroupString; import static org.junit.Assert.assertEquals; public class TestNoNewlineTemplates extends BaseTest { @Test public void testNoNewlineTemplate() throws Exception { String template = "t(x) ::= <%\n" + "[ " + "" + "\n" + "" + "\n" + "\n" + "]\n" + "\n" + "%>\n"; STGroup g = new STGroupString(template); ST st = g.getInstanceOf("t"); st.add("x", 99); String expected = "[ 99]"; String result = st.render(); assertEquals(expected, result); } @Test public void testWSNoNewlineTemplate() throws Exception { String template = "t(x) ::= <%\n" + "\n" + "%>\n"; STGroup g = new STGroupString(template); ST st = g.getInstanceOf("t"); st.add("x", 99); String expected = ""; String result = st.render(); assertEquals(expected, result); } @Test public void testEmptyNoNewlineTemplate() throws Exception { String template = "t(x) ::= <%%>\n"; STGroup g = new STGroupString(template); ST st = g.getInstanceOf("t"); st.add("x", 99); String expected = ""; String result = st.render(); assertEquals(expected, result); } @Test public void testIgnoreIndent() throws Exception { String template = "t(x) ::= <%\n" + " foo\n" + " \n" + "%>\n"; STGroup g = new STGroupString(template); ST st = g.getInstanceOf("t"); st.add("x", 99); String expected = "foo99"; String result = st.render(); assertEquals(expected, result); } @Test public void testIgnoreIndentInIF() throws Exception { String template = "t(x) ::= <%\n" + " \n" + " foo\n" + " \n" + " \n" + "%>\n"; STGroup g = new STGroupString(template); ST st = g.getInstanceOf("t"); st.add("x", 99); String expected = "foo99"; String result = st.render(); assertEquals(expected, result); } @Test public void testKeepWS() throws Exception { String template = "t(x) ::= <%\n" + " hi\n" + "%>\n"; STGroup g = new STGroupString(template); ST st = g.getInstanceOf("t"); st.add("x", 99); String expected = "99 99 hi"; String result = st.render(); assertEquals(expected, result); } @Test public void testRegion() throws Exception { String template = "t(x) ::= <%\n" + "<@r>\n" + " Ignore\n" + " newlines and indents\n" + "\n\n\n" + "<@end>\n" + "%>\n"; STGroup g = new STGroupString(template); ST st = g.getInstanceOf("t"); st.add("x", 99); String expected = "Ignorenewlines and indents99"; String result = st.render(); assertEquals(expected, result); } @Test public void testDefineRegionInSubgroup() throws Exception { String dir = getRandomDir(); String g1 = "a() ::= <<[<@r()>]>>\n"; writeFile(dir, "g1.stg", g1); String g2 = "@a.r() ::= <%\n" + " foo\n\n\n" + "%>\n"; writeFile(dir, "g2.stg", g2); STGroup group1 = new STGroupFile(dir+"/g1.stg"); STGroup group2 = new STGroupFile(dir+"/g2.stg"); group2.importTemplates(group1); // define r in g2 ST st = group2.getInstanceOf("a"); String expected = "[foo]"; String result = st.render(); assertEquals(expected, result); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestNullAndEmptyValues.java000066400000000000000000000405621231426731300302410ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.Test; import org.stringtemplate.v4.AutoIndentWriter; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroupFile; import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; public class TestNullAndEmptyValues extends BaseTest { public static class T { String template; Object x; String expecting; String result; public T(String template, Object x, String expecting) { this.template = template; this.x = x; this.expecting = expecting; } public T(T t) { this.template = t.template; this.x = t.x; this.expecting = t.expecting; } @Override public String toString() { String s = x.toString(); if ( x.getClass().isArray() ) { s = Arrays.toString((Object[])x); } return "('"+template+"', "+s+", '"+expecting+"', '"+result+"')"; } } final static Object UNDEF = ""; final static List LIST0 = new ArrayList(); final static T[] singleValuedTests = new T[] { new T("", UNDEF, ""), new T("", null, ""), new T("", "", ""), new T("", LIST0, ""), new T("", UNDEF, ""), new T("", null, ""), new T("", "", ""), new T("", LIST0, ""), new T("", UNDEF, "y"), new T("", null, "y"), new T("", "", ""), new T("", LIST0, ""), new T("", UNDEF, "y"), new T("", null, "y"), new T("", "", ""), new T("", LIST0, ""), new T("y", UNDEF, ""), new T("y", null, ""), new T("y", "", "y"), new T("y", LIST0, ""), new T("yz", UNDEF, "z"), new T("yz", null, "z"), new T("yz", "", "y"), new T("yz", LIST0, "z"), }; final static String[] LISTa = {"a"}; final static String[] LISTab = {"a", "b"}; final static String[] LISTnull = {null}; final static String[] LISTa_null = {"a",null}; final static String[] LISTnull_b = {null,"b"}; final static String[] LISTa_null_b = {"a",null,"b"}; final static T[] multiValuedTests = new T[] { new T("", LIST0, ""), new T("", LISTa, "a"), new T("", LISTab, "ab"), new T("", LISTnull, ""), new T("", LISTnull_b, "b"), new T("", LISTa_null, "a"), new T("", LISTa_null_b, "ab"), new T("", LIST0, ""), new T("", LISTa, "a"), new T("", LISTab, "ab"), new T("", LISTnull, "y"), new T("", LISTnull_b, "yb"), new T("", LISTa_null, "ay"), new T("", LISTa_null_b, "ayb"), new T("", LIST0, ""), new T("", LISTa, "a"), new T("", LISTab, "a,b"), new T("", LISTnull, ""), new T("", LISTnull_b, "b"), new T("", LISTa_null, "a"), new T("", LISTa_null_b, "a,b"), new T("", LIST0, ""), new T("", LISTa, "a"), new T("", LISTab, "a,b"), new T("", LISTnull, "y"), new T("", LISTnull_b, "y,b"), new T("", LISTa_null, "a,y"), new T("", LISTa_null_b, "a,y,b"), new T("y", LIST0, ""), new T("y", LISTa, "y"), new T("y", LISTab, "y"), new T("y", LISTnull, "y"), new T("y", LISTnull_b, "y"), new T("y", LISTa_null, "y"), new T("y", LISTa_null_b, "y"), new T("}>", LIST0, ""), new T("}>", LISTa, "a"), new T("}>", LISTab, "ab"), new T("}>", LISTnull, ""), new T("}>", LISTnull_b, "b"), new T("}>", LISTa_null, "a"), new T("}>", LISTa_null_b, "ab"), new T("}; null={y}>", LIST0, ""), new T("}; null={y}>", LISTa, "a"), new T("}; null={y}>", LISTab, "ab"), new T("}; null={y}>", LISTnull, "y"), new T("}; null={y}>", LISTnull_b, "yb"), new T("}; null={y}>", LISTa_null, "ay"), new T("}; null={y}>", LISTa_null_b, "ayb"), new T(".}>", LIST0, ""), new T(".}>", LISTa, "1.a"), new T(".}>", LISTab, "1.a2.b"), new T(".}>", LISTnull, ""), new T(".}>", LISTnull_b, "1.b"), new T(".}>", LISTa_null, "1.a"), new T(".}>", LISTa_null_b, "1.a2.b"), new T(".}; null={y}>", LIST0, ""), new T(".}; null={y}>", LISTa, "1.a"), new T(".}; null={y}>", LISTab, "1.a2.b"), new T(".}; null={y}>", LISTnull, "y"), new T(".}; null={y}>", LISTnull_b, "y1.b"), new T(".}; null={y}>", LISTa_null, "1.ay"), new T(".}; null={y}>", LISTa_null_b, "1.ay2.b"), new T("y}; null={z}>", LIST0, ""), new T("y}; null={z}>", LISTa, "x"), new T("y}; null={z}>", LISTab, "xx"), new T("y}; null={z}>", LISTnull, "z"), new T("y}; null={z}>", LISTnull_b, "zx"), new T("y}; null={z}>", LISTa_null, "xz"), new T("y}; null={z}>", LISTa_null_b, "xzx"), new T("", LIST0, ""), new T("", LISTa, "a"), new T("", LISTab, "ab"), new T("", LISTnull, "y"), new T("", LISTnull_b, "yb"), new T("", LISTa_null, "ay"), new T("", LISTa_null_b, "ayb") }; final static T[] listTests = new T[] { new T("<[]>", UNDEF, ""), new T("<[]; null={x}>", UNDEF, ""), new T("<[]:{it | x}>", UNDEF, ""), new T("<[[],[]]:{it| x}>", UNDEF, ""), new T("<[]:t()>", UNDEF, ""), }; @Test public void testSingleValued() throws Exception { List failed = testMatrix(singleValuedTests); List expecting = new ArrayList(); assertArrayEquals("failed tests "+failed, expecting.toArray(), failed.toArray()); } @Test public void testMultiValued() throws Exception { List failed = testMatrix(multiValuedTests); List expecting = new ArrayList(); assertArrayEquals("failed tests "+failed, expecting.toArray(), failed.toArray()); } @Test public void testLists() throws Exception { List failed = testMatrix(listTests); List expecting = new ArrayList(); assertArrayEquals("failed tests "+failed, expecting.toArray(), failed.toArray()); } public List testMatrix(T[] tests) throws Exception { List failed = new ArrayList(); for (T t : tests) { T test = new T(t); // dup since we might mod with result STGroup group = new STGroup(); // System.out.println("running "+test); group.defineTemplate("t", "x", ""); group.defineTemplate("u", "x", ""); group.defineTemplate("test", "x", test.template); ST st = group.getInstanceOf("test"); if ( test.x!=UNDEF ) { st.add("x", test.x); } String result = st.render(); if ( !result.equals(test.expecting) ) { test.result = result; failed.add(test); } } return failed; } @Test public void testSeparatorWithNullFirstValue() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "name", "hi !"); ST st = group.getInstanceOf("test"); st.add("name", null); // null is added to list, but ignored in iteration st.add("name", "Tom"); st.add("name", "Sumana"); String expected = "hi Tom, Sumana!"; String result = st.render(); assertEquals(expected, result); } @Test public void testTemplateAppliedToNullIsEmpty() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "name", ""); group.defineTemplate("t", "x", ""); ST st = group.getInstanceOf("test"); st.add("name", null); String expected = ""; String result = st.render(); assertEquals(expected, result); } @Test public void testTemplateAppliedToMissingValueIsEmpty() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "name", ""); group.defineTemplate("t", "x", ""); ST st = group.getInstanceOf("test"); String expected = ""; String result = st.render(); assertEquals(expected, result); } @Test public void testSeparatorWithNull2ndValue() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "name", "hi !"); ST st = group.getInstanceOf("test"); st.add("name", "Ter"); st.add("name", null); st.add("name", "Sumana"); String expected = "hi Ter, Sumana!"; String result = st.render(); assertEquals(expected, result); } @Test public void testSeparatorWithNullLastValue() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "name", "hi !"); ST st = group.getInstanceOf("test"); st.add("name", "Ter"); st.add("name", "Tom"); st.add("name", null); String expected = "hi Ter, Tom!"; String result = st.render(); assertEquals(expected, result); } @Test public void testSeparatorWithTwoNullValuesInRow() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "name", "hi !"); ST st = group.getInstanceOf("test"); st.add("name", "Ter"); st.add("name", "Tom"); st.add("name", null); st.add("name", null); st.add("name", "Sri"); String expected = "hi Ter, Tom, Sri!"; String result = st.render(); assertEquals(expected, result); } @Test public void testTwoNullValues() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "name", "hi !"); ST st = group.getInstanceOf("test"); st.add("name", null); st.add("name", null); String expected = "hi xx!"; String result = st.render(); assertEquals(expected, result); } @Test public void testNullListItemNotCountedForIteratorIndex() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "name", ":}>"); ST st = group.getInstanceOf("test"); st.add("name", "Ter"); st.add("name", null); st.add("name", null); st.add("name", "Jesse"); String expected = "1:Ter2:Jesse"; String result = st.render(); assertEquals(expected, result); } @Test public void testSizeZeroButNonNullListGetsNoOutput() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "users", "begin\n" + "\n" + "end\n"); ST t = group.getInstanceOf("test"); t.add("users", null); String expecting="begin"+newline+"end"; String result = t.render(); assertEquals(expecting, result); } @Test public void testNullListGetsNoOutput() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "users", "begin\n" + "}; separator=\", \">\n" + "end\n"); ST t = group.getInstanceOf("test"); String expecting="begin"+newline+"end"; String result = t.render(); assertEquals(expecting, result); } @Test public void testEmptyListGetsNoOutput() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "users", "begin\n" + "}; separator=\", \">\n" + "end\n"); ST t = group.getInstanceOf("test"); t.add("users", new ArrayList()); String expecting="begin"+newline+"end"; String result = t.render(); assertEquals(expecting, result); } @Test public void testMissingDictionaryValue() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "m", ""); ST t = group.getInstanceOf("test"); t.add("m", new HashMap()); String expecting=""; String result = t.render(); assertEquals(expecting, result); } @Test public void testMissingDictionaryValue2() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "m", "[]"); ST t = group.getInstanceOf("test"); t.add("m", new HashMap()); String expecting=""; String result = t.render(); assertEquals(expecting, result); } @Test public void testMissingDictionaryValue3() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "m", "[]"); ST t = group.getInstanceOf("test"); t.add("m", new HashMap() {{put("foo",null);}}); String expecting=""; String result = t.render(); assertEquals(expecting, result); } @Test public void TestSeparatorEmittedForEmptyIteratorValue() throws IOException { ST st = new ST( "x}; separator=\" \">" ); st.add("values", new boolean[] {true, false, true}); StringWriter sw = new StringWriter(); st.write(new AutoIndentWriter(sw)); String result = sw.toString(); String expecting = "x x"; assertEquals(expecting, result); } @Test public void TestSeparatorEmittedForEmptyIteratorValu3333e() throws IOException { String dir = getRandomDir(); String groupFile = "filter ::= [\"b\":, default: key]\n" + "t() ::= <%<[\"a\", \"b\", \"c\", \"b\"]:{it | }; separator=\",\">%>\n"; writeFile(dir, "group.stg", groupFile); STGroupFile group = new STGroupFile(dir+"/group.stg"); ST st = group.getInstanceOf("t"); StringWriter sw = new StringWriter(); st.write(new AutoIndentWriter(sw)); String result = sw.toString(); String expecting = "a,,c,"; assertEquals(expecting, result); } @Test public void TestSeparatorEmittedForEmptyIteratorValue2() throws IOException { ST st = new ST( "" ); st.add("values", new String[]{"x", "", "y"}); StringWriter sw = new StringWriter(); st.write(new AutoIndentWriter(sw)); String result = sw.toString(); String expecting = "x y"; assertEquals(expecting, result); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestOptions.java000066400000000000000000000170521231426731300261360ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.*; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.misc.ErrorBuffer; import static org.junit.Assert.assertEquals; public class TestOptions extends BaseTest { @Test public void testSeparator() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "name", "hi !"); ST st = group.getInstanceOf("test"); st.add("name", "Ter"); st.add("name", "Tom"); st.add("name", "Sumana"); String expected = "hi Ter, Tom, Sumana!"; String result = st.render(); assertEquals(expected, result); } @Test public void testSeparatorWithSpaces() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "name", "hi !"); ST st = group.getInstanceOf("test"); System.out.println(st.impl.ast.toStringTree()); st.add("name", "Ter"); st.add("name", "Tom"); st.add("name", "Sumana"); String expected = "hi Ter, Tom, Sumana!"; String result = st.render(); assertEquals(expected, result); } @Test public void testAttrSeparator() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "name,sep", "hi !"); ST st = group.getInstanceOf("test"); st.add("sep", ", "); st.add("name", "Ter"); st.add("name", "Tom"); st.add("name", "Sumana"); String expected = "hi Ter, Tom, Sumana!"; String result = st.render(); assertEquals(expected, result); } @Test public void testIncludeSeparator() throws Exception { STGroup group = new STGroup(); group.defineTemplate("foo", "|"); group.defineTemplate("test", "name,sep", "hi !"); ST st = group.getInstanceOf("test"); st.add("sep", ", "); st.add("name", "Ter"); st.add("name", "Tom"); st.add("name", "Sumana"); String expected = "hi Ter|Tom|Sumana!"; String result = st.render(); assertEquals(expected, result); } @Test public void testSubtemplateSeparator() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "name,sep", "hi _}>!"); ST st = group.getInstanceOf("test"); st.add("sep", ","); st.add("name", "Ter"); st.add("name", "Tom"); st.add("name", "Sumana"); String expected = "hi Ter, _Tom, _Sumana!"; String result = st.render(); assertEquals(expected, result); } @Test public void testSeparatorWithNullFirstValueAndNullOption() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "name", "hi !"); ST st = group.getInstanceOf("test"); st.add("name", null); st.add("name", "Tom"); st.add("name", "Sumana"); String expected = "hi n/a, Tom, Sumana!"; String result = st.render(); assertEquals(expected, result); } @Test public void testSeparatorWithNull2ndValueAndNullOption() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "name", "hi !"); ST st = group.getInstanceOf("test"); st.impl.dump(); st.add("name", "Ter"); st.add("name", null); st.add("name", "Sumana"); String expected = "hi Ter, n/a, Sumana!"; String result = st.render(); assertEquals(expected, result); } @Test public void testNullValueAndNullOption() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "name", ""); ST st = group.getInstanceOf("test"); st.add("name", null); String expected = "n/a"; String result = st.render(); assertEquals(expected, result); } @Test public void testListApplyWithNullValueAndNullOption() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "name", "}; null=\"n/a\">"); ST st = group.getInstanceOf("test"); st.add("name", "Ter"); st.add("name", null); st.add("name", "Sumana"); String expected = "Tern/aSumana"; String result = st.render(); assertEquals(expected, result); } @Test public void testDoubleListApplyWithNullValueAndNullOption() throws Exception { // first apply sends [ST, null, ST] to second apply, which puts [] around // the value. This verifies that null not blank comes out of first apply // since we don't get [null]. STGroup group = new STGroup(); group.defineTemplate("test", "name", "}:{n | []}; null=\"n/a\">"); ST st = group.getInstanceOf("test"); st.add("name", "Ter"); st.add("name", null); st.add("name", "Sumana"); String expected = "[Ter]n/a[Sumana]"; String result = st.render(); assertEquals(expected, result); } @Test public void testMissingValueAndNullOption() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "name", ""); ST st = group.getInstanceOf("test"); String expected = "n/a"; String result = st.render(); assertEquals(expected, result); } @Test public void testOptionDoesntApplyToNestedTemplate() throws Exception { STGroup group = new STGroup(); group.defineTemplate("foo", ""); group.defineTemplate("test", "zippo", ""); ST st = group.getInstanceOf("test"); st.add("zippo", null); String expected = ""; String result = st.render(); assertEquals(expected, result); } @Test public void testIllegalOption() throws Exception { ErrorBuffer errors = new ErrorBuffer(); STGroup group = new STGroup(); group.setListener(errors); group.defineTemplate("test", "name", ""); ST st = group.getInstanceOf("test"); st.add("name", "Ter"); String expected = "Ter"; String result = st.render(); assertEquals(expected, result); expected = "[test 1:7: no such option: bad]"; assertEquals(expected, errors.errors.toString()); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestRegions.java000066400000000000000000000356241231426731300261160ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.*; import org.stringtemplate.v4.*; import org.stringtemplate.v4.misc.ErrorBuffer; import static org.junit.Assert.assertEquals; public class TestRegions extends BaseTest { @Test public void testEmbeddedRegion() throws Exception { String dir = getRandomDir(); String groupFile = "a() ::= <<\n" + "[<@r>bar<@end>]\n" + ">>\n"; writeFile(dir, "group.stg", groupFile); STGroup group = new STGroupFile(dir+"/group.stg"); ST st = group.getInstanceOf("a"); String expected = "[bar]"; String result = st.render(); assertEquals(expected, result); } @Test public void testRegion() throws Exception { String dir = getRandomDir(); String groupFile = "a() ::= <<\n" + "[<@r()>]\n" + ">>\n"; writeFile(dir, "group.stg", groupFile); STGroup group = new STGroupFile(dir+"/group.stg"); ST st = group.getInstanceOf("a"); String expected = "[]"; String result = st.render(); assertEquals(expected, result); } @Test public void testDefineRegionInSubgroup() throws Exception { String dir = getRandomDir(); writeFile(dir, "g1.stg", "a() ::= <<[<@r()>]>>\n"); writeFile(dir, "g2.stg", "@a.r() ::= <>\n"); STGroup group1 = new STGroupFile(dir+"/g1.stg"); STGroup group2 = new STGroupFile(dir+"/g2.stg"); group2.importTemplates(group1); // define r in g2 ST st = group2.getInstanceOf("a"); String expected = "[foo]"; String result = st.render(); assertEquals(expected, result); } @Test public void testDefineRegionInSubgroupOneInSubdir() throws Exception { String dir = getRandomDir(); writeFile(dir, "g1.stg", "a() ::= <<[<@r()>]>>\n"); writeFile(dir+"/subdir", "g2.stg", "@a.r() ::= <>\n"); STGroup group1 = new STGroupFile(dir+"/g1.stg"); STGroup group2 = new STGroupFile(dir+"/subdir/g2.stg"); group2.importTemplates(group1); // define r in g2 ST st = group2.getInstanceOf("a"); String expected = "[foo]"; String result = st.render(); assertEquals(expected, result); } @Test public void testDefineRegionInSubgroupBothInSubdir() throws Exception { String dir = getRandomDir(); writeFile(dir+"/subdir", "g1.stg", "a() ::= <<[<@r()>]>>\n"); writeFile(dir+"/subdir", "g2.stg", "@a.r() ::= <>\n"); STGroup group1 = new STGroupFile(dir+"/subdir/g1.stg"); STGroup group2 = new STGroupFile(dir+"/subdir/g2.stg"); group2.importTemplates(group1); // define r in g2 ST st = group2.getInstanceOf("a"); String expected = "[foo]"; String result = st.render(); assertEquals(expected, result); } @Test public void testDefineRegionInSubgroupThatRefsSuper() throws Exception { String dir = getRandomDir(); String g1 = "a() ::= <<[<@r>foo<@end>]>>\n"; writeFile(dir, "g1.stg", g1); String g2 = "@a.r() ::= <<(<@super.r()>)>>\n"; writeFile(dir, "g2.stg", g2); STGroup group1 = new STGroupFile(dir+"/g1.stg"); STGroup group2 = new STGroupFile(dir+"/g2.stg"); group2.importTemplates(group1); // define r in g2 ST st = group2.getInstanceOf("a"); String expected = "[(foo)]"; String result = st.render(); assertEquals(expected, result); } @Test public void testDefineRegionInSubgroup2() throws Exception { String dir = getRandomDir(); String g1 = "a() ::= <<[<@r()>]>>\n"; writeFile(dir, "g1.stg", g1); String g2 = "@a.r() ::= <>>\n"; writeFile(dir, "g2.stg", g2); STGroup group1 = new STGroupFile(dir+"/g1.stg"); STGroup group2 = new STGroupFile(dir+"/g2.stg"); group1.importTemplates(group2); // opposite of previous; g1 imports g2 ST st = group1.getInstanceOf("a"); String expected = "[]"; // @a.r implicitly defined in g1; can't see g2's String result = st.render(); assertEquals(expected, result); } @Test public void testDefineRegionInSameGroup() throws Exception { String dir = getRandomDir(); String g = "a() ::= <<[<@r()>]>>\n"+ "@a.r() ::= <>\n"; writeFile(dir, "g.stg", g); STGroup group = new STGroupFile(dir+"/g.stg"); ST st = group.getInstanceOf("a"); String expected = "[foo]"; String result = st.render(); assertEquals(expected, result); } @Test public void testAnonymousTemplateInRegion() throws Exception { String dir = getRandomDir(); String g = "a() ::= <<[<@r()>]>>\n" + "@a.r() ::= <<\n" + "<[\"foo\"]:{x|}>\n" + ">>\n"; writeFile(dir, "g.stg", g); STGroup group = new STGroupFile(dir+"/g.stg"); ST st = group.getInstanceOf("a"); String expected = "[foo]"; String result = st.render(); assertEquals(expected, result); } @Test public void testAnonymousTemplateInRegionInSubdir() throws Exception { //fails since it makes region name /region__/g/a/_r String dir = getRandomDir(); String g = "a() ::= <<[<@r()>]>>\n" + "@a.r() ::= <<\n" + "<[\"foo\"]:{x|}>\n" + ">>\n"; writeFile(dir, "g.stg", g); STGroup.verbose = true; STGroup group = new STGroupDir(dir); ST st = group.getInstanceOf("g/a"); String expected = "[foo]"; String result = st.render(); assertEquals(expected, result); } @Test public void testCantDefineEmbeddedRegionAgain() throws Exception { String dir = getRandomDir(); String g = "a() ::= <<[<@r>foo<@end>]>>\n"+ "@a.r() ::= <>\n"; // error; dup writeFile(dir, "g.stg", g); STGroupFile group = new STGroupFile(dir+"/g.stg"); ErrorBuffer errors = new ErrorBuffer(); group.setListener(errors); group.load(); String expected = "g.stg 2:3: region /a.r is embedded and thus already implicitly defined"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testCantDefineEmbeddedRegionAgainInTemplate() throws Exception { String dir = getRandomDir(); String g = "a() ::= <<\n" + "[\n" + "<@r>foo<@end>\n" + "<@r()>" + "]\n" + ">>\n"; // error; dup writeFile(dir, "g.stg", g); STGroupFile group = new STGroupFile(dir+"/g.stg"); ErrorBuffer errors = new ErrorBuffer(); group.setListener(errors); group.load(); String expected = "g.stg 3:2: redefinition of region /a.r"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testMissingRegionName() throws Exception { String dir = getRandomDir(); String g = "@t.() ::= \"\"\n"; writeFile(dir, "g.stg", g); STGroupFile group = new STGroupFile(dir+"/g.stg"); ErrorBuffer errors = new ErrorBuffer(); group.setListener(errors); group.load(); String expected = "g.stg 1:3: missing ID at '('"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testIndentBeforeRegionIsIgnored() throws Exception { String dir = getRandomDir(); String g = "a() ::= <<[\n" + " <@r>\n" + " foo\n" + " <@end>\n" + "]>>\n"; writeFile(dir, "g.stg", g); STGroupFile group = new STGroupFile(dir+"/g.stg"); ST st = group.getInstanceOf("a"); String expected = "[" + newline + " foo" + newline + "]"; String result = st.render(); assertEquals(expected, result); } @Test public void testRegionOverrideStripsNewlines() throws Exception { String dir = getRandomDir(); String g = "a() ::= \"X<@r()>Y\"" + "@a.r() ::= <<\n" + "foo\n" + ">>\n"; writeFile(dir, "g.stg", g); STGroupFile group = new STGroupFile(dir+"/g.stg"); String sub = "@a.r() ::= \"A<@super.r()>B\"" +newline; writeFile(dir, "sub.stg", sub); STGroupFile subGroup = new STGroupFile(dir+"/sub.stg"); subGroup.importTemplates(group); ST st = subGroup.getInstanceOf("a"); String result = st.render(); String expecting = "XAfooBY"; assertEquals(expecting, result); } // @Test public void testRegionOverrideRefSuperRegion() throws Exception { String dir = getRandomDir(); String g = "a() ::= \"X<@r()>Y\"" + "@a.r() ::= \"foo\"" +newline; writeFile(dir, "g.stg", g); STGroupFile group = new STGroupFile(dir+"/g.stg"); String sub = "@a.r() ::= \"A<@super.r()>B\"" +newline; writeFile(dir, "sub.stg", sub); STGroupFile subGroup = new STGroupFile(dir+"/sub.stg"); subGroup.importTemplates(group); ST st = subGroup.getInstanceOf("a"); String result = st.render(); String expecting = "XAfooBY"; assertEquals(expecting, result); } @Test public void testRegionOverrideRefSuperRegion2Levels() throws Exception { String g = "a() ::= \"X<@r()>Y\"\n" + "@a.r() ::= \"foo\"\n"; STGroup group = new STGroupString(g); String sub = "@a.r() ::= \"<@super.r()>2\"\n"; STGroup subGroup = new STGroupString(sub); subGroup.importTemplates(group); ST st = subGroup.getInstanceOf("a"); String result = st.render(); String expecting = "Xfoo2Y"; assertEquals(expecting, result); } @Test public void testRegionOverrideRefSuperRegion3Levels() throws Exception { String dir = getRandomDir(); String g = "a() ::= \"X<@r()>Y\"" + "@a.r() ::= \"foo\"" +newline; writeFile(dir, "g.stg", g); STGroupFile group = new STGroupFile(dir+"/g.stg"); String sub = "@a.r() ::= \"<@super.r()>2\"" +newline; writeFile(dir, "sub.stg", sub); STGroupFile subGroup = new STGroupFile(dir+"/sub.stg"); subGroup.importTemplates(group); String subsub = "@a.r() ::= \"<@super.r()>3\"" +newline; writeFile(dir, "subsub.stg", subsub); STGroupFile subSubGroup = new STGroupFile(dir+"/subsub.stg"); subSubGroup.importTemplates(subGroup); ST st = subSubGroup.getInstanceOf("a"); String result = st.render(); String expecting = "Xfoo23Y"; assertEquals(expecting, result); } @Test public void testRegionOverrideRefSuperImplicitRegion() throws Exception { String dir = getRandomDir(); String g = "a() ::= \"X<@r>foo<@end>Y\""+newline; writeFile(dir, "g.stg", g); STGroupFile group = new STGroupFile(dir+"/g.stg"); String sub = "@a.r() ::= \"A<@super.r()>\"" +newline; writeFile(dir, "sub.stg", sub); STGroupFile subGroup = new STGroupFile(dir+"/sub.stg"); subGroup.importTemplates(group); ST st = subGroup.getInstanceOf("a"); String result = st.render(); String expecting = "XAfooY"; assertEquals(expecting, result); } @Test public void testUnknownRegionDefError() throws Exception { String dir = getRandomDir(); String g = "a() ::= <<\n" + "X<@r()>Y\n" + ">>\n"+ "@a.q() ::= \"foo\"" +newline; STErrorListener errors = new ErrorBuffer(); writeFile(dir, "g.stg", g); STGroupFile group = new STGroupFile(dir+"/g.stg"); group.setListener(errors); ST st = group.getInstanceOf("a"); st.render(); String result = errors.toString(); String expecting = "g.stg 4:3: template /a doesn't have a region called q"+newline; assertEquals(expecting, result); } @Test public void testSuperRegionRefMissingOk() throws Exception { String dir = getRandomDir(); String g = "a() ::= \"X<@r()>Y\"" + "@a.r() ::= \"foo\"" +newline; writeFile(dir, "g.stg", g); STGroupFile group = new STGroupFile(dir+"/g.stg"); String sub = "@a.r() ::= \"A<@super.q()>B\"" +newline; // allow this; trap at runtime STErrorListener errors = new ErrorBuffer(); group.setListener(errors); writeFile(dir, "sub.stg", sub); STGroupFile subGroup = new STGroupFile(dir+"/sub.stg"); subGroup.importTemplates(group); ST st = subGroup.getInstanceOf("a"); String result = st.render(); String expecting = "XABY"; assertEquals(expecting, result); } @Test public void testEmbeddedRegionOnOneLine() throws Exception { String dir = getRandomDir(); String groupFile = "a() ::= <<\n" + "[\n" + " <@r>bar<@end>\n" + "]\n" + ">>\n"; writeFile(dir, "group.stg", groupFile); STGroup group = new STGroupFile(dir+"/group.stg"); ST st = group.getInstanceOf("a"); st.impl.dump(); String expected = "["+newline+" bar"+newline+"]"; String result = st.render(); assertEquals(expected, result); } @Test public void testEmbeddedRegionTagsOnSeparateLines() throws Exception { String dir = getRandomDir(); String groupFile = "a() ::= <<\n" + "[\n" + " <@r>\n" + " bar\n" + " <@end>\n" + "]\n" + ">>\n"; writeFile(dir, "group.stg", groupFile); STGroup group = new STGroupFile(dir+"/group.stg"); ST st = group.getInstanceOf("a"); String expected = "["+newline+" bar"+newline+"]"; String result = st.render(); assertEquals(expected, result); } @Ignore("will revisit the behavior of indented expressions spanning multiple lines for a future release") @Test public void testEmbeddedSubtemplate() throws Exception { String dir = getRandomDir(); String groupFile = "a() ::= <<\n" + "[\n" + " <{\n" + " bar\n" + " }>\n" + "]\n" + ">>\n"; writeFile(dir, "group.stg", groupFile); STGroup group = new STGroupFile(dir+"/group.stg"); ST st = group.getInstanceOf("a"); String expected = "["+newline+" bar"+newline+"]"; String result = st.render(); assertEquals(expected, result); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestRenderers.java000066400000000000000000000340571231426731300264400ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.*; import org.stringtemplate.v4.*; import java.util.*; import static org.junit.Assert.assertEquals; public class TestRenderers extends BaseTest { // Make sure to use the US Locale during the tests private Locale origLocale; @Before @Override public void setUp() { origLocale = Locale.getDefault(); Locale.setDefault(Locale.US); } @After public void tearDown() { Locale.setDefault(origLocale); } @Test public void testRendererForGroup() throws Exception { String templates = "dateThing(created) ::= \"datetime: \"\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/t.stg"); group.registerRenderer(GregorianCalendar.class, new DateRenderer()); ST st = group.getInstanceOf("dateThing"); st.add("created", new GregorianCalendar(2005, 07-1, 05)); String expecting = "datetime: 7/5/05 12:00 AM"; String result = st.render(); assertEquals(expecting, result); } @Test public void testRendererWithFormat() throws Exception { String templates = "dateThing(created) ::= << date: >>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/t.stg"); group.registerRenderer(GregorianCalendar.class, new DateRenderer()); ST st = group.getInstanceOf("dateThing"); st.add("created", new GregorianCalendar(2005, 07-1, 05)); String expecting = " date: 2005.07.05 "; String result = st.render(); assertEquals(expecting, result); } @Test public void testRendererWithPredefinedFormat() throws Exception { String templates = "dateThing(created) ::= << datetime: >>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/t.stg"); group.registerRenderer(GregorianCalendar.class, new DateRenderer()); ST st = group.getInstanceOf("dateThing"); st.add("created", new GregorianCalendar(2005, 07-1, 05)); String expecting = " datetime: 7/5/05 12:00 AM "; String result = st.render(); assertEquals(expecting, result); } @Test public void testRendererWithPredefinedFormat2() throws Exception { String templates = "dateThing(created) ::= << datetime: >>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/t.stg"); group.registerRenderer(GregorianCalendar.class, new DateRenderer()); ST st = group.getInstanceOf("dateThing"); TimeZone origTimeZone = TimeZone.getDefault(); try { // set Timezone to "PDT" TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles")); st.add("created", new GregorianCalendar(2005, 07-1, 05)); String expecting = " datetime: Tuesday, July 5, 2005 12:00:00 AM PDT "; String result = st.render(); assertEquals(expecting, result); } finally { // Restore original Timezone TimeZone.setDefault(origTimeZone); } } @Test public void testRendererWithPredefinedFormat3() throws Exception { String templates = "dateThing(created) ::= << date: >>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/t.stg"); group.registerRenderer(GregorianCalendar.class, new DateRenderer()); ST st = group.getInstanceOf("dateThing"); st.add("created", new GregorianCalendar(2005, 07-1, 05)); String expecting = " date: Jul 5, 2005 "; String result = st.render(); assertEquals(expecting, result); } @Test public void testRendererWithPredefinedFormat4() throws Exception { String templates = "dateThing(created) ::= << time: >>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/t.stg"); group.registerRenderer(GregorianCalendar.class, new DateRenderer()); ST st = group.getInstanceOf("dateThing"); st.add("created", new GregorianCalendar(2005, 07-1, 05)); String expecting = " time: 12:00:00 AM "; String result = st.render(); assertEquals(expecting, result); } @Test public void testStringRendererWithFormat_cap() throws Exception { String templates = "foo(x) ::= << >>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/t.stg"); group.registerRenderer(String.class, new StringRenderer()); ST st = group.getInstanceOf("foo"); st.add("x", "hi"); String expecting = " Hi "; String result = st.render(); assertEquals(expecting, result); } @Test public void testStringRendererWithTemplateInclude_cap() throws Exception { // must toString the t() ref before applying format String templates = "foo(x) ::= << <(t()); format=\"cap\"> >>\n" + "t() ::= <>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/t.stg"); group.registerRenderer(String.class, new StringRenderer()); ST st = group.getInstanceOf("foo"); st.add("x", "hi"); String expecting = " Ack "; String result = st.render(); assertEquals(expecting, result); } @Test public void testStringRendererWithSubtemplateInclude_cap() throws Exception { String templates = "foo(x) ::= << <({ack}); format=\"cap\"> >>\n" + "t() ::= <>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/t.stg"); group.registerRenderer(String.class, new StringRenderer()); ST st = group.getInstanceOf("foo"); st.add("x", "hi"); String expecting = " Ack "; String result = st.render(); assertEquals(expecting, result); } @Test public void testStringRendererWithFormat_cap_emptyValue() throws Exception { String templates = "foo(x) ::= << >>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/t.stg"); group.registerRenderer(String.class, new StringRenderer()); ST st = group.getInstanceOf("foo"); st.add("x", ""); String expecting = " ";//FIXME: why not two spaces? String result = st.render(); assertEquals(expecting, result); } @Test public void testStringRendererWithFormat_url_encode() throws Exception { String templates = "foo(x) ::= << >>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/t.stg"); group.registerRenderer(String.class, new StringRenderer()); ST st = group.getInstanceOf("foo"); st.add("x", "a b"); String expecting = " a+b "; String result = st.render(); assertEquals(expecting, result); } @Test public void testStringRendererWithFormat_xml_encode() throws Exception { String templates = "foo(x) ::= << >>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/t.stg"); group.registerRenderer(String.class, new StringRenderer()); ST st = group.getInstanceOf("foo"); st.add("x", "a &\t\b"); String expecting = " a<b> &\t "; String result = st.render(); assertEquals(expecting, result); } @Test public void testStringRendererWithFormat_xml_encode_null() throws Exception { String templates = "foo(x) ::= << >>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/t.stg"); group.registerRenderer(String.class, new StringRenderer()); ST st = group.getInstanceOf("foo"); st.add("x", null); String expecting = " "; String result = st.render(); assertEquals(expecting, result); } @Test public void testStringRendererWithPrintfFormat() throws Exception { String templates = "foo(x) ::= << >>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/t.stg"); group.registerRenderer(String.class, new StringRenderer()); ST st = group.getInstanceOf("foo"); st.add("x", "hi"); String expecting = " hi "; String result = st.render(); assertEquals(expecting, result); } @Test public void testNumberRendererWithPrintfFormat() throws Exception { String templates = "foo(x,y) ::= << >>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/t.stg"); group.registerRenderer(Integer.class, new NumberRenderer()); group.registerRenderer(Double.class, new NumberRenderer()); ST st = group.getInstanceOf("foo"); st.add("x", -2100); st.add("y", 3.14159); String expecting = " -2100 3.142 "; String result = st.render(); assertEquals(expecting, result); } @Test public void testInstanceofRenderer() throws Exception { String templates = "numberThing(x,y,z) ::= \"numbers: , ; \"\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/t.stg"); group.registerRenderer(Number.class, new NumberRenderer()); ST st = group.getInstanceOf("numberThing"); st.add("x", -2100); st.add("y", 3.14159); st.add("z", "hi"); String expecting = "numbers: -2100, 3.14159; hi"; String result = st.render(); assertEquals(expecting, result); } @Test public void testLocaleWithNumberRenderer() throws Exception { String templates = "foo(x,y) ::= <<\n" + " \n" + ">>\n"; writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/t.stg"); group.registerRenderer(Integer.class, new NumberRenderer()); group.registerRenderer(Double.class, new NumberRenderer()); ST st = group.getInstanceOf("foo"); st.add("x", -2100); st.add("y", 3.14159); // Polish uses ' ' (ASCII 160) for ',' and ',' for '.' String expecting = "-2\u00A0100 3,142"; String result = st.render(new Locale("pl")); assertEquals(expecting, result); } @Test public void testRendererWithFormatAndList() throws Exception { String template = "The names: "; STGroup group = new STGroup(); group.registerRenderer(String.class, new StringRenderer()); ST st = new ST(group, template); st.add("names", "ter"); st.add("names", "tom"); st.add("names", "sriram"); String expecting = "The names: TERTOMSRIRAM"; String result = st.render(); assertEquals(expecting, result); } @Test public void testRendererWithFormatAndSeparator() throws Exception { String template = "The names: "; STGroup group = new STGroup(); group.registerRenderer(String.class, new StringRenderer()); ST st = new ST(group, template); st.add("names", "ter"); st.add("names", "tom"); st.add("names", "sriram"); String expecting = "The names: TER and TOM and SRIRAM"; String result = st.render(); assertEquals(expecting, result); } @Test public void testRendererWithFormatAndSeparatorAndNull() throws Exception { String template = "The names: "; STGroup group = new STGroup(); group.registerRenderer(String.class, new StringRenderer()); ST st = new ST(group, template); List names = new ArrayList(); names.add("ter"); names.add(null); names.add("sriram"); st.add("names", names); String expecting = "The names: TER and N/A and SRIRAM"; String result = st.render(); assertEquals(expecting, result); } @Test public void testDateRendererWithLocale() { String input = ""; STGroup group = new STGroup(); group.registerRenderer(Calendar.class, new DateRenderer()); ST st = new ST(group, input); Calendar cal = Calendar.getInstance(); cal.set(2012, Calendar.JUNE, 12); st.add("date", cal); assertEquals("12 de Junho de 2012", st.render(new Locale("pt"))); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestSTRawGroupDir.java000066400000000000000000000101171231426731300271520ustar00rootroot00000000000000package org.stringtemplate.v4.test; import org.junit.Test; import org.stringtemplate.v4.*; import java.util.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; public class TestSTRawGroupDir extends BaseTest { @Test public void testSimpleGroup() throws Exception { String dir = getRandomDir(); writeFile(dir, "a.st", "foo"); STGroup group = new STRawGroupDir(dir, '$', '$'); ST st = group.getInstanceOf("a"); String expected = "foo"; String result = st.render(); assertEquals(expected, result); } @Test public void testSimpleGroup2() throws Exception { String dir = getRandomDir(); writeFile(dir, "a.st", "foo"); writeFile(dir, "b.st", "$name$"); STGroup group = new STRawGroupDir(dir, '$', '$'); ST st = group.getInstanceOf("a"); String expected = "foo"; String result = st.render(); assertEquals(expected, result); ST b = group.getInstanceOf("b"); b.add("name", "Bob"); assertEquals("Bob", b.render()); } @Test public void testSimpleGroupAngleBrackets() throws Exception { String dir = getRandomDir(); writeFile(dir, "a.st", "foo"); writeFile(dir, "b.st", ""); STGroup group = new STRawGroupDir(dir); ST st = group.getInstanceOf("a"); String expected = "foo"; String result = st.render(); assertEquals(expected, result); ST b = group.getInstanceOf("b"); b.add("name", "Bob"); assertEquals("Bob", b.render()); } @Test public void testSTRawGroupDir() { String dir = getRandomDir(); writeFile(dir, "template.st", "$values:{foo|[$foo$]}$"); STGroup group = new STRawGroupDir(dir, '$', '$'); ST template = group.getInstanceOf("template"); List values = new ArrayList(); values.add("one"); values.add("two"); values.add("three"); template.add("values", values); assertEquals("[one][two][three]", template.render()); } @Test public void testMap() throws Exception { String dir = getRandomDir(); writeFile(dir, "a.st", "$names:bold()$"); writeFile(dir, "bold.st", "$it$"); STGroup group = new STRawGroupDir(dir, '$', '$'); ST st = group.getInstanceOf("a"); List names = new ArrayList(); names.add("parrt"); names.add("tombu"); st.add("names", names); // String asmResult = st.impl.instrs(); // System.out.println(asmResult); // st.inspect(); String expected = "parrttombu"; String result = st.render(); assertEquals(expected, result); } @Test public void testSuper() throws Exception { String dir1 = getRandomDir(); String a = "dir1 a"; String b = "dir1 b"; writeFile(dir1, "a.st", a); writeFile(dir1, "b.st", b); String dir2 = getRandomDir(); a = "[]"; writeFile(dir2, "a.st", a); STGroup group1 = new STRawGroupDir(dir1); STGroup group2 = new STRawGroupDir(dir2); group2.importTemplates(group1); ST st = group2.getInstanceOf("a"); String expected = "[dir1 a]"; String result = st.render(); assertEquals(expected, result); } /** * This is a regression test for antlr/stringtemplate4#70. "Argument * initialization for sub-template in template with STRawGroupDir doesn't * recognize valid parameters" * https://github.com/antlr/stringtemplate4/issues/70 */ @Test public void testRawArgumentPassing() { String dir1 = getRandomDir(); String mainRawTemplate = "Hello $name$" + newline + "Then do the footer:" + newline + "$footerRaw(lastLine=veryLastLineRaw())$" + newline; String footerRawTemplate = "Simple footer. And now a last line:" + newline + "$lastLine$"; String veryLastLineTemplate = "That's the last line."; writeFile(dir1, "mainRaw.st", mainRawTemplate); writeFile(dir1, "footerRaw.st", footerRawTemplate); writeFile(dir1, "veryLastLineRaw.st", veryLastLineTemplate); STGroup group = new STRawGroupDir(dir1, '$', '$'); ST st = group.getInstanceOf("mainRaw"); assertNotNull(st); st.add("name", "John"); String result = st.render(); String expected = "Hello John" + newline + "Then do the footer:" + newline + "Simple footer. And now a last line:" + newline + "That's the last line." + newline; assertEquals(expected, result); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestScopes.java000066400000000000000000000060661231426731300257420ustar00rootroot00000000000000package org.stringtemplate.v4.test; import org.junit.Test; import org.stringtemplate.v4.*; import org.stringtemplate.v4.misc.*; import static org.junit.Assert.assertEquals; public class TestScopes extends BaseTest { @Test public void testSeesEnclosingAttr() throws Exception { String templates = "t(x,y) ::= \"\"\n" + "u() ::= \"\""; ErrorBuffer errors = new ErrorBuffer(); writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); ST st = group.getInstanceOf("t"); st.add("x", "x"); st.add("y", "y"); String result = st.render(); String expectedError = ""; assertEquals(expectedError, errors.toString()); String expected = "xy"; assertEquals(expected, result); } @Test public void testMissingArg() throws Exception { String templates = "t() ::= \"\"\n" + "u(z) ::= \"\""; ErrorBuffer errors = new ErrorBuffer(); writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); ST st = group.getInstanceOf("t"); String result = st.render(); String expectedError = "context [/t] 1:1 passed 0 arg(s) to template /u with 1 declared arg(s)"+newline; assertEquals(expectedError, errors.toString()); } @Test public void testUnknownAttr() throws Exception { String templates = "t() ::= \"\"\n"; ErrorBuffer errors = new ErrorBuffer(); writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); ST st = group.getInstanceOf("t"); String result = st.render(); String expectedError = "context [/t] 1:1 attribute x isn't defined"+newline; assertEquals(expectedError, errors.toString()); } @Test public void testArgWithSameNameAsEnclosing() throws Exception { String templates = "t(x,y) ::= \"\"\n" + "u(y) ::= \"\""; ErrorBuffer errors = new ErrorBuffer(); writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); ST st = group.getInstanceOf("t"); st.add("x", "x"); st.add("y", "y"); String result = st.render(); String expectedError = ""; assertEquals(expectedError, errors.toString()); String expected = "xx"; assertEquals(expected, result); group.setListener(ErrorManager.DEFAULT_ERROR_LISTENER); } @Test public void testIndexAttrVisibleLocallyOnly() throws Exception { String templates = "t(names) ::= \"}>\"\n" + "u(x) ::= \":\""; ErrorBuffer errors = new ErrorBuffer(); writeFile(tmpdir, "t.stg", templates); STGroup group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); ST st = group.getInstanceOf("t"); st.add("names", "Ter"); String result = st.render(); group.getInstanceOf("u").impl.dump(); String expectedError = "t.stg 2:11: implicitly-defined attribute i not visible"+newline; assertEquals(expectedError, errors.toString()); String expected = ":Ter"; assertEquals(expected, result); group.setListener(ErrorManager.DEFAULT_ERROR_LISTENER); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestSubtemplates.java000066400000000000000000000233061231426731300271520ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.*; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroupFile; import org.stringtemplate.v4.misc.ErrorBuffer; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.Map; import static org.junit.Assert.assertEquals; public class TestSubtemplates extends BaseTest { @Test public void testSimpleIteration() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "names", "}>!"); ST st = group.getInstanceOf("test"); st.add("names", "Ter"); st.add("names", "Tom"); st.add("names", "Sumana"); String expected = "TerTomSumana!"; String result = st.render(); assertEquals(expected, result); } @Test public void testMapIterationIsByKeys() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "emails", "}>!"); ST st = group.getInstanceOf("test"); Map emails = new LinkedHashMap(); emails.put("parrt", "Ter"); emails.put("tombu", "Tom"); emails.put("dmose", "Dan"); st.add("emails", emails); String expected = "parrttombudmose!"; String result = st.render(); assertEquals(expected, result); } @Test public void testSimpleIterationWithArg() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "names", "}>!"); ST st = group.getInstanceOf("test"); st.add("names", "Ter"); st.add("names", "Tom"); st.add("names", "Sumana"); String expected = "TerTomSumana!"; String result = st.render(); assertEquals(expected, result); } @Test public void testNestedIterationWithArg() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "users", "=}>}>!"); ST st = group.getInstanceOf("test"); st.add("users", new TestCoreBasics.User(1, "parrt")); st.add("users", new TestCoreBasics.User(2, "tombu")); st.add("users", new TestCoreBasics.User(3, "sri")); String expected = "1=parrt2=tombu3=sri!"; String result = st.render(); assertEquals(expected, result); } @Test public void testSubtemplateAsDefaultArg() throws Exception { String templates = "t(x,y={}>}) ::= <<\n" + "x: \n" + "y: \n" + ">>"+newline ; writeFile(tmpdir, "group.stg", templates); STGroup group = new STGroupFile(tmpdir+"/group.stg"); ST b = group.getInstanceOf("t"); b.add("x", "a"); String expecting = "x: a" +newline+ "y: aa"; String result = b.render(); assertEquals(expecting, result); } @Test public void testParallelAttributeIteration() throws Exception { ST e = new ST( "@

: \n}>" ); e.add("names", "Ter"); e.add("names", "Tom"); e.add("phones", "1"); e.add("phones", "2"); e.add("salaries", "big"); e.add("salaries", "huge"); String expecting = "Ter@1: big"+newline+"Tom@2: huge"+newline; assertEquals(expecting, e.render()); } @Test public void testParallelAttributeIterationWithNullValue() throws Exception { ST e = new ST( "@

: \n}>" ); e.add("names", "Ter"); e.add("names", "Tom"); e.add("names", "Sriram"); e.add("phones", new ArrayList() {{add("1"); add(null); add("3");}}); e.add("salaries", "big"); e.add("salaries", "huge"); e.add("salaries", "enormous"); String expecting = "Ter@1: big"+newline+ "Tom@: huge"+newline+ "Sriram@3: enormous"+newline; assertEquals(expecting, e.render()); } @Test public void testParallelAttributeIterationHasI() throws Exception { ST e = new ST( ". @

: \n}>" ); e.add("names", "Ter"); e.add("names", "Tom"); e.add("phones", "1"); e.add("phones", "2"); e.add("salaries", "big"); e.add("salaries", "huge"); String expecting = "0. Ter@1: big"+newline+ "1. Tom@2: huge"+newline; assertEquals(expecting, e.render()); } @Test public void testParallelAttributeIterationWithDifferentSizes() throws Exception { ST e = new ST( "@

: }; separator=\", \">" ); e.add("names", "Ter"); e.add("names", "Tom"); e.add("names", "Sriram"); e.add("phones", "1"); e.add("phones", "2"); e.add("salaries", "big"); String expecting = "Ter@1: big, Tom@2: , Sriram@: "; assertEquals(expecting, e.render()); } @Test public void testParallelAttributeIterationWithSingletons() throws Exception { ST e = new ST( "@

: }; separator=\", \">" ); e.add("names", "Ter"); e.add("phones", "1"); e.add("salaries", "big"); String expecting = "Ter@1: big"; assertEquals(expecting, e.render()); } @Test public void testParallelAttributeIterationWithDifferentSizesTemplateRefInsideToo() throws Exception { String templates = "page(names,phones,salaries) ::= "+newline+ " << @: }; separator=\", \"> >>"+newline + "value(x) ::= \"n/a\"" +newline; writeFile(tmpdir, "g.stg", templates); STGroup group = new STGroupFile(tmpdir+"/g.stg"); ST p = group.getInstanceOf("page"); p.add("names", "Ter"); p.add("names", "Tom"); p.add("names", "Sriram"); p.add("phones", "1"); p.add("phones", "2"); p.add("salaries", "big"); String expecting = " Ter@1: big, Tom@2: n/a, Sriram@n/a: n/a "; assertEquals(expecting, p.render()); } @Test public void testEvalSTIteratingSubtemplateInSTFromAnotherGroup() throws Exception { ErrorBuffer errors = new ErrorBuffer(); STGroup innerGroup = new STGroup(); innerGroup.setListener(errors); innerGroup.defineTemplate("test", "m", ""); innerGroup.defineTemplate("samegroup", "x", "hi "); ST st = innerGroup.getInstanceOf("test"); st.add("m", new int[] {1,2,3}); STGroup outerGroup = new STGroup(); outerGroup.defineTemplate("errorMessage", "x", ""); ST outerST = outerGroup.getInstanceOf("errorMessage"); outerST.add("x", st); String expected = "hi hi hi "; String result = outerST.render(); assertEquals(errors.errors.size(), 0); // ignores no such prop errors assertEquals(expected, result); } @Test public void testEvalSTIteratingSubtemplateInSTFromAnotherGroupSingleValue() throws Exception { ErrorBuffer errors = new ErrorBuffer(); STGroup innerGroup = new STGroup(); innerGroup.setListener(errors); innerGroup.defineTemplate("test", "m", ""); innerGroup.defineTemplate("samegroup", "x", "hi "); ST st = innerGroup.getInstanceOf("test"); st.add("m", 10); STGroup outerGroup = new STGroup(); outerGroup.defineTemplate("errorMessage", "x", ""); ST outerST = outerGroup.getInstanceOf("errorMessage"); outerST.add("x", st); String expected = "hi "; String result = outerST.render(); assertEquals(errors.errors.size(), 0); // ignores no such prop errors assertEquals(expected, result); } @Test public void testEvalSTFromAnotherGroup() throws Exception { ErrorBuffer errors = new ErrorBuffer(); STGroup innerGroup = new STGroup(); innerGroup.setListener(errors); innerGroup.defineTemplate("bob", "inner"); ST st = innerGroup.getInstanceOf("bob"); STGroup outerGroup = new STGroup(); outerGroup.setListener(errors); outerGroup.defineTemplate("errorMessage", "x", ""); outerGroup.defineTemplate("bob", "outer"); // should not be visible to test() in innerGroup ST outerST = outerGroup.getInstanceOf("errorMessage"); outerST.add("x", st); String expected = "inner"; String result = outerST.render(); assertEquals(errors.errors.size(), 0); // ignores no such prop errors assertEquals(expected, result); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestSyntaxErrors.java000066400000000000000000000212121231426731300271570ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.*; import org.stringtemplate.v4.STErrorListener; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroupFile; import org.stringtemplate.v4.compiler.STException; import org.stringtemplate.v4.misc.ErrorBuffer; import static org.junit.Assert.assertEquals; public class TestSyntaxErrors extends BaseTest { @Test public void testEmptyExpr() throws Exception { String template = " <> "; STGroup group = new STGroup(); ErrorBuffer errors = new ErrorBuffer(); group.setListener(errors); try { group.defineTemplate("test", template); } catch (STException se) { assert false; } String result = errors.toString(); String expected = "test 1:0: this doesn't look like a template: \" <> \""+newline; assertEquals(expected, result); } @Test public void testEmptyExpr2() throws Exception { String template = "hi <> "; STGroup group = new STGroup(); ErrorBuffer errors = new ErrorBuffer(); group.setListener(errors); try { group.defineTemplate("test", template); } catch (STException se) { assert false; } String result = errors.toString(); String expected = "test 1:3: doesn't look like an expression"+newline; assertEquals(expected, result); } @Test public void testUnterminatedExpr() throws Exception { String template = "hi '" +newline+ "test 1:7: premature EOF"+newline; assertEquals(expected, result); } @Test public void testWeirdChar() throws Exception { String template = " <*>"; STGroup group = new STGroup(); ErrorBuffer errors = new ErrorBuffer(); group.setListener(errors); try { group.defineTemplate("test", template); } catch (STException se) { assert false; } String result = errors.toString(); String expected = "test 1:4: invalid character '*'"+newline + "test 1:0: this doesn't look like a template: \" <*>\""+newline; assertEquals(expected, result); } @Test public void testWeirdChar2() throws Exception { String template = "\n<\\\n"; STGroup group = new STGroup(); ErrorBuffer errors = new ErrorBuffer(); group.setListener(errors); try { group.defineTemplate("test", template); } catch (STException se) { assert false; } String result = errors.toString(); String expected = "test 1:2: invalid escaped char: ''" + newline + "test 1:2: expecting '>', found ''"+newline; assertEquals(expected, result); } @Test public void testValidButOutOfPlaceChar() throws Exception { String templates = "foo() ::= < mom>>\n"; writeFile(tmpdir, "t.stg", templates); STErrorListener errors = new ErrorBuffer(); STGroupFile group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "t.stg 1:15: doesn't look like an expression"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testValidButOutOfPlaceCharOnDifferentLine() throws Exception { String templates = "foo() ::= \"hi <\n" + ".> mom\"\n"; writeFile(tmpdir, "t.stg", templates); ErrorBuffer errors = new ErrorBuffer(); STGroupFile group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "[t.stg 1:15: \\n in string, t.stg 1:14: doesn't look like an expression]"; String result = errors.errors.toString(); assertEquals(expected, result); } @Test public void testErrorInNestedTemplate() throws Exception { String templates = "foo() ::= \"hi ]}> mom\"\n"; writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; STErrorListener errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "t.stg 1:29: '!' came as a complete surprise to me"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testEOFInExpr() throws Exception { String templates = "foo() ::= \"hi ]}\"\n"; writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; STErrorListener errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "t.stg 1:34: premature EOF"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testEOFInString() throws Exception { String templates = "foo() ::= << >\n"; writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; STErrorListener errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "t.stg 1:20: EOF in string"+newline + "t.stg 1:20: premature EOF"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testNonterminatedComment() throws Exception { String templates = "foo() ::= << >>"; writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; STErrorListener errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "t.stg 1:20: Nonterminated comment starting at 1:1: '!>' missing" +newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testMissingRPAREN() throws Exception { String templates = "foo() ::= \"hi \"\n"; writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; STErrorListener errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "t.stg 1:19: '>' came as a complete surprise to me"+newline; String result = errors.toString(); assertEquals(expected, result); } @Test public void testRotPar() throws Exception { String templates = "foo() ::= \"\"\n"; writeFile(tmpdir, "t.stg", templates); STGroupFile group = null; STErrorListener errors = new ErrorBuffer(); group = new STGroupFile(tmpdir+"/"+"t.stg"); group.setListener(errors); group.load(); // force load String expected = "t.stg 1:19: mismatched input ',' expecting RDELIM"+newline; String result = errors.toString(); assertEquals(expected, result); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestTemplateNames.java000066400000000000000000000101611231426731300272340ustar00rootroot00000000000000package org.stringtemplate.v4.test; import org.junit.Test; import org.stringtemplate.v4.*; import static org.junit.Assert.assertEquals; public class TestTemplateNames extends BaseTest { @Test public void testAbsoluteTemplateRefFromOutside() throws Exception { // /randomdir/a and /randomdir/subdir/b String dir = getRandomDir(); writeFile(dir, "a.st", "a(x) ::= << >>\n"); writeFile(dir+"/subdir", "b.st", "b() ::= <>\n"); STGroup group = new STGroupDir(dir); assertEquals(" bar ", group.getInstanceOf("a").render()); assertEquals(" bar ", group.getInstanceOf("/a").render()); assertEquals("bar", group.getInstanceOf("/subdir/b").render()); } @Test public void testRelativeTemplateRefInExpr() throws Exception { // /randomdir/a and /randomdir/subdir/b String dir = getRandomDir(); writeFile(dir, "a.st", "a(x) ::= << >>\n"); writeFile(dir+"/subdir", "b.st", "b() ::= <>\n"); STGroup group = new STGroupDir(dir); assertEquals(" bar ", group.getInstanceOf("a").render()); } @Test public void testAbsoluteTemplateRefInExpr() throws Exception { // /randomdir/a and /randomdir/subdir/b String dir = getRandomDir(); writeFile(dir, "a.st", "a(x) ::= << >>\n"); writeFile(dir+"/subdir", "b.st", "b() ::= <>\n"); STGroup group = new STGroupDir(dir); assertEquals(" bar ", group.getInstanceOf("a").render()); } @Test public void testRefToAnotherTemplateInSameGroup() throws Exception { String dir = getRandomDir(); writeFile(dir, "a.st", "a() ::= << >>\n"); writeFile(dir, "b.st", "b() ::= <>\n"); STGroup group = new STGroupDir(dir); ST st = group.getInstanceOf("a"); String expected = " bar "; String result = st.render(); assertEquals(expected, result); } @Test public void testRefToAnotherTemplateInSameSubdir() throws Exception { // /randomdir/a and /randomdir/subdir/b String dir = getRandomDir(); writeFile(dir+"/subdir", "a.st", "a() ::= << >>\n"); writeFile(dir+"/subdir", "b.st", "b() ::= <>\n"); STGroup group = new STGroupDir(dir); group.getInstanceOf("/subdir/a").impl.dump(); assertEquals(" bar ", group.getInstanceOf("/subdir/a").render()); } @Test public void testFullyQualifiedGetInstanceOf() throws Exception { String dir = getRandomDir(); writeFile(dir, "a.st", "a(x) ::= <>"); STGroup group = new STGroupDir(dir); assertEquals("foo", group.getInstanceOf("a").render()); assertEquals("foo", group.getInstanceOf("/a").render()); } @Test public void testFullyQualifiedTemplateRef() throws Exception { // /randomdir/a and /randomdir/subdir/b String dir = getRandomDir(); writeFile(dir+"/subdir", "a.st", "a() ::= << >>\n"); writeFile(dir+"/subdir", "b.st", "b() ::= <>\n"); STGroup group = new STGroupDir(dir); assertEquals(" bar ", group.getInstanceOf("/subdir/a").render()); assertEquals(" bar ", group.getInstanceOf("subdir/a").render()); } @Test public void testFullyQualifiedTemplateRef2() throws Exception { // /randomdir/a and /randomdir/group.stg with b and c templates String dir = getRandomDir(); writeFile(dir, "a.st", "a(x) ::= << >>\n"); String groupFile = "b() ::= \"bar\"\n"+ "c() ::= \"\"\n"; writeFile(dir, "group.stg", groupFile); STGroup group = new STGroupDir(dir); ST st1 = group.getInstanceOf("/a"); ST st2 = group.getInstanceOf("/group/c"); // invokes /a String expected = " bar bar "; String result = st1.render()+st2.render(); assertEquals(expected, result); } @Test public void testRelativeInSubdir() throws Exception { // /randomdir/a and /randomdir/subdir/b String dir = getRandomDir(); writeFile(dir, "a.st", "a(x) ::= << >>\n"); writeFile(dir+"/subdir", "b.st", "b() ::= <>\n"); writeFile(dir+"/subdir", "c.st", "c() ::= << >>\n"); STGroup group = new STGroupDir(dir); assertEquals(" bar ", group.getInstanceOf("a").render()); } // TODO: test is RELATIVE NOT ABSOLUTE } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestTokensForDollarDelimiters.java000066400000000000000000000100021231426731300315610ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.Test; public class TestTokensForDollarDelimiters extends BaseTest { @Test public void testSimpleAttr() throws Exception { String template = "hi $name$"; String expected = "[[@0,0:2='hi ',,1:0], [@1,3:3='$',,1:3], [@2,4:7='name',,1:4], [@3,8:8='$',,1:8]]"; checkTokens(template, expected, '$', '$'); } @Test public void testString() throws Exception { String template = "hi $foo(a=\"$\")$"; String expected = "[[@0,0:2='hi ',,1:0], [@1,3:3='$',,1:3], [@2,4:6='foo',,1:4], [@3,7:7='(',,1:7], [@4,8:8='a',,1:8], [@5,9:9='=',,1:9], [@6,10:12='\"$\"',,1:10], [@7,13:13=')',,1:13], [@8,14:14='$',,1:14]]"; checkTokens(template, expected, '$', '$'); } @Test public void testEscInString() throws Exception { String template = "hi $foo(a=\"$\\\"\")$"; // "hi $foo(a="$\"")$" String expected = "[[@0,0:2='hi ',,1:0], [@1,3:3='$',,1:3], [@2,4:6='foo',,1:4], [@3,7:7='(',,1:7], [@4,8:8='a',,1:8], [@5,9:9='=',,1:9], [@6,10:14='\"$\"\"',,1:10], [@7,15:15=')',,1:15], [@8,16:16='$',,1:16]]"; checkTokens(template, expected, '$', '$'); } @Test public void testSubtemplate() throws Exception { String template = "hi $names:{n | $n$}$"; String expected = "[[@0,0:2='hi ',,1:0], [@1,3:3='$',,1:3], [@2,4:8='names',,1:4], " + "[@3,9:9=':',,1:9], [@4,10:10='{',,1:10], [@5,11:11='n',,1:11], " + "[@6,13:13='|',,1:13], [@7,15:15='$',,1:15], [@8,16:16='n',,1:16], " + "[@9,17:17='$',,1:17], [@10,18:18='}',,1:18], [@11,19:19='$',,1:19]]"; checkTokens(template, expected, '$', '$'); } @Test public void testNestedSubtemplate() throws Exception { String template = "hi $names:{n | $n:{$it$}$}$"; String expected = "[[@0,0:2='hi ',,1:0], [@1,3:3='$',,1:3], [@2,4:8='names',,1:4], [@3,9:9=':',,1:9], [@4,10:10='{',,1:10], [@5,11:11='n',,1:11], [@6,13:13='|',,1:13], [@7,15:15='$',,1:15], [@8,16:16='n',,1:16], [@9,17:17=':',,1:17], [@10,18:18='{',,1:18], [@11,19:19='$',,1:19], [@12,20:21='it',,1:20], [@13,22:22='$',,1:22], [@14,23:23='}',,1:23], [@15,24:24='$',,1:24], [@16,25:25='}',,1:25], [@17,26:26='$',,1:26]]"; checkTokens(template, expected, '$', '$'); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestTreeConstruction.gunit000066400000000000000000000007401231426731300302160ustar00rootroot00000000000000/** Test ST's AST construction. Translate to junit tests with: * * $ java org.antlr.v4.gunit.Gen TestTreeConstruction.gunit * * Use local version of gUnitBase to avoid dependency on v4 antlr. */ gunit TestTreeConstruction; @header{package org.stringtemplate.v4.test;} options { parser = org.stringtemplate.v4.compiler.STParser; lexer = org.stringtemplate.v4.compiler.STLexer; } template: "<[]>" -> (EXPR [) "<[a,b]>" -> (EXPR ([ a b)) stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestTreeConstruction.java000066400000000000000000000020331231426731300300060ustar00rootroot00000000000000package org.stringtemplate.v4.test; import org.antlr.runtime.RuleReturnScope; import org.antlr.runtime.tree.Tree; import org.junit.*; import static org.junit.Assert.assertEquals; public class TestTreeConstruction extends gUnitBase { @Before public void setup() { lexerClassName = "org.stringtemplate.v4.compiler.STLexer"; parserClassName = "org.stringtemplate.v4.compiler.STParser"; } @Test public void test_template1() throws Exception { // gunit test on line 16 RuleReturnScope rstruct = (RuleReturnScope)execParser("template", "<[]>", 16); Object actual = ((Tree)rstruct.getTree()).toStringTree(); Object expecting = "(EXPR [)"; assertEquals("testing rule template", expecting, actual); } @Test public void test_template2() throws Exception { // gunit test on line 17 RuleReturnScope rstruct = (RuleReturnScope)execParser("template", "<[a,b]>", 17); Object actual = ((Tree)rstruct.getTree()).toStringTree(); Object expecting = "(EXPR ([ a b))"; assertEquals("testing rule template", expecting, actual); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/TestWhitespace.java000066400000000000000000000331461231426731300266010ustar00rootroot00000000000000/* [The "BSD license"] Copyright (c) 2009 Terence Parr All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.stringtemplate.v4.test; import org.junit.*; import org.stringtemplate.v4.AutoIndentWriter; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroupString; import java.io.StringWriter; import static org.junit.Assert.assertEquals; public class TestWhitespace extends BaseTest { @Test public void testTrimmedSubtemplates() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "names", "}>!"); ST st = group.getInstanceOf("test"); st.add("names", "Ter"); st.add("names", "Tom"); st.add("names", "Sumana"); String expected = "TerTomSumana!"; String result = st.render(); assertEquals(expected, result); } @Test public void testTrimmedNewlinesBeforeAfterInTemplate() throws Exception { String templates = "a(x) ::= <<"+newline+ "foo"+newline+ ">>"+newline; STGroupString group = new STGroupString(templates); ST st = group.getInstanceOf("a"); String expected = "foo"; String result = st.render(); assertEquals(expected, result); } @Test public void testDontTrimJustSpaceBeforeAfterInTemplate() throws Exception { String templates = "a(x) ::= << foo >>\n"; STGroupString group = new STGroupString(templates); ST st = group.getInstanceOf("a"); String expected = " foo "; String result = st.render(); assertEquals(expected, result); } @Test public void testTrimmedSubtemplatesNoArgs() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "[]"); group.defineTemplate("foo", "x", ""); ST st = group.getInstanceOf("test"); String expected = "[ foo ]"; String result = st.render(); assertEquals(expected, result); } @Test public void testTrimmedSubtemplatesArgs() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "names", ""); ST st = group.getInstanceOf("test"); st.add("names", "Ter"); st.add("names", "Tom"); st.add("names", "Sumana"); String expected = " foo foo foo "; String result = st.render(); assertEquals(expected, result); } @Test public void testTrimJustOneWSInSubtemplates() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "names", " }>!"); ST st = group.getInstanceOf("test"); st.add("names", "Ter"); st.add("names", "Tom"); st.add("names", "Sumana"); String expected = " Ter Tom Sumana !"; String result = st.render(); assertEquals(expected, result); } @Test public void testTrimNewlineInSubtemplates() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "names", "}>!"); ST st = group.getInstanceOf("test"); st.add("names", "Ter"); st.add("names", "Tom"); st.add("names", "Sumana"); String expected = "TerTomSumana!"; String result = st.render(); assertEquals(expected, result); } @Test public void testLeaveNewlineOnEndInSubtemplates() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "names", "\n" + "}>!"); ST st = group.getInstanceOf("test"); st.add("names", "Ter"); st.add("names", "Tom"); st.add("names", "Sumana"); String expected = "Ter"+newline+"Tom"+newline+"Sumana"+newline+"!"; String result = st.render(); assertEquals(expected, result); } @Ignore("will revisit the behavior of indented expressions spanning multiple lines for a future release") @Test public void testTabBeforeEndInSubtemplates() throws Exception { STGroup group = new STGroup(); group.defineTemplate("test", "names", " \n" + " }>!"); ST st = group.getInstanceOf("test"); st.add("names", "Ter"); st.add("names", "Tom"); st.add("names", "Sumana"); String expected = " Ter"+newline+" Tom"+newline+" Sumana"+newline+"!"; String result = st.render(); st.impl.dump(); assertEquals(expected, result); } @Test public void testEmptyExprAsFirstLineGetsNoOutput() throws Exception { ST t = new ST( "\n" + "end\n"); String expecting="end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testEmptyLineWithIndent() throws Exception { ST t = new ST( "begin\n" + " \n" + "end\n"); String expecting="begin"+newline+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testEmptyLine() throws Exception { ST t = new ST( "begin\n" + "\n" + "end\n"); String expecting="begin"+newline+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testSizeZeroOnLineByItselfGetsNoOutput() throws Exception { ST t = new ST( "begin\n"+ "\n"+ "\n"+ "\n"+ "end\n"); String expecting="begin"+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testSizeZeroOnLineWithIndentGetsNoOutput() throws Exception { ST t = new ST( "begin\n"+ " \n"+ " \n"+ " \n"+ "end\n"); String expecting="begin"+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testSizeZeroOnLineWithMultipleExpr() throws Exception { ST t = new ST( "begin\n"+ " \n"+ " \n"+ "end\n"); String expecting="begin"+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testIFExpr() throws Exception { ST t = new ST( "begin\n"+ "\n"+ "end\n"); String expecting="begin"+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testIndentedIFExpr() throws Exception { ST t = new ST( "begin\n"+ " \n"+ "end\n"); String expecting="begin"+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testIFElseExprOnSingleLine() throws Exception { ST t = new ST( "begin\n"+ "\n"+ "end\n"); String expecting="begin"+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testIFOnMultipleLines() throws Exception { ST t = new ST( "begin\n"+ "\n" + "foo\n" + "\n" + "bar\n" + "\n"+ "end\n"); String expecting="begin"+newline+"bar"+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testEndifNotOnLineAlone() throws Exception { ST t = new ST( "begin\n"+ " \n" + " foo\n" + " \n" + " bar\n" + " end\n"); String expecting="begin"+newline+" bar"+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testElseIFOnMultipleLines() throws Exception { ST t = new ST( "begin\n"+ "\n" + "foo\n" + "\n" + "bar\n" + "\n"+ "end\n"); String expecting="begin"+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testElseIFOnMultipleLines2() throws Exception { ST t = new ST( "begin\n"+ "\n" + "foo\n" + "\n" + "bar\n" + "\n"+ "end\n"); t.add("b", true); String expecting="begin"+newline+"bar"+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testElseIFOnMultipleLines3() throws Exception { ST t = new ST( "begin\n"+ " \n" + " foo\n" + " \n" + " bar\n" + " \n"+ "end\n"); t.add("a", true); String expecting="begin"+newline+" foo"+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testNestedIFOnMultipleLines() throws Exception { ST t = new ST( "begin\n"+ "\n" + "\n" + "foo\n" + "\n" + "bar\n" + "\n"+ "\n"+ "end\n"); t.add("x", "x"); String expecting="begin"+newline+"bar"+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testLineBreak() throws Exception { ST st = new ST( "Foo <\\\\>"+newline+ " \t bar" +newline ); StringWriter sw = new StringWriter(); st.write(new AutoIndentWriter(sw,"\n")); // force \n as newline String result = sw.toString(); String expecting ="Foo bar\n"; // expect \n in output assertEquals(expecting, result); } @Test public void testLineBreak2() throws Exception { ST st = new ST( "Foo <\\\\> "+newline+ " \t bar" +newline ); StringWriter sw = new StringWriter(); st.write(new AutoIndentWriter(sw,"\n")); // force \n as newline String result = sw.toString(); String expecting ="Foo bar\n"; assertEquals(expecting, result); } @Test public void testLineBreakNoWhiteSpace() throws Exception { ST st = new ST( "Foo <\\\\>"+newline+ "bar\n" ); StringWriter sw = new StringWriter(); st.write(new AutoIndentWriter(sw,"\n")); // force \n as newline String result = sw.toString(); String expecting ="Foo bar\n"; assertEquals(expecting, result); } @Test public void testNewlineNormalizationInTemplateString() throws Exception { ST st = new ST( "Foo\r\n"+ "Bar\n" ); StringWriter sw = new StringWriter(); st.write(new AutoIndentWriter(sw,"\n")); // force \n as newline String result = sw.toString(); String expecting ="Foo\nBar\n"; // expect \n in output assertEquals(expecting, result); } @Test public void testNewlineNormalizationInTemplateStringPC() throws Exception { ST st = new ST( "Foo\r\n"+ "Bar\n" ); StringWriter sw = new StringWriter(); st.write(new AutoIndentWriter(sw,"\r\n")); // force \r\n as newline String result = sw.toString(); String expecting ="Foo\r\nBar\r\n"; // expect \r\n in output assertEquals(expecting, result); } @Test public void testNewlineNormalizationInAttribute() throws Exception { ST st = new ST( "Foo\r\n"+ "\n" ); st.add("name", "a\nb\r\nc"); StringWriter sw = new StringWriter(); st.write(new AutoIndentWriter(sw,"\n")); // force \n as newline String result = sw.toString(); String expecting ="Foo\na\nb\nc\n"; // expect \n in output assertEquals(expecting, result); } @Test public void testCommentOnlyLineGivesNoOutput() throws Exception { ST t = new org.stringtemplate.v4.ST( "begin\n" + "\n" + "end\n"); String expecting="begin"+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } @Test public void testCommentOnlyLineGivesNoOutput2() throws Exception { ST t = new org.stringtemplate.v4.ST( "begin\n" + " \n" + "end\n"); String expecting="begin"+newline+"end"+newline; String result = t.render(); assertEquals(expecting, result); } } stringtemplate4-4.0.8/test/org/stringtemplate/v4/test/gUnitBase.java000066400000000000000000000034751231426731300255300ustar00rootroot00000000000000package org.stringtemplate.v4.test; import org.antlr.runtime.ANTLRStringStream; import org.antlr.runtime.CharStream; import org.antlr.runtime.CommonTokenStream; import org.antlr.runtime.Parser; import org.antlr.runtime.TokenSource; import org.antlr.runtime.TokenStream; import org.antlr.runtime.tree.TreeAdaptor; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class gUnitBase { public String lexerClassName; public String parserClassName; public String adaptorClassName; public Object execParser( String ruleName, String input, int scriptLine) throws Exception { ANTLRStringStream is = new ANTLRStringStream(input); Class lexerClass = Class.forName(lexerClassName).asSubclass(TokenSource.class); Constructor lexConstructor = lexerClass.getConstructor(CharStream.class); TokenSource lexer = lexConstructor.newInstance(is); is.setLine(scriptLine); CommonTokenStream tokens = new CommonTokenStream(lexer); Class parserClass = Class.forName(parserClassName).asSubclass(Parser.class); Constructor parConstructor = parserClass.getConstructor(TokenStream.class); Parser parser = parConstructor.newInstance(tokens); // set up customized tree adaptor if necessary if ( adaptorClassName!=null ) { Method m = parserClass.getMethod("setTreeAdaptor", TreeAdaptor.class); Class adaptorClass = Class.forName(adaptorClassName).asSubclass(TreeAdaptor.class); m.invoke(parser, adaptorClass.newInstance()); } Method ruleMethod = parserClass.getMethod(ruleName); // INVOKE RULE return ruleMethod.invoke(parser); } }