Skip to content

Tea Template Language

jappy edited this page Oct 15, 2011 · 19 revisions

Introduction to Tea
Embedding Tea
Lexical Structure
Templates
Functions
Grammar Summary

3 - Lexical Structure

4 - Templates

5 FUNCTIONS

5.1 - Calling Functions and Templates

The call statement is used to invoke other templates or to call built-in Java functions. Both templates and Java functions may return a value. Ones that don't, (they return void) are invoked with a call statement. Otherwise, it is invoked with a call expression. The syntax of the two types of calls are identical, and are only distinguished by the presence or absence of a return value. A template returns a value using its last expression statement (see 4.1.7 Expression Statement).

CallStatement / CallExpression:
Name ( Listopt ) Blockopt
call  Name ( Listopt ) Blockopt

The optional block part of the call statement is used to pass a block to another template or to a built in Java function. A template can be called by its short name or its full name. A template's short name is the same as defined in its declaration. Its full name is based on the root directory from which it is stored. Essentially, templates can be packaged, but templates don’t have package declarations. For example, the full name of a template declared as "header" in the "common" directory is named "common.header". When a template invokes another template within the same package, the full name is not required.

Functions are defined in a template's runtime context class. The template has no control over what context it receives. It is the responsibility of the hosting system to provide one. Any function that contains '$' characters in the name can be invoked in Tea by substituting '.' characters.

A set of standard functions are defined in the Java interface com.go.tea.runtime.Context and its sub-interface, com.go.tea.runtime.UtilityContext. Functions that apply to locale and formatting are "sticky" and remain active until the top-most template returns or the setting is changed again. In addition, a called template can change these settings, possibly affecting the caller. The string manipulation functions do not alter the first string argument, but instead return (possibly) a new string with changes.

Examples:

// Convert to lowercase 
message = toLowerCase(message)

// Invoke a template named "header" in the same package as this one
call header("Header text")

// Invoke a template using its full name
call common.header("Header text")

// Invoke a template and pass a substitution block
name = "John"
call bigtext() {
    if (name == "Bob") {
	// Bob is welcome...
	"Hello Bob!"
    } else {
	// ...others are not
	"Go away, " & name & "."
    }
}

The header and bigtext templates are defined as follows:

<% template header(String title) %>
<html>
<head><title><% title %></title></head>
<body>

<% template bigtext() {...} %>
<font size="50"><% ...  %></font>

5.2 - Function List

setLocale
setLocale(Locale locale)
setLocale(String language, String country)
setLocale(String language, String country, String variant)

Setting the locale resets date and number formats to the default for that locale. Setting a locale of null resets date and number formats to the system defaults. Since a template cannot create a specific Locale object itself, the first form is most useful if the hosting system provides a Locale object via a function or bean property.

getLocale
java.util.Locale getLocale()

Returns the current locale setting. Null if none set.

getAvailableLocales
Locale[] getAvailableLocales()

This function returns, in Locale objects, a list of all the available locales in the system. This is useful for writing a template that displays the capabilities of its hosting system.

nullFormat
nullFormat(String format)

By default, null references are printed with the string "null". This function allows that setting to be overridden. Passing null sets the format back to "null".

getNullFormat
String getNullFormat()

Returns the current null format specification. Null if none set.

dateFormat
dateFormat(String format)
dateFormat(String format, String timeZoneID)

Defines a format to use when printing dates from templates. Passing null sets the format back to the default. The format string is of the form "MM d yyyy". Date formatting is provided by the Java class java.text.SimpleDateFormat. Refer to its documentation for more information.

getDateFormat
String getDateFormat()

Returns the current date format specification.

getAvailableTimeZones
TimeZone[] getAvailableTimeZones()

Returns, in TimeZone objects, a list of all the available time zones in the system. This is useful for writing a template that displays the capabilities of its hosting system.

getDateFormatTimeZone
String getDateFormatTimeZone()

Returns the current date format time zone.

numberFormat
numberFormat(String)

Defines a format to use when printing numbers from templates. Passing null sets the format back to the default. The format string is of the form "#.#". Number formatting is provided by the Java class java.text.DecimalFormat. Refer to its documentation for more information.

getNumberFormat
String getNumberFormat()

Returns the current number format specification. Null if none set.

getNumberFormatInfinity
String getNumberFormatInfinity()

Returns the current number format for infinity. Null if none set.

getNumberFormatNaN
String getNumberFormatNaN()

Returns the current number format for NaN (Not-A-Number). Null if none set.

currentDate
Date currentDate()

Returns a Date object with the current date and time of when this function is called. Subsequent calls within the same template may return a different date.

startsWith
boolean startsWith(String str, String prefix)

Tests if the given string starts with the given prefix.

endsWith
boolean endsWith(String str, String suffix)

Tests if the given string ends with the given suffix.

find
int[] find(String str, String search)
int[] find(String str, String search, int fromIndex)

Finds the indices (in an array) for each occurrence of the given search string in the source string, optionally starting from the given index.

findFirst
int findFirst(String str, String search)
int findFirst(String str, String search, int fromIndex)

Finds the index of the first occurrence of the given search string in the source string, optionally starting from the given index, or -1 if not found.

findLast
int findLast(String str, String search)
int findLast(String str, String search, int fromIndex)

Finds the index of the last occurrence of the given search string in the source string, optionally starting from the given index, or -1 if not found.

substring
String substring(String str, int start)
String substring(String str, int start, int end)

Returns a substring using the substring method defined for the Java String class. Start and end position is zero-based, and the end index is exclusive.

toLowerCase
String toLowerCase(String str)

Returns a new string of all lowercase letters from the contents of the string passed in.

