Skip to content
Shiva Wu edited this page Nov 14, 2013 · 11 revisions

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.

Template Rendering

There're two templates in Greed, the source code template and the test code template.

We generate the code as follows:

  1. Generate test code, bind it to the ${TestCode} key in the same model.

  2. Use the source code, using the model with ${TestCode} binded in 1.

Template Engine

To fully enable the power of template, we use a lightweight template engine jmte. It's efficient, simple, and enough powerful.

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. Here for 2 reasons,

  1. Our version of jmte is 3.0, which is the newest version, and not all features are mentioned in the current documentation of jmte.

  2. To make the code more pretty, some slight changes are made to jmte. I will tell you what I did in the following sentences.

Template language

Very simple to use, here it comes!

Templates 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 key X 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 bind v to every value in values, v will be put in the model while in the scope in the .... A , is inserted after every ... block, except the last one.
  • ${key;custom(format)} - custom is a named renderer programmatically added in the engine, the value of key will be passed into the named renderer and return the rendering result, format is the parameter for the custom renderer. Currently, a 'string' utility renderer is binded, for transforming strings, see here.

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. The config values and templates use the same engine to render.

What I changed?

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.

Predefined Variables

Remember those predefined variables introduced in configuration page? Well, that's just a portion of them. Here's the full list. Those not listed in configuration page can only be used in the templates.

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
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 binded to type identifier according to current language
Method.ReturnType;ZeroValue vector<int>() A special renderer for a default return value. Make sure your code can be correctly compiled
TestCode Too long to show... The test code are generated first and binded here, in convenient for user to seperate the test code template from the source code template

These values are enough for you to generate your code template.

What? You wanna DIY your test code template? OK, OK, read on.

Value Name Comment
HasArray Set to true if any of the parameter or return type is an array
ReturnsArray Set to true if the return type is an array, you may need a function to print it to diff the result
RecordRuntime Set to true if the runtime record is turned on in the configuration
RecordScore Set to true if the score record is turned on in the configuration
CreateTime Set to the create system time of this template, used for calculating the score
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}

For a complete use-case, refer to the built-in templates like Template.cpp and GreedTest.cpp, with the greed.model package in the source code of Greed.

More words on the model and variable resolving

The model are also hierarchical, just like the config keys. Sounds familiar, huh? Better show you with examples.

${e.Output.Param.Type.Array} is rendered as follows:

  1. Looks for key e in the model, it's either a predefined variable, or a local variable in the foreach tag. If not found, a empty string will be used as the result
  2. If found, the value object r for e is obtained. Based on its type, do the following
  3. If r is a String, no key for Output, empty string!
  4. If r is another Map, goto 1 and repeat for key ReturnType
  5. Otherwise, see if object r has method called getOutput, or isOutput, then if it has a public field called Output, if so, use the return value or field value.

When the final value v are fetched for all hierarchical keys, if the value is not a string, A typed renderer will be looked up for rendering v. If not found, v.toString() is called.

These are not described in the documentation of jmte, in case you're interested.

Clone this wiki locally