Skip to content
This repository was archived by the owner on Dec 20, 2019. It is now read-only.

Expressions

Manuel Freire edited this page Jul 24, 2014 · 11 revisions

Expressions allow values to be computed during game-play.

Expressions in the schema

(that is: from the point of view of JSON, expressions are simple strings. This makes them more compact and offloads all their internal complexity to the parsing implementation, avoiding many intermediate serialization objects.)

Example: calculating the value of a "gold" variable + 1

  " ( + $gold i1 )"

Expressions in the code

Expressions are built from from variables, literals and operations (= sub-expressions). Each of these abstractions can be found in their respective classes: Expression, VariableRef, Literal and Operation.

A sample expression (pseudocode), which could be used to calculate whether a level is complete or not could be:

   ( 100 < ( ( levelScore * 10 ) + ( bonusPoints * 2 ) ) )

Here, 100, 10 and 2 are integer literals; levelScore and bonusPoints are variables, and each parenthesis group, including the outer parenthesis, is an expression. Notice that each expression contains exactly one operator.

Internal syntax

Internally, this is currently stated using a lisp-like, type-prefixed syntax:

   ( lt i100 ( + ( * $levelScore i10 ) ( * $bonusPoints i2 ) ) )

although this syntax is strictly for ease of parsing, since once the editor is complete expressions will never need to be edited by hand. lt represents "less than", and is equivalent to a mathematical <. A full list of supported operations can be found in the OperationsFactory.

Type-safety is ensured by using prefixes to indicate the type of all literals. The types of expressions depend on their operations, and we explicitly allow certain kinds of type-casts (for example, ( + i1 f2.1416 ) is equivalent to f3.1416 ).

The following prefixes are defined: i for integer (eg.: i123), f for float (eg.: i3.1416), b for boolean (either bfalse or btrue), and s for string. Strings must be quoted and can contain anything except for unescaped quotes; for instance, s"printf(\"hello world\");" is a valid string, but shello or s"hi"there" are considered syntax errors.

Variables carry a $ before the name of the variable. Therefore, $a is a variable named a. Variable names are not typed - they must be looked up in a VarsContext to determine their actual types and values.

Internal expression cheat sheet

types syntax
boolean btrue bfalse
integer i42 i-123
float f42 f42.0 f-1E-2
string s"hi there" s"\""
  • Variables must not contain spaces, and must use the $ prefix
  • Operators must be separated by (at least) 1 space from operands. The operation in an expression is always the first word after the opening parenthesis: ( operation operand... ).

Using expressions

To build an expression from a string representation (via parsing), use:

   OperationFactory of = new OperationFactory();
   Expression expression = null;
   try {
       expression = Parser.parse(
          "( lt i100 ( + ( * $levelScore i10 ) ( * $bonusPoints i2 ) ) )", of);
   } catch (IllegalArgumentException iae) {
       // if the iae is thrown, the expression was syntactically not valid
   } 

To build the same expression programmatically, use:

   OperatorFactory of = new OperatorFactory();
   Operation mul1 = of.createOperation("*");
   mul1.getChildren().add(new VariableRef("levelScore"));
   mul1.getChildren().add(new Literal(10));
   Operation mul2 = of.createOperation("*");
   mul2.getChildren().add(new VariableRef("bonusPoints"));
   mul2.getChildren().add(new Literal(2));
   Operation add = of.createOpertion("+");
   add.getChildren().add(mul1);
   add.getChildren().add(mul2);
   Operation lt = of.createOperation("lt");
   lt.getChildren().add(new Literal(100));
   lt.getChildren().add(add);
   Expression expression = lt;

To get a string representation from an expression, use:

   String s = expression.toString();

Evaluation & exceptions

You can evaluate an expression for a given VarsContext by using:

   Object o = null;
   try {
       o = expression.evaluate(varsContext);
   } catch (ExpressionEvaluationException eee) {
       // any type of error during evaluation; 
       // this includes arithmetic errors, unresolved vars, and type errors
   }

Adding new operations

To add a new operation, have a look at the operators package. You will need to write a new class in that package that extends Operation, and register this new class (to make it available for use during parsing and programmatic expression construction) in the OperatorFactory.

Clone this wiki locally