Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
990 lines (652 sloc) 31.5 KB
Changes to ST (StringTemplate).
#### Releases
3.2.1: September 22, 2009
3.2: June 11, 2008
3.1: January 23, 2008
3.0: September 6, 2006
2.2: August 5, 2005
2.1: January 22, 2005
2.0: July 16, 2004
1.0.3: Feb 5, 2004
1.0.2: Oct 14, 2003
#### Fixed bugs and changes
09-22-2009 -- 3.2.1 release
o If default arg is a template with single expression wrapped in parens, x={<(...)>},
then eval to string rather than setting x to the template for later eval. Useful
in rare cases where the expression can change value when you read it, such as
accessing time value or random number generator object.
o Added line break operator <\\>. It consumes remaining whitespace on that line, the first
and then any whitespace. Added a number of unit tests. example:
"foo <\\>
emits "foo bar". All of the whitespace after the <\\> gets thrown away like a comment.
o IF with false condition results in missing not empty value. So,
<names:{n | <if(><n><endif>}; separator=",">
doesn't emit a separator for non-cool names. See
WARNING: You now pay a penalty now for a separator if the iterated value is
nullable. Nullable if iterable or a template with nothing buf IF statements.
If nullable, ST writes each element to a temp buffer before emitting. Expensive.
o IF conditionals and list elements couldn't use template
application. Can do $if(names:{$it$})$Fail!$endif$ and
$[names:{$it$!},phones]$ and $[names, ["foo","bar"]:{$it$!},phones]$
Can't use IF inside of a [...] because those are expressions not
o Made template output sensitive to the anchor of any enclosing template
instances. ST used to ignore anchor unless you had a wrap and now it
looks at anchor like an indent; uses widest. ST used to give this:
{ a,
{ 1,
3 }
, b }
for these templates where the first was stuck into second
<\n>{ <stuff; anchor, separator=",\n"> }<\n>
{ <values; anchor, separator=", "> }
but now gives:
{ a,
{ 1,
3 }
, b };
see testSubtemplatesAnchorToo()
o To deal with combined anchors and indentation, force indents to
include any current anchor point. Prevents a check later in write
to deal with anchors when starting new line. See pushIndentation()
06-11-2008 -- 3.2 release
o Fixed ST-36; allow <elseif>
o Fixed ST-37; chk for null
o Added \r\n normalization in AutoIndentWriter. Converts \r\n or \n
to whatever the writer's newline instance var is. wrap="\n" will
give the proper newline by locale as will \n and \r\n in the
templates or even incoming data attributes (toString()'d of course).
Added unit tests. It even works with special literals <\r\n> and <\n>.
o Fixed ST-39; an obscure memory leak issue with embeddedInstances
o rest and strip returned iterators. Made them return show list copies
so recursion works. iterators have side-effects. Added 2 unit tests.
o implemented trunc. returns all but last element.
o Fix ST-33; [a,b] cat function used iterators; side-effect problem.
o Had a problem with "int" : "0" in a map but ST as incoming lookup key.
Decided that I'd lookup as raw object first so Integer lookup works
but I try toString version if not found. Document this!
o <aMap.(k)> no longer calls toString() on k.
<aMap.keys:{k|<k>:<aMap.(k)>} was not working when aMap had Integer
keys. Added unit test.
o Made unit tests not depend on map order. commented out tests that fail.
o debug tags now emit group name with tags. improves debugging ability.
01-23-2008 -- 3.1 release
o reader was not closed in PathGroupLoader.
o removed some counters used to test the efficiency of reflection cache.
o updated unit tests to work with new improved error messages.
o $first(list).prop$ is not allowed. Fixed and added a unit test.
o Improved error message for "template not found". Shows template hierarchy
now not just context (if any). E.g.,
Can't find template; group hierarchy is [Java]
o allows unicode escapes as expression literals but only if it's the whole
expression: <\uFEA5\n\u00C2> Previously could only do one char and just
the special ones like <\n>.
o resolve ST-34. Super group loading was not using template lexer
(<...> or $...$) according to subclass. Updated group loader interface.
o added elseif. $if(x)$...$elseif(y)$...$else$...$endif$
o updated some unit tests (names, guts) to make more sense.
o updated group.g and eval.g so that list literals can have empty
atoms like $["a",,"b"]:{n | ...}; null="nullstring"$.
o "default" was not a valid value in map. had testLiterals looking even at strings in lexer for
group.g. ST-15
o ST-18 fixed. put close in a finally block.
o i0 was not set when you applied a template to a single value.
o Thomas Brandon pointed out that we have a bug in our if/else computation.
You could not reference super.attr inside the if/else sub templates.
August 6, 2007: 3.1b1 (starting towards a 3.1)
o changed to 3.1b1 in anticipation of diong a 3.1 release using ANTLR v3.
o Updated group.g to allow default clause by itself in map (from Caleb Lyness)
o Caleb also revamped entire TestStringTemplate to run under windows.
o Added 16 bit char unit test also.
o Made convertArrayToList create an ArrayWrappedInList so it doesn't
copy arrays any more.
o John Snyders found bug in format stuff. Renderer was being called
for string expr options.
o Another bug fix by John. Length problem.
o added format option
o \_ was not allowed in group/interface.g but in group.g. Now \_ is
allowed as first char.
o ST.dup() was not copying renderers field.
September 6 -- 3.0 release
o added toString to Aggregate so that setAttribute("foo.{x,y}", ...) and
then referencing foo in isolation prints something useful.
o had to fix that:
InputStream is = cl.getResourceAsStream(fileName);
if ( is==null ) {
cl = ErrorManager.class.getClassLoader();
is = cl.getResourceAsStream(fileName);
o allow different source of classloader:
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if ( cl==null ) {
cl = this.getClass().getClassLoader();
o fixed bug where separator did not appear in lists of stuff with lots
of null entries.
o map still iterates over values if you say <aMap> but it is now
shorthand for <aMap.values>. Similarly <aMap.keys> walks over the keys. You can do stuff like: <aMap.keys:{k| <k> maps to <aMap.k>}>.
o added length(attribute) thanks to Kay Roepke. For now it does not
work on strings; it works on attributes so length("foo") is 1 meaning
1 attribute. Nulls are counted in lists so a list of 300 nulls is
length 300. If you don't want to count nulls, use
o added strip(attribute) that returns an iterator that
skips any null values. strip(x)=x when x is a single-valued
attribute. Added StripIterator to handle this.
o BACKWARD INCOMPATIBLE: I had to make a more clear distinction
between empty and null. Null means there is nothing there whereas
empty means the value is there but renders to an empty string. IF
conditionals now evaluate to empty if condition is false.
o BACKWARD INCOMPATIBLE: Changed how separators are generated. Now I
generate a separator for any non-null value in the list even if that
value is a conditional that evaluates to false. Iterated empty values
always get a separator. Note that empty is not the same thing as
missing. "" is not missing and hence will get a separator.
This made the ASTExpr.write separator computation much simpler and
allowed me to properly handle the new "null" option.
o Added null=expr option on expressions.
For null values in iterated attributes and single attributes that are
null, use this value instead of skipping. For single valued
attributes like <name; null="n/a">
It's a shorthand for
For iterated values
<values; null="0", separator=",">
you get 0 for or null list values. Works for template application
like this also:
<values:{v| <v>}; null="0">
This does not replace empty strings like "" as they are not null.
o made static maps in STG synchronized, also synchronized the look
up/def methods for templates in STG.
o removed reflection property lookup; too complex for value. profiling
indicates it's a small cost. No thread synch issues either now.
o template evaluation for anonymous templates did not properly look up
overridden templates. The group for anonymous templates was not reset
to be the current enclosing template's group (remember we can dynamically
set the superGroup).
o Signature changed to use AttributeRenderer:
public void registerRenderer(Class attributeClassType,
AttributeRenderer renderer)
o If expr in <(expr):template()> evaluated to nothing, the template was
still invoked.
o added ability to show start/stop of template with <name>...</name>.
clean up! emitTemplateStartDebugString/emitTemplateStopDebugString
and doNotEmitDebugStringsForTemplate(tempaltename) and
o Improved error when property ref causes the error internally. Now shows
that exception rather than invocation target exception.
o Couldn't handle List<int[]>. Nested int[] was not iteratable.
o Couldn't gen \ in a template. \<value> in a template escaped the <.
\\<value> printed both slashes. Fixed.
o added line wrap facility. st.toString(72). Wraps in between
expressions or elements of a multiple value attribute if you use
new expression option "wrap". It will not break line between
element and separator. toString(72) followed by toString() does not
wrap on the second invocation. Wrap is a soft width; does not break
elements to enforce a hard right edge. WARNING: separators and wrap
values are templates and are evaluated once *before* multi-valued
expressions are evaluated. You cannot change the wrap based on, for
example, <i>. Default values for wrap="\n", anchor="true" (any
non-null value means anchor).
o Updated StringTemplateWriter:
void pushAnchorPoint();
void popAnchorPoint();
void setLineWidth(int lineWidth);
/** Same as write, but wrap lines using the indicated string as the
* wrap character (such as "\n").
int write(String str, String wrap) throws IOException;
/** Write a separator. Same as write() except that a \n cannot
* be inserted before emitting a separator.
int writeSeparator(String str) throws IOException;
o Examples of wrapping:
data(a) ::= <<int[] a = { 1,9,2,<values; wrap, separator=","> };\>>
int[] a = { 1,9,2,3,9,20,2,1,4,
4,9,20,2,1,4,63,9,20,2,1,4,6 };
data(a) ::= <<int[] a = { 1,9,2,<values; wrap, anchor, separator=","> };\>>
int[] a = { 1,9,2,3,9,20,2,1,4,
2,1,4,6 };
data(a) ::= <<int[] a = { <{1,9,2,<values; wrap, separator=",">}; anchor> };\>>
int[] a = { 1,9,2,3,9,20,2,1,4,
1,4,6 };
o Couldn't use \\\{ inside of a {...} anonymous template.
o Fixed: you could not have template expressions, just simple
expressions in indirect template expressions like
$data:("foo":a())()$. I decided not to allow IF expressions inside.
o now throws exception when dots are in template names or attribute names
o don't set "it" nor "attr" default attributes if there is a parameter
to an anonymous block like <names:{n | ...}>
o Bug fix. If you passed in a list and then another element, it added
it to the list you passed in! Now, I make a (shallow) copy of the list.
o Bug fix. If you passed an element then a list to an attr and I
think it didn't flatten out properly!
o added build.xml ANT file (ick)
o {} and "" work as arguments now to templates
o Couldn't escape in template group. \>> failed as did {...\}} for
anonymous templates.
o When creating an aggregate list, couldn't have spaces in {...} such
as "folders.{a, b}".
o Embedded templates such as {...} anonymous templates couldn't see
the renderers for enclosing templates. Easy to set one renderer in
root template for, say, Date and forget about it. If none found for
that class in containment hierarchy, then group hierarchy is checked.
o using nativegroup to create instances now in ST.getInstanceOf. Needed
so that works properly. THe new instance's group will point at
creating group so polymorphism works properly.
o BACKWARD INCOMPATIBLE: <...> is now default delimiter for group files.
o note in doc that map strings are now templates and that <<...>> works too.
default or others can have empty values (implying no value) or use "key"
but not in template; it's a keyword.
Also, default must be at end now (and only 1). Default value is empty
as before.
To return null, use "default :" at end. Can use empty values too:
{"float":}, {"int":"0"}, ...
o added cache for all obj.prop lookups
o added PathGroupLoader/CommonGroupLoader (which uses CLASSPATH)
o added i0 which is like i except indexed from 0 not 1.
o auto defined attribute i was not defined for <a,b: {...}> case. ooops.
o You couldn't have '=' in a string if preceded by '+' like foo+"ick=".
o Added default lexer mechanism for groups so you can set once
public static void registerDefaultLexer(Class lexerClass)
o Added STG.getInstanceOf(name,attributes)
o Fixed bug where an expr on the first line that yields no output left
a blank line.
o Added group inheritance notation; added unit tests. setSuperGroup(name)
now does something useful. Notation:
group subG : superG;
o Added interfaces. See unit tests.
group Java implements ANTLRCoreTarget;
rule(...) ::= "..."
You can say "optional template(args);" also. Uses group loader to
find interfaces.
o Added CommonGroupLoader so you can reference groups/interfaces now
in group files etc...
String tmpdir = System.getProperty("");
StringTemplateGroup.registerGroupLoader(new CommonGroupLoader(tmpdir,errors));
The tmpdir can be "dir1:dir2:dir3" etc...
o There was a bug in StringTemplateGroup.isDefined that it always
returned true.
o Added StringTemplate.getDependencyGraph() to get a list of n->m edges
where template n contains template m. Also made convenient
getDOTForDependencyGraph(). You get a template back that lets you reset
node shape, fontsize, width, height attributes. Use removeAttribute
before setting so you are sure you only get one value.
o Added StringTemplate.toStructureString() to help discover nested structure.
If you iterated multiple empty attributes, it iterated once with null values. Bizarre. Fixed.
Bug in polymorphism when an overridden template called its super which called
another template which was also overridden; didn't call the overridden method.
Fixed getInstanceOf() so that it always sets the proper group so polymorphic
template lookup also starts at the right group.
Test testLazyEvalOfSuperInApplySuperTemplateRef was wrong...The
"super." prefix is (like in Java, ...) a scope override and is always
evaluated relative to the template in which it was defined not the
template in which it is evaluate!
Ugh. I *think* I have this polymorphism nailed down now.
Improving error messages to be more specific when you get a parser error.
I'm including more context info and hopefully the file within a group file
the error occurs.
The defaultGroup is now public so you can know StringTemplate's default group
when you see it:
public static StringTemplateGroup defaultGroup =
new StringTemplateGroup("defaultGroup", ".");
Template polymorphism bug: wouldn't work for references in IF clauses!
Added regions.
Any Map instance is now allowed as a "map" attribute not just Hashtable, HashMap.
NullPtrExc if you registered a renderer and sent an object as an attribute
of another type!
The tree viewer didn't work; class cast problem with Hashtable vs HashMap.
Thanks to Joe Soroka, he showed me how to fix some weird thing in Java
where public members of an anonymous class weren't visible to
StringTemplate. You have to setAccessible on the field or method
object. Bizarre.
o removed debug code as it's useless/broken
o decided that {+} should not be the list creation operator. {[a,b,c]}
should be the thing as it mirrors the maps in group files. I want {+}
to mean add still.
o also decided that default arg values are templates only if "\{...}"
is used and strings in arg lists are just strings. I added \{...}
instead: $bold(it=\{$name$ Parr})$ instead. Default values can be
string and {...} as can args. You can have {...} on left side of
apply now: $\{foo}:\{($it$)}$
o Decided that {+} should always return a multi-valued attribute;
_this is backward incompatible for anyone using + to mean string
cat_. Instead of
now do this:
o added multiple attributes to left of the apply operator; works for
anonymous templates only! $names,phones:{n,p | $n$: $p$}$. An error
is generated if you have too many args for the number of parallel
lists. Iteration proceeds while at least one of the attributes
({names} or {phones}, in this case) has values.
o added '+' cat operator for multi-valued attributes, yielding single,
longer multi-valued attribute. $mine+yours$ is a new list with both
elements; all of "mine" first then all of yours.
o allows any template invocation to assume sole argument name if
just one formal argument. If you do {$bold(name)$} and {bold} has one
formal argument, then it gets the value of name. This works also for
template application:
test(names) ::= << <names:bold(),italics(); separator=", "> >>
bold(x) ::= "*<x>*"
italics(y) ::= "_<y>_"
Note: The binding of a value to the name of a sole formal argument is
done dynamically so that indirect template invocation and lazy
evaluation stuff works properly. For example {(templateName)(value)}
should work for different templates with differently-name (but sole)
args. See unit test testInvokeIndirectTemplateWithSingleFormalArgs().
o I changed the first, rest, tail operators from yesterday. It was
weird doing {users:first()}...seems like {first(users)} is better.
This introduces a function-like syntax, which necessitated the "assign
to sole formal arg" functionality above that supports things like
{bold(name)}. Makes it possible to say {first(rest(names))} to get
second element now. Previous syntax made it impossible.
o Added attribute functions: first (get first element), last (get last
element) and tail (get everything but first element). [backward
incompatible if you used first,last,tail as an attribute or template
o if you are applying a template to a list and that template only has
one formal argument, that arg gets the same value as the iterated
value, "it". I.e., previously this didn't work: $list:bold()$ where
bold was
bold(item) ::= "<b>$item$</b>"
A template define as
bold() ::= "<b>$it</b>"
would still work though.
o You can define arguments for anonymous templates now, which is much
nicer that using <it> all the time:
$names:{n| $n$}; separator=","$
o To define an empty template, you had to write <<>>; "" didn't work.
o Added maps to the group:
typeInitMap ::= ["int"="0", "float"="0.0", default="null"]
then within a template you can refer to them {<>},
which returns "0". Those strings are actually templates, but I can't
really think of a use for that just yet. ;) If your type name is an
attribute not a constant like int, then use
{<typeInitMap.(typeName)>}. The maps are defined in the group's scope
and are visible if no attribute hides them. For example, if you
define a formal argument called {typeInitMap} in template {foo} then
{foo} cannot see the map defined in the group (though you could pass
it in, which would be the point). If a name is not an attribute and
it's not in the group's maps table, then the super group is consulted
etc... You may not redefine a map and it may not have the same name
as a template in that group. The {default} value is used if you use a
key as a property that doesn't exist. For example {<>}
returns "{null}".
o Added renderers per template and group. Templates are inherited
from super group. Thanks to Anton Keks for his suggestion and sample
o literal arguments are now templates not just strings. :)
You can even use <<...>> literals as argument now.
In bug list:
Template inclusion expressions won't accept a nested template
as an argument. I'd like to be able to write <foo(bar={...})>, which
would mean the same thing as <foo(bar="":{...})>.
o added default argument templates like bold(x="empty") ::= ...
Note: because of lazy evaluation semantics, default value templates may refer
to argument values. Everything is evaluated after arg values are set.
This works for invoked templates and templates you create with code.
o all strings are now templates; does that mean "\n" is not newline anymore? Did I break compatibility?
o when calling another template, y, from within a template, x, none of the
x parameters are visible to y because the formal parameters force you to
define values. This prevents surprises and makes it easy to ensure a
a value is empty unless you specifically set it for that template. The
problem is that I need to factor templates sometimes and I want to refine
behavior with a subclass or just invoke another shared template but
<y()> erases all of x's parameters. Perhaps <y(\*)> or <y(...)> as a
syntax to indicate y should inherit all values. <y(name="foo", ...)>
would mean that I set one, but the others are inherited whereas
<y(name="foo")> only has name set; others are empty. Ok, I made it
work today. Was a 10 minute tweak. Easy. You can set manually with
StringTemplate.setPassThroughAttributes(). This is awesome.
o When you invoke foo(x=y), x must be an attribute of foo (well if you
have formal args defined that is) and y is evaluated within the
context of the surrounding template; more precisely, it's evaluated in
the context of the actual template invocation (which can have
predefined attributes like attr, it, and i). It's weird, but foo(x=x)
also makes sense. See new unit test testArgEvaluationContext(). This
was not working before, though I thought it was!
o error messages are better for setting an undefined argument.
o When a property is not found, you get a better error. I show the
template context (nested tree of templates).
o Collections, Maps, and Iterators that are non-null but have no elements
return false in conditionals; e.g., $if(users)$ is false if users is
an empty list.
o added template context upon no such element. It says stuff like:
no such attribute: decisionNumber in template context
[outputFile lexer cyclicDFA cyclicDFAState cyclicDFAEdge lookaheadTest]
o added ability to use indirect property names. $user.(propName)$
evaluates (propName) to find the name of the property and then looks
it up in user object.
o Empty output for a single attribute expression one a line by itself gets no newline (i.e., you don't get a blank line).
o You can access public fields now instead of via just accessors
o empty (i.e., no char output) values in an iteration do not get a separator if specified. This will be 99% of the time what you want. Only if pure IF (no else).
o Made convertArrayToList() handle long[] also and made "a.{f1,f2}" type aggregate attributes properly convert incoming arrays to lists for normalization.
o Made a template lookup that is not defined throw an IllegalArgumentException rather than generate an error directly.
o Made null indirect template generate nothing; used to generate null-ptr exception.
o trap all antlr generated errors now and send to listener.
o Added
/** Specify a StringTemplateWriter implementing class to use for
* filtering output
public void setStringTemplateWriter(Class c) {
userSpecifiedWriter = c;
and made StringTemplate.toString() sensitive to it.
o added support for nonlocal file encodings; added property fileCharEncoding. The template loading routines are now sensitive to this property. Defaults to the file.encoding system property.
o STG.templateIsDefinedInThisGroup -> isDefinedInThisGroup
o added isDefined(name) that checks whole hierarchy
o addressed whitespace at begin/end of template .st file issue. Decided to let it continue to strip all front/back whitespace and then make you add it directly. This is a simple rule and can be made to do what you want. It is consistent with the strip newline before \>\> rule too.
o added <\ > for space char
o updated testing harness to be same as ANTLR 3.0's which is more sophisticated.
o the newline immediately preceding >> in a template group file is tossed out just like the newline right after the \<<
o newlines ignored before <else> and <endif>. Rule is: kill a single newline
after <if>, <<, <else>, and <endif> (but for <endif> only if it's on a line by itself) . Kill newlines before <else> and <endif> and >>.
o added <\n>, <\r>, <\t>
o fixed \n refs in TestStringTemplate unit tests to be portable newline reference.
o added $!...!$ and <!...!> comments (version 2.1b3)
o allow HashMap, Hashtable precisely but not Map in lookup
o $attributes$ is a text string when lint mode on that recursively dumps
out types, properties, etc... (no values)
o Templates track their embedded instances; can ask for embedded
o added isXXX accessor properties so x.special invokes x.getSpecial then x.isSpecial if not successful.
o bug in st.attribute...if no attributes table, got null ptr exception
o given the big changes to ST, I'm going to deprecate attr and use "it" as the default iterator attribute. Says "iterator" and is sort of like "this". I looked at "this", "that", "iter", and even "the". "ith" even [i].
o a.b yields a's b attribute if a is stringtemplate, which lets you treat a list of templates or nested set of templates as a data structure. For example, given a list of templates representing output rules from antlr, i can generate both the C function definitions for those rules and the list of C function declarations:
<rules:{public void <>(<attr.args);}>
<rules:{public void <>(<attr.args) {<attr.body>\}}>
o applying a template to a list of attributes reused the same template, but you need a new one to get a new attribute set etc...
o apply a template to a list of attributes did a toString() rather than build up a list of templates to apply later.
o to prevent recursion, formally defined parameters hide any (dynamically) enclosing scope. The attributes can be null or have values still, but you cannot inherit an attribute from an enclosing scope, bypassing an empty local attribute formally defined in that template. See test case that used to cause infinite recursion. Hmm...can i limit to the case where same template is up the call stack somewhere? Any other inheritance should be ok, right? This
is not always what you want. If you set the font for a table, then nested
tables cannot inherit the font. However it prevents you from forgetting to
set the rows attr in the nested, which would cause an infinite recursive loop. Actually figured out precisely what it should be. Can't avoid infinite recursion without expensive tests so make part of lintMode:
StringTemplate: error: possible recursive self-reference to stats in template ifstat
If you get a value in getAttribute that refers to the current template or an enclosing template, must be in an infinite loop. Can't stop it, but error to errorListener. Ok, now I really have it. In ASTExpr.write, if the object to write out is a ST, then it walks up enclosing chain and makes sure it is unique. Otherwise, it's infinite recursion. Same template, different instance is fine. Only in lintMode! throws IllegalStateException.
Back to formal arg always hides enclosing value, though if you stick in a looped attribute set then I catch it in lint mode.
o added helper method setAttribute(String,int)
o removed ability to pass hashtable in as initial hole.
o included templates like <font()> computed the text right away rather
than lazily evaluating when the outer template evaluated. Missed some
parameters that way.
o when embedding a template inside another via setAttribute, it must set the
enclosingInstance so that it can inherit attributes. This was not working
when you setAttribute("foo"...) multiple times for attribute foo. It was
just adding stuff to the internal array without checking to see if it was
a ST.
o Improved test harness so we can time tests; added some eval speed tests.
o nested IF works
o $else$ clause added
o antlr lexer used to chunk now two predefined $..$ and <..>
o added group file format
o changed boolean so that you are testing its value not presence/absence
o added formal parameter checking. Can only set attributes that exist at
a template or enclosing template. Can only ref attributes that exist at
that template or above. Throws NoSuchElement exceptions.
o added general notion of StringTemplateWriter so you can do output filters.
o predefined auto indentation filter (default used).
o properties that return arrays are converted to iterators. Factored out
this normalization code into static ASTExpr methods. Did not handle properties that return collections as multi-valued values.
o Added Collection and Iterator stuff in ASTExpr writeAttribute. Can dump or apply template to either Map, Collection, or Iterator now.
o anything iteratable can be used for "APPLY" template
o Fixed some errors in the escape char when in anonymous templates {...}
o Fixed so nested anonymous templates works now.
o Changed some protections and so on so that can override behavior more
o Make StringTemplate to List interface or collection.
[Fixed 5-17-2003]
o Need $(foo)()$. What about $names:(boldtemplate)():italics()$?
What about $(foo)()+(bar)()$? $(foo+".template")()$
[Fixed 5-17-2003]
o if a template name is not found, it will still try to apply it to an
[Fixed 5-15-2003]
o fix missing end $. now it consumes the rest of the file.
[Fixed 5-15-2003. Well, it still consumes, but now the listener gets
the error actually.]
o add more messages that go to the error listener
[Fixed 5-15-2003]:
added warning(msg) to listener
added setLintMode(true), makes setting of unknown attr a warning
4-01-2003 [Fixed 5-15-2003]
o attr is not re-evaluated in template application to a vector--args
are evaluated a priori!
does not work!