toUpperCase
String toUpperCase(String str)

Returns a new string of all uppercase letters from the contents of the string passed in.

trim
String trim(String str)

Trims all leading and trailing whitespace characters from the given string.

trimLeading
String trimLeading(String str)

Trims all leading whitespace characters from the given string.

trimTrailing
String trimTrailing(String str)

Trims all trailing whitespace characters from the given string.

replace
String replace(String source, String pattern, String replacement)
String replace(String source, String pattern, String replacement, 
               int fromIndex)
String replace(String source, Map patternReplacements)

Replaces all exact matches of the given pattern in the source string with the provided replacement, optionally starting from the given index. Another form applies string replacements using the pattern-replacement pairs provided by the given map (associative array). The longest matching pattern is used for selecting an appropriate replacement.

replaceFirst
String replaceFirst(String source, String pattern, String replacement)
String replaceFirst(String source, String pattern, String replacement,
                    int fromIndex)

Replaces the first exact match of the given pattern in the source string with the provided replacement, optionally starting from the given index.

replaceLast
String replaceLast(String source, String pattern, String replacement)
String replaceLast(String source, String pattern, String replacement,
                   int fromIndex)

Replaces the last exact match of the given pattern in the source string with the provided replacement, optionally starting from the given index.

shortOrdinal
String shortOrdinal(Number n)

Returns a number’s abbreviated ordinal text i.e. 1st, 2nd, 3rd etc. Tea currently does not support localized ordinal numbers.

ordinal
String ordinal(Number n)

Returns a number’s ordinal text i.e. first, second, third etc. Tea currently does not support localized ordinal numbers.

cardinal
String cardinal(Number n)

Returns a number’s cardinal text i.e. one, two, three etc. Tea currently does not support localized cardinal numbers.

6 - TYPE CONVERSION

Although variables in Tea are implicitly typed, Tea is still strongly typed and type conversion operations are performed automatically.

The exception to this are variables that are declaratively typed using define or as. In this case, when an assignment occurs along with a type cast, the compiler will verify that this cast is valid and report an error if not.

Conversions that are automatically applied are usually guaranteed to always succeed. For example, an automatic conversion from Integer to String is preferred over String to Integer because Strings can represent the value of any Integer, but the opposite is not always true. Other kinds of conversions are applied to convert primitive data types to objects and vice versa. When performing addition on an int and an Integer, the Integer is converted to an int in order for the addition to be applied. This conversion could fail, however, if the Integer type being converted references null. In this case, a NullPointerException is thrown.

If the compiler cannot perform a conversion for any reason, the type checker generates an error and the template doesn’t compile. This is generally caused by a true error on the part of the template writer, for example trying to use a boolean where an int should go.

6.1 - Method Binding

Since Java methods can be overloaded to accept parameters of different types, the Tea compiler needs to decide on which method to bind to based on which types fit best. In Java, a cast operation can be applied which forces the binding if there is an ambiguity. Since Tea has no cast operation, the compiler binds to a method by calculating a conversion cost to all the parameters.

A conversion from an int to an Integer is deemed to cost higher than converting an int to a long. If a method is overloaded to accept an Integer or a long as a parameter and the template has an int, the method that takes the long is preferred and is called instead.

6.2 - Primitive Types

Tea treats primitive types as though they were objects, except it will use primitive values wherever possible for performance. If a template passes an int to a method that accepts an Integer, a Number or just any Object, the int is converted to an Integer. If the template passes a Number to a method that accepts an int, the intValue method is called to get at the int value.

Conversion can also be applied between primitives of differing precision. If given a choice, the compiler attempts to apply the conversion with the least loss of precision. A conversion of an int to a double is preferred over the reverse, for example. Also, if given a choice, the compiler will choose to apply a conversion that does not create a new object. Tea only performs conversions between primitive data types that represent numbers. For example, a number cannot be used where a boolean is accepted. Even though Java treats char as an unsigned 16-bit number, Tea treats it as a character, and it often gets converted to a String.

A numerical conversion from an integer to a double or float can always be forced by adding 0.0 or 0.0f. This is useful for displaying the result of a division without losing the fractional part.

6.3 - Conversion to String

Any object and primitive type in Java can be converted to a string. If given the choice, however, the Tea compiler avoids doing this as it is considered a last resort. Binding an int to an Object parameter is preferred over a String parameter because it will convert it to an Integer, which is a more precise representation.

String conversion may cause a formatting operation to be applied. If the object being converted is null, the current null format is applied (see 5.2 Function List). If a date or a number, the current date or number format is applied.

The string concatenation operation, '&', always forces its operands to be converted to strings, and the resulting expression is (of course) a string. Concatenating with "" is a convenient way of forcing an expression to be converted to a string.

6.4 - Variable Promotion

A variable assignment in the scope of a block can be promoted to appear after that scope. This applies to if statements, foreach statements and calls that accept blocks. Consider the following code:

w = "Monday" // w is a String
if (value == "something") {
    x = "Hello" // x is a String
    y = 76.6    // y is a double
    z = "ZZZ"   // z is a String
}
else {
    w = currentDate() // w is a Date
    x = 56            // x is an int
    y = 89            // y is an int
}

After the if statement, the following variables will be available for use: w, x and y with the respective types: Object, Object and double. The z variable is unavailable since it was only assigned in the then part of the if statement, and therefore there is no guarantee that will contain a legal value.

When promoting variables from an inner scope, the Tea compiler chooses a compatible type that represents the merged type as specifically as possible. For objects, it does this by analyzing the inheritance graph. The common type produced for java.util.Vector and java.util.Set is java.util.Collection.