Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Excerpt

MCS Software provides a formula language in used by various imports and exports throughout our suite of applications.  This formula language is intended to produce a single output value from available input values.  The language is not white-space, line-break, or case sensitive.  Using an informal BNF, the language can be described in the following way:

 

<formula> :: = <statement> [ <statement> [ <statement> ... ] ]

 

<statement> ::= 

RETURN <expression>  |

IF <expression> THEN <statement> [ ELSE <statement> ]   |

BEGIN <statement> [ <statement> [ <statement> ... ] ] END  |

WHILE <expression> <statement>  |

VAR <variablename> [ = <expression> ]  |

SET <variablename> = <expression>  |

TRY <statement> CATCH <statement> |

THROW <expression> |

FOREACH <variablename> IN <expression> <statement> |

BREAK |

TRACE <expression> |

GLOBAL <variablename> [ = <expression> ]

 

<expression> :== <literal>  |

<constant>  |

<variablename>  |

<fieldname> |

<functionname> ( <expression> [ , <expression> [ , <expresion> ... ] ]

<expression> <binary_operator> <expression>  |  

<unary_operator> <expression>  |

( <expression> ) 

 

<literal> :== [ - ] [ 0-9*] [ . 0-9* ]

"string literal"  |

true  |

false  |

null

<constant> := @@identifierName

<variablename> :== @identifierName

<fieldname> :== [ fieldName ] 

<functionname> :== one of the following functions

function namemeaningparameter1parameter2parameter3parameter4
IIFConditional If, if parameter1 is true then returns parameter2 otherwise returns parameter3conditionexpression to return if condition is trueexpression to return if condition is not true 
Coalescereturns the first non-null parameterfirst expression to check if not-nullsecond expression to check if not-null(optional) 3rd expression to check(optional) 4th expression to check (you can have an unlimited number of parameters)
NullIfreturns NULL if parameter1 equals parameter 2, otherwise it returns parameter1value to return if not equal to parameter2value to test parameter1 against  
NullIfErrorreturns NULL if the evaluation of parameter1 throws an exception, otherwise it returns parameter 1expression to evaluate   
Datereturns a new date value from the supplied Gregorian calendar componentsyearmonthday 
Nowreturns the date and time right at the time the formula evaluation began (this value does not change when called multiple times with a given formula evaluation context, such that if used on an export all rows would have the same value)    
AddDaysreturns the result of adding a number of days to a datestarting datenumber of days to add  
AddMonthsreturns the result of adding a number of months to a datestarting datenumber of months to add  
AddYearsreturns the result of adding a number of years to a datestarting datenumber of years to add  
Dayreturns the day of the month of a given datedate   
Monthreturns the calendar month of a given datedate   
Yearreturns the calendar year of a given datedate   
DayOfWeekreturns the day of the week (sunday = 0, monday = 1, ... saturday = 6 ) of a given datedate   
ParseDateconverts a string to a datestring value to parse(optional) the expected format of the string. For example MM/dd/yyyy  
Lenreturns the length of a string; or, the number of elements in a list/arraystring value or array value   
Leftreturns a portion of a string starting from the leftstring valuemaximum number of characters to return  
Rightreturns a portion of a string starting from the rightstring valuemaximum number of characters to return  
Substringreturns a portion of a string starting at a given position (this function will error if you specify a start and/or length beyond the range of the string)string valuethe starting index (beginning with 0)(optional) the number of characters to return 
Replacereturns a the result of a string search-and-replace operation (case-sensitive)string value to searchsubstring to search for within parameter1string value with which to replace any occurrences of parameter2 
IndexOfreturns the first occurrence of a search within a string (-1 means not found, >= 0 means the index within the string that the match was found)string value to searchsubstring to search for(optional) the starting position (beginning with 0) to begin searching.(optional)true for case-sensitive, false for case-insensitive
StartsWithreturns true if a string starts with a given substring, false otherwisestring value to checksubstring to search for(optional) true for case-sensitive, false for case-insensitive 
EndsWithreturns true if a string ends with a given substring, false otherwisestring value to checksubstring to search for(optional) true for case-sensitive, false for case-insensitive 
StringComparereturns -1 if the parameter1 is alphabetically less than parameter2, 0 if they are equal, and 1 if parameter2 is greater than parameter1first string to comparesecond string to compare(optional) true for case-sensitive, false for case-insensitive 
ToUpperreturns the result of converting any lower case letters in parameter1 to upper-case lettersstring value   
ToLowerreturns the result of converting any upper case letters in parameter1 to lower

...

-case lettersstring value   
Trimreturns the result of removing any leading or trailing white-space characters from parameter1string value   
PadLeftreturns the specified string padded to the left to the specified length if the string is less than that lengthstring valueminimum length to pad to(optional)character to use for padding 
PadRightreturns the specified string padded to the right to the specified length if the string is less than that lengthstring valueminimum length to pad to(optional)character to use for padding 
MatchRegexreturns whether or not the specified string matches the supplied regular expressionstring test valueregular expression (ECMA script)(optional) true for case-insensitive, false for case-sensitive 
ReplaceRegexreturns the result of a regular expression replacementstring valueregular expression match string (ECMA script)regular expression replacement string(optional) true for case-insensitive, false for case-sensitive
ParseFirstNamereturns the first name component of the supplied full namefull name to parse   
ParseLastNamereturns the last name component of the supplied full namefull name to parse   
ParseMiddleNamereturns the middle name component of the supplied full namefull name to parse   
ParseSuffixreturns the suffix component of the supplied full namefull name to parse   
Formatreturns the result of formatting zero or more supplied values into a string using a standard .net formatting string. Parameter1 is returns with { n } replaced by value-n, and { n : format } replaced by value-n formatted by the specified format. For example Format("{0} + {1:0.00} = {2:0.0}", 1, 2, 3) would return "1 + 2.00 = 3.0".net style format string(optional) value 0 to apply to the format string(optional) value 1 to apply to the format string(optional) value 2 to apply to the format string. You can supply an unlimited number of value
Roundreturns a numeric value rounded to a given number of decimal places. Midpoints are rounded away from 0 (e.g. 2.5 rounds to 3)numeric value to round(optional) number of decimal places to round to (0 is the default)  
Truncatereturns the integer portion of a number, discarding any fractional amounts (can be thought of as rounding towards 0)numeric value   
Ceilingreturns a numeric value rounded up to the first integer greater than or equal to it (can be thought of as rounding towards positive infinite)numeric value   
Floorreturns a numeric value rounded down to the first integer less than or equal to it (can be thought of as rounding towards negative infinite)numeric value   
Fracreturns the fractional portion of a numbernumeric value   
Absreturns the absolute value of a numbernumeric value   
GetPropertygets the specified property of an objectobject valuestring property name  
GetPropertyNamesgets an array of all of the properties in an objectobject value   
HasPropertygets whether or not the specified property exists in an objectobject valuestring property name  
GetListItemgets the specified array/list itemarray value   
CurrentRecordreturns the current field values wrapped up as an object    

 

<binary_operator> :== one of the following operators

operatormeaning
+if the left-hand operand is a string, then string concatenation, otherwise numeric addition
-subtraction
*multiplication
/division
\integer division
%modulus division ( the remainder after integer division)
|bit-wise OR
&bit-wise AND
^bit-wise XOR
ORlogical OR
ANDlogical AND
XORlogical XOR
=equals
<>not equal
>greater-than
>=greater-than or equal
<less-than
<=less-than or equal

<unary_operator> :== one of the following operators

operatormeaning
-negative
Notlogical NOT
~bit-wise NOT

 

Comments

Comments may be added anywhere in within a formula body using C/C++ style comment notations

Code Block
languagenone
VAR @A = 3  //Everything after the two slashes on this line is considered a comment and is not executed
RETURN /*everything between the slash-stars is a comment and not executed*/ "Hello World"
 

 

Execution

Each statement within a formula is executed until a RETURN statement is encountered.  The expression supplied to the first executed RETURN statement is the result of the formula.  If no RETURN statement is executed, the result of the formula is NULL.  Each statement type is described below:

RETURN <expression>

Stops execution of the formula and returns <expression> as the result

For example:

Code Block
languagenone
RETURN "hello world"

 

IF <expression> THEN <statement1> [ ELSE <statement2> ]

if <expression> is true then execute statement 1.  If the optional ELSE portion is present, then statement2 is executed if <expression> is not true

For example:

 

Code Block
languagenone
IF @A > 4 THEN
   RETURN true;
ELSE
   RETURN false;

 

 

BEGIN <statement> [ <statement> [ <statement> ... ] ] END

Combines multiple statements into a single statement.  This is useful if you need a conditional execution of more than one statement.

For example:

Code Block
IF @A > 4 THEN
   BEGIN
      IF @B < 3 THEN
          RETURN "hello"
      IF @B < 5 THEN
          RETURN "world"
   END
ELSE
   RETURN "hi"
 
 

 

WHILE <expression> <statement>

Executes a statement in a pre-test loop.  If <expression> is true, then statement is executed and the test repeated until <expression> returns false

For example:

Code Block
languagenone
WHILE @A > 10
   SET @A = @A - 3

 

VAR <variablename> [ = <expression> ]

Declares a variable and optionally initializes it to a value

For example:

Code Block
VAR @A = 3

 

SET <variablename> = <expression>

Sets a previously declared variable to a new value

For example:

Code Block
SET @A = @A + 4

 

TRY <statement1> CATCH <statement2>

Execute statement1.  If an error occurs while executing statement1, statement1 is immediately aborted and statement2 is executed

For example:

Code Block
VAR @A = 0
TRY
   RETURN 4 / @A
CATCH
   RETURN NULL

 

THROW <expression>

Raises an error / exception

For example:

Code Block
IF @A = 0 THEN
   THROW "Unexpected value"
ELSE
   RETURN @A
 
FOREACH <variable> IN <expression> <statement>

Iterates through an array and executes a statement for each item in the array

For example:

Code Block
VAR @CountNoIncome = 0
FOREACH @Student in [Students] BEGIN
	IF GetProperty(@Student, 'NoIncome') = True
   		SET @CountNoIncome = @CountNoIncome + 1
END
RETURN @CountNoIncome
 

 

BREAK

Breaks out of the current innermost WHILE or FOREACH loop.   

For example:

Code Block
VAR @NoIncomeExists = FALSE
FOREACH @Student in [Students] BEGIN
	IF GetProperty(@Student, "NoIncome") = True BEGIN
   		SET @NoIncomeExists = TRUE
		BREAK	//break out of FOREACH and stop looking at the rest of the students
	END
END
IF @NoIncomeExists BEGIN
END
 
TRACE <expression>

Writes the value of <expression> to the trace log.  This is useful for debugging a formula.  When using the 'Test' button to test a formula, the trace log is displayed along with the results.  Trace events are logged to log4net as DEBUG events for all formula evaluations, whether test or production.

For example:

Code Block
VAR @NoIncomeExists = FALSE
FOREACH @Student in [Students] BEGIN
	TRACE Format("Checking student {0} for NoIncome flag", GetProperty(@Student, "Fullname"))
	IF GetProperty(@Student, "NoIncome") = True
   		SET @NoIncomeExists = TRUE
END

RETURN @NoIncomeExists
 
GLOBAL <variablename> [ = <expression> ]

Declares a global variable and optionally initializes it to a value.  Global variable persist their values within the same formula body over multiple records.  They are not shared between different formulas.  The initial value is only used to initialize the global variable.  It does not reset the value every time the statement executes.  Use SET to change or reset the value of a global variable.

For example (running summary operations):

Code Block
GLOBAL @RowCount = 0 //This does not get reset to 0 every time the formula executes, it only initializes the value to 0 the first time
SET @RowCount = @RowCount + 1
RETURN @RowCount //returns the row number of the record within an export

Or (accessing previous records):

Code Block
GLOBAL @PreviousStudent = NULL
VAR @Result
IF @PreviousStudent = NULL
	SET @Result = NULL
ELSE
	SET @Result = GetProperty(@PreviousStudent, "Fullname")
SET @PreviousStudent = CurrentRecord()  //CurrentRecord() takes the current field values and places them in a object-value result with properties matching the field names
RETURN @Result	//returns the Fullname field value of the previous student record

...