- virtual_machine_t is a stack-based expression evaluator. There are several built-in operators as well as named- and unnamed- argument functions, as well as the capability of extending these functions within a given client.
- An expression is simply a sequence of elements, some of which can be expressions themselves. The virtual machine iterates through the expression sequence, pushing all the elements it finds onto the evaluation stack until it runs across an execute token. An execute token is any adobe::name_t whose first character is a period (
'.'
). When the evaluator finds this kind of token it is used as the name of the operator, and one or more arguments are popped off the stack successively for this operator. The evaluation of the arguments is handled by recursing to evaluate. There is no branching in the evaluator. The result of the operator is then pushed onto the stack and the evaluation continues down the expression sequence. Conditionals are handled with recursive evaluates; the machine always moves forward. The evaluator is very specifically not turing complete. It has no loops, no primitive recursion within the machine model, and it is not infinite.
Operators
- The following table describes the built-in operators available for use in the virtual machine. For each operation there is listed one or more required parameters that must be pushed onto the stack for the operation to succeed. The result of the operation is pushed onto the top of the stack. All values must meet the requirements for adobe::any_regular_t.
Unary Operation Name | Parameter | Result |
.not | boolean | logical not |
.unary_negate | number | unary negation |
Binary Operation Name | Parameters | Result |
.add | number_0 | number_1 | number_0 + number_1 |
.subtract | number_0 | number_1 | number_0 - number_1 |
.multiply | number_0 | number_1 | number_0 * number_1 |
.modulus | number_0 | number_1 | number_0 % number_1 |
.divide | number_0 | number_1 | number_0 / number_1 |
Predicate Operation Name | Parameters | Result |
.less | number_0 | number_1 | number_0 < number_1 |
.greater | number_0 | number_1 | number_0 > number_1 |
.less_equal | number_0 | number_1 | number_0 <= number_1 |
.greater_equal | number_0 | number_1 | number_0 >= number_1 |
.equal | value_0 | value_1 | value_0 == value_1 |
.not_equal | value_0 | value_1 | value_0 != value_1 |
.and_op | boolean | expression | boolean && expression [1] [3] |
.or_op | boolean | expression | boolean || expression [2] [3] |
Misc. Operation Name | Parameters | Result |
.array | number | number unnamed argument(s) | an array_t containing the top number elements in the evaluation stack |
.dictionary | number | number key/value pair(s) (named argument(s)) | a dictionary_t containing the top number key/value pairs in the evaluation stack |
.ifelse | boolean | expression_0 | expression_1 | evaluated expression_0 if boolean is true; evaluated expression_1 otherwise [4] |
.index | array | number | evaluated array[number] |
.index | dictionary | name | evaluated dictionary[name] |
.function | name | dictionary of expressions | result of calling function name with argument dictionary |
.function | name | array of expressions | result of calling function name with argument array |
.variable | name | evaluated value of name |
- Notes
- [1] expression is evaluated only if boolean is true.
- [2] expression is evaluated only if boolean is false.
- [3] expression must yield a boolean.
- [4] only the pertinent expression is evaluated.
Named Functions
- When looking up named functions in your client-side callback, the name of the function will be the adobe::name_t parameter of the callback, and any arguments to that function will be in the second parameter. You are required to return the value returned by your client-side function as a any_regular_t, which will be pushed onto the evaluation stack of the machine. Note that these do not have periods in their names, as they are not operations but rather the first parameter to the
.function
operator.
Unnamed Argument Functions | Arguments | Result |
contributing | A sequence of unnamed arguments | a dictionary_t outlining the values that contributed to this value [5] |
max | The largest of the evaluated numbers [6] |
min | The smallest of the evaluated numbers [6] |
round | Rounds the argument to the nearest whole number [5] |
typeof | Specifies the type of the element [5] |
Named Argument Functions | Argument Type | Argument Name | Argument Note | Result |
scale | number | m | Linear scale slope.
Default: 1 | Perform a linear scaling of x |
number | b | Linear scale y-intercept.
Default: 0 |
number | x | Value to scale.
Default: 0 |
- Notes
- [5] Only operates on the first element in the argument list.
- [6] All values in the argument list must be numbers.
Example
- The following is a pdf-formatted expression sequence for the expression
round(x<3 ? 2+9/5 : 7.8-2.94)
% pdf output
[
/x /.variable 3 /.less
[
2 9 5 /.divide /.add
]
[
7.800000000000000 2.940000000000000 /.subtract
]
/.ifelse 1 /.array /round /.function
]
% end pdf output
- The following is a pdf-formatted expression sequence for the expression
{name: @value, items: [4, "Hello"]}
% pdf output
[
/name /value
/items 4 (Hello) 2 /.array
2 /.dictionary
]
% end pdf output
Definition at line 67 of file virtual_machine.hpp.