-
Notifications
You must be signed in to change notification settings - Fork 45
Template Engine
In Greed, Templates
are used to generating code to test your program against the example test cases. Many other plugins, like FileEdit, supports templates, too. But in Greed, templates are much more powerful and completely flexible. You can involve in almost every step of the code generation and take full control of the generating process.
There are too many details for me to describe when writing a template. The best way to learn this is through examples. Here're some default templates in which you can work based on. If you have finished reading other pages, you must've understand what these templates are.
I'll cover some basic knowledge of the template engine in the following section.
To fully enable the power of template, we use a lightweight template engine jmte. It's efficient, simple, and enough powerful (maybe not :3).
If you're interested in this engine, read its documentation.
But as in Configuration, I'll briefly describe the template language, although the documentation of jmte has done such a thing. I've made several changes to the template itself, so we have to describe these things.
Template keys are surrounded by ${
and }
. Anything else will be directly copied to the rendering result.
Templates are translated based on a model. The model is a String->Object
mapping, in which Object
can be anything.
jmte provided built-in functional templates like ${if}
, ${foreach}
, described below:
-
${if X}...${else}...${end}
- if keyX
is found in the model, the...
is inserted, the${else}
is optional. -
${foreach values v , }...${end}
-values
is a iterable object, and the loop will bindv
to every value invalues
,v
will be put in the model while in the scope in the...
. A,
is inserted after every...
block, except the last one.
Recall the ${Contest.Name}
in pathPattern
? If you wanna, you can write ${Contest.Name}${if Contest.Div}/DIV ${Contest.Div}${end}
.
It'll produce folder path like SRM 257/DIV 2
if SRM 257
contest has a division, or just SRM 257
if not.
When rendering a data like ${a.xyz.uvw}
, the template engine usually do the following:
- Find a key in the map called
a
, if not present, returns""
. - If present, check its value
- If it's an object
o
, try the following until found one available:o.getXyz()
,o.isXyz()
,o.xyz
(public field) - If it's another map, goto 1
- Otherwise, returns
""
- If it's an object
When it hits the final key in the path, uvw
in this case, and now the value is o
, the result is
- If
o
is of a primitive type, returns its string representation - If
o
is an raw object, first find a typed renderer based on its class - If not found, call its
toString
Like in the following table, Contest
is an object of type greed.model.Contest
, hence
${Contest.Name}
represents the full contest name.
This part is not available in the official version of jmte.
One of the limitation of the template mechanism above, is that the template cannot do anything about the plain text outside the template. So if I write,
${foreach ...}
${end}
See? There're two blank lines after each tag, and will be inserted into the result. That's not good practice for a programming code. So what I did, is that, you can change the above to:
${<foreach ...}
${<end}
The <
is like an option to the tag token. It will remove the directly following newline. It will work on any tag.
In this way, we can get a better formatted code.
Although the config library and the template engine
uses the same syntax for resolving data, ${key}
, they're of different implementations and have
different semantics.
In the config file, ${a.b.c}
means the value of a.b.c
following the path from the root of the config file.
However, in the template file, ${a.b.c}
simply binds to the value inside a map m
, which is
m.get("a").get("b").get("c")
. This is the core difference.
Sometimes (often) Greed needs to specify some data in the config file, like ${Problem.Name}
, for example, to specify the output file name. And we must prevent the config library to resolve this reference in its way. We achieve this by putting the value in quotation, that's why you'll see a lot of ""
in the default.conf
.
It's also possible to have named renderers in the template engine, in this format ${data;name_of_renderer(param)}
.
These renderers define custom functions to render the data, according to its param.
Available named renderers in Greed:
-
format
, accepts a string as input and a format string as params. It callsString.format
in Java directly and returns the result. -
zeroval
, no params, whose data must be a type (greed.model.Type), and it returns a string representing its zero value in the current language. -
string
is a generic string transformation renderer, the data is a String, and its params is also a string which is a list of actions to perform on the input, and they are concatenated with commas. The actions are applied one by one, in sequential order. The available actions are:-
lower
- to lower case -
upcasefirst
- uppercase the first letter and lowercase the rest -
unquote
- remove the surrounding"
in the string, if any -
abbr
- abbreviate the input, by transforming all its all-uppercase tokens to its first letter and then joining them together
-
-
category
: A special renderer for objects of typegreed.model.Contest
intended to help organize code folders:- If the given string contains
Topcoder open
orTCO
, the returned result isTCO
. - If the given string contains
TCHS
, the returned result isTCHS
. - If the given string name contains
TCCC
, the returned result isTCCC
- If the given string name contains
Single Round Match XXX
orSRM XXX
where XXX is a number, then it returnsSRM
. This behavior can be modified by using thesrm=X
parameter, whereX
is a interval length. For example: `Contest;category(srm=25) will do the following:-
SRM 597
,Single Round Match 575
andSingle Round Match 599
becomeSRM 575-599
. -
SRM 525.5
,SRM 530
andSRM 536
becomeSRM 525-549
.
-
- If the string doesn't match any of the mentioned patterns, the renderer returns
Other
.
- If the given string contains
-
parser
is only available for java and python language, whose data is of typegreed.model.Type
, and its param is a string. It returns a parsing expression in that language, which parses the param to its input type. Like in Java,${type;parser(numBeans)}
transforms toInteger.parseInt(numBeans)
if type is of integer. -
html
is intended to help in problem statement templates. If the input is of typeString
(speciallyString
values in example test cases), it will escape any HTML entities (e.g: Turns"
into"
). Most importantly, if the input is agreed.model.ParamValue
or agreed.model.Type
, it will format it for it to be displayed in HTML:
-
paramval;html
: Renders Param Value parameters - will always renderString[]
parameters in a single line. -
paramval;html("grid")
: Will render someString[]
parameters as if they were 2D grids. Using multiple lines. If all elements in theString[]
have the same length, it will assume it is a grid. -
type;html(lang)
: Renders the type name in languagelang
.lang
can be:cpp
,java
,python
,csharp
.
You can use these renderers to write your template and also in the configuration file. The string
renderer is especially useful
for things like changing the ContestName
to lowercase, or to its abbreviation.
There're also two advanced named renderers, which is used to strengthen the power of the template engine, you will be very likely not using them.
-
seq(params)
, is a named renderer inside template engine. It takes anything as input, and takes a sequence of expressions as params. It transform the input via a series of renderers, giving the engine the ability of sequential and nested operations. It does two things.- Resolve all the variables in the params expressions, starting with
$
and ending with one of the symbols in(),
.Resolve
means rendering using the engine. - Iterate the input with each expression, by first binding it to some random key
K
, then- If the exp is
#
, meaning no named renderer, just render${K}
- Otherwise it's a named renderer, render
${K;exp}
.
- If the exp is
- Resolve all the variables in the params expressions, starting with
-
reify
, takes a string input and render it using the engine. It's just rendering the input as a key, enabling the ability for some renderer to output a key, then reifying it to a value.
Here's a table for all the keys and their values with their available scopes.
Key Name | Value | Scope | Class/Type |
---|---|---|---|
Contest | The contest object | config + template | greed.model.Contest |
Problem | The current problem object | config + template | greed.model.Problem |
ClassName | The class name for the current problem | config + template | String |
Method | The method name | config + template | String |
Examples | The list of samples given | template | greed.model.Testcase |
NumOfExamples | The number of samples | template | String |
ReturnsArray | Whether the method returns an array | template | Boolean |
HasArray | Whether the method returns an array or one of the parameter is an array | template | Boolean |
ReturnsString | Whether the method returns a string | template | Boolean |
HasString | Similar to HasArray
|
template | Boolean |
CreateTime | A time tag when the code is created, to calc the score | template | Long |
CutBegin | The begin-cut mark for the current language | template | String |
CutEnd | The end-cut mark | template | String |
GeneratedFileName | The generated file name | afterFileGen |
String |
GeneratedFilePath | The generated file path | afterFileGen |
String |
Here's a list of examples which you can use in your template. They're all available in the previous table, but more specific and with concrete values. We use C++ as the current language.
Value Name | Example | Comment |
---|---|---|
Contest.Name |
SRM 257 |
Contest name |
Contest.Div |
1 |
Contest division number |
Problem.Name |
RabbitWorking |
Problem name |
Problem.Score |
1000 |
Problem score, in integer |
Problem.MemoryLimitMB |
256 |
The problem's memory limit in MB. Old TC problems have a 64 MB limit. Most but not all of recent problems will have 256. |
Problem.TimeLimitMillis |
2000 | The problem's time limit in milliseconds. Most but not all problems have a time limit of 2000 milliseconds. |
Problem.TimeLimitSeconds |
2.0 | A floating point variable equivalent to Problem.TimeLimitMillis / 1000.0 . |
ClassName |
StangeDictionary2 |
Class name |
Method.Name |
getProbabilities |
Method name |
Method.Params |
vector<string> words |
Method parameter list, splitted by ,
|
Method.ReturnType |
vector<int> |
Method return type, will be bound to type identifier according to current language |
Method.ReturnType;zeroval |
vector<int>() |
A special renderer for a default return value. |
TestCode |
Too long to show... | This is the default key where the template filetest and test bound to, and will be put in the source template |
A table of value names related to test samples.
Value Name | Comment |
---|---|
Examples |
Example object list, each of which is of type Testcase . Iterate over it using ${foreach Examples e} . |
e.Num |
the example number of e (a Testcase object above) |
e.Input |
A list of ParamValue represents the input, each for one parameter |
e.Output |
The output value of this example, let it be parVal below |
parVal.Param |
This is a Param object let it be p below |
p.Name |
The name of a parameter |
p.Index |
The index of a parameter (0-indexed) |
p.Type |
The type of a parameter, it is a type object(we call it t ) |
t.Primitive |
the primitive type of t , like String , int
|
t.Array |
Set to true if t represents an array |
t.RealNumer |
Set to true if the primitive type in t is double
|
t.String |
Set to true if the primitive type in t is String
|
t.LongInteger |
Set to true if the primitive type in t is long
|
parVal.Value |
the given value of this param |
parVal.ValueList |
The value list, if it's an array, can be iterated on via ${foreach}
|
NumOfExamples |
Number of example test cases. A workaround for the not-working ${Examples.length}
|
And a table of values related to problem statement.
Value Name | Comment |
---|---|
Problem.Description |
Returns a ProblemDescription object for the problem. In the following rows we will refer to it as desc
|
desc.Intro |
The problem introduction HTML |
desc.HasNotes |
True if the problem statement has a Notes section |
desc.Notes |
Returns a list of problem notes. Each note is a HTML string |
desc.Constraints |
Returns a list of constraints. |
e.Annotation |
If example e has an annotation contains HTML of the annotation. Else it is null |
desc.Modulo |
Greed tries to parse the statement, if it finds the pattern "Modulo NUMBER", it will store the NUMBER in the desc.Modulo value. Use ${if Problem.Description.Modulo} to find if this value exists |