#-----------------------------------------------------------------------------* # # @file gtl_expressions.galgas # # @section desc File description # # expressions in GTL. # # @section copyright Copyright # # Goil OIL compiler, part of Trampoline RTOS # # Trampoline is copyright (c) CNRS, University of Nantes, # Ecole Centrale de Nantes # Trampoline is protected by the French intellectual property law. # # This software is distributed under the GNU Public Licence V2. # Check the LICENSE file in the root directory of Trampoline # # $Date$ # $Rev$ # $Author$ # $URL$ # #-----------------------------------------------------------------------------* #-----------------------------------------------------------------------------* # Wrappers on @gtlStruct because a gtlStruct is used to store the variables #-----------------------------------------------------------------------------* override getter @gtlStruct overrideMap -> @gtlStruct mapOverriden { mapOverriden = .new { !where !emptylstring() !@gtlVarMap.mapWithMapToOverride{!value} } } #-----------------------------------------------------------------------------* override getter @gtlStruct overriddenMap -> @gtlStruct overriddenMap { overriddenMap = .new{ !where !emptylstring() ![value overriddenMap] } } #-----------------------------------------------------------------------------* func wantGtlStruct ?@gtlData inData ->@gtlData outData { cast inData case == @gtlStruct inDataStruct: outData = inDataStruct else outData = @gtlStruct.new { !inData !emptylstring() !.emptyMap } end } #-----------------------------------------------------------------------------* func wantGtlMap ?@gtlData inData ->@gtlData outData { cast inData case == @gtlMap inDataMap: outData = inDataMap else outData = @gtlMap.new { !inData !emptylstring() !.emptyMap } end } #-----------------------------------------------------------------------------* func wantGtlList ?@gtlData inData ->@gtlData outData { cast inData case == @gtlList inDataList: outData = inDataList else outData = @gtlList.new { !inData !emptylstring() !.emptyList } end } #=============================================================================* # A @gtlVarItem is a part of a variable path. # For instance A::B["e"]::C::D[3] is a path. A is a struct, B is a field of # A and is a map, ["e"] is the element of the map with key "e". This element # is a struct with field C which is itself a struct with field D which is a # list and we reference the element at index 3. #-----------------------------------------------------------------------------* abstract class @gtlVarItem {} abstract getter @gtlVarItem stringPath ?let @gtlContext exeContext ?let @gtlData vars ?let @library lib -> @string abstract getter @gtlVarItem location -> @location #-----------------------------------------------------------------------------* # abstract method to set a data in a context #-----------------------------------------------------------------------------* abstract method @gtlVarItem setInContext ?let @gtlContext exeContext ?! @gtlData context ?let @gtlData vars ?let @library lib ?let @gtlVarPath path ?let @gtlData newData #-----------------------------------------------------------------------------* # abstact getter to get a data in a context #-----------------------------------------------------------------------------* abstract getter @gtlVarItem getInContext ?let @gtlContext exeContext ?let @gtlData context ?let @gtlData vars ?let @library lib ?let @gtlVarPath path -> @gtlData #-----------------------------------------------------------------------------* # abstact getter to test the existence of a field in a context #-----------------------------------------------------------------------------* abstract getter @gtlVarItem existsInContext ?let @gtlContext exeContext ?let @gtlData context ?let @gtlData vars ?let @library lib ?let @gtlVarPath path -> @bool #-----------------------------------------------------------------------------* # abstact method to remove field in a context #-----------------------------------------------------------------------------* abstract method @gtlVarItem deleteInContext ?let @gtlContext exeContext ?! @gtlData context ?let @gtlData vars ?let @library lib ?let @gtlVarPath path #=============================================================================* # Scalar struct field, ie A or C in the example above #-----------------------------------------------------------------------------* class @gtlVarItemField : @gtlVarItem { @lstring field } override getter @gtlVarItemField location -> @location loc { loc = field } override getter @gtlVarItemField stringPath ?let @gtlContext unused exeContext ?let @gtlData unused vars ?let @library unused lib -> @string result { result = field } getter @gtlVarItemField lstringPath -> @lstring result { result = field } #-----------------------------------------------------------------------------* # method to set a data in a struct context #-----------------------------------------------------------------------------* override method @gtlVarItemField setInContext ?let @gtlContext exeContext ?! @gtlData context ?let @gtlData vars ?let @library lib ?let @gtlVarPath path ?let @gtlData newData { context = wantGtlStruct(!context) if [path length] == 0 then [!?context setStructField !field !newData] else [context structField !field ?@gtlData data ?*] [[path itemAtIndex !0] setInContext !exeContext !?data !vars !lib ![path subListFromIndex !1] !newData ] [!?context setStructField !field !data] end } #-----------------------------------------------------------------------------* # getter to get a data in a struct context #-----------------------------------------------------------------------------* override getter @gtlVarItemField getInContext ?let @gtlContext exeContext ?let @gtlData context ?let @gtlData vars ?let @library lib ?let @gtlVarPath path -> @gtlData result { [context structField !field ?let @gtlData data ?let @bool found] if [path length] == 0 then if found then result = data else error data : "Variable or field does not exist" : result end else result = [[path itemAtIndex !0] getInContext !exeContext !data !vars !lib ![path subListFromIndex !1] ] end } #-----------------------------------------------------------------------------* # getter to get a data in a struct context #-----------------------------------------------------------------------------* override getter @gtlVarItemField existsInContext ?let @gtlContext exeContext ?let @gtlData context ?let @gtlData vars ?let @library lib ?let @gtlVarPath path -> @bool result { if [context hasStructField !field] then if [path length] == 0 then result = true else [context structField !field ?let @gtlData subContext ?*] result = [[path itemAtIndex !0] existsInContext !exeContext !subContext !vars !lib ![path subListFromIndex !1] ] end else result = false end } #-----------------------------------------------------------------------------* # method to delete a data in a struct context #-----------------------------------------------------------------------------* override method @gtlVarItemField deleteInContext ?let @gtlContext exeContext ?! @gtlData context ?let @gtlData vars ?let @library lib ?let @gtlVarPath path { if [context hasStructField !field] then if [path length] == 0 then [!?context deleteStructField !field] else [context structField !field ?@gtlData data ?*] [[path itemAtIndex !0] deleteInContext !exeContext !?data !vars !lib ![path subListFromIndex !1] ] [!?context setStructField !field !data] end end } #=============================================================================* # Collection field, ie B or D in the example above #-----------------------------------------------------------------------------* class @gtlVarItemCollection : @gtlVarItemField { @gtlExpression key } override getter @gtlVarItemCollection stringPath ?let @gtlContext exeContext ?let @gtlData vars ?let @library lib -> @string result { result = [field string] + "[" let @gtlData keyValue = [key eval !exeContext !vars !lib] cast keyValue case == @gtlString keyString: result += "\"" + keyString + "\"" case == @gtlInt keyInt: result += keyInt end result += "]" } #-----------------------------------------------------------------------------* # method to set a data in a list or map context #-----------------------------------------------------------------------------* override method @gtlVarItemCollection setInContext ?let @gtlContext exeContext ?! @gtlData context ?let @gtlData vars ?let @library lib ?let @gtlVarPath path ?let @gtlData newData { cast [key eval !exeContext !vars !lib] case == @gtlString keyString: context = wantGtlStruct(!context) [context structField !field ?@gtlData data ?*] data = wantGtlMap(!data) if [path length] == 0 then [!?data setMapItem !keyString !newData] else [data mapItem !keyString ?@gtlData subContext] [[path itemAtIndex !0] setInContext !exeContext !?subContext !vars !lib ![path subListFromIndex !1] !newData ] [!?data setMapItem !keyString !subContext] end [!?context setStructField !field !data] case == @gtlInt keyInt: context = wantGtlStruct(!context) [context structField !field ?@gtlData data ?*] data = wantGtlList(!data) if [path length] == 0 then [!?data setItemAtIndex !newData !keyInt] else [data itemAtIndex ?@gtlData subContext !keyInt] [[path itemAtIndex !0] setInContext !exeContext !?subContext !vars !lib ![path subListFromIndex !1] !newData ] [!?data setItemAtIndex !subContext !keyInt] end [!?context setStructField !field !data] else error key : "string ot int expected" end } #-----------------------------------------------------------------------------* # getter to get a data in a list or map context #-----------------------------------------------------------------------------* override getter @gtlVarItemCollection getInContext ?let @gtlContext exeContext ?let @gtlData context ?let @gtlData vars ?let @library lib ?let @gtlVarPath path -> @gtlData result { [context structField !field ?let @gtlData collection ?*] cast [key eval !exeContext !vars !lib] case == @gtlString keyString: if [path length] == 0 then [collection mapItem !keyString ?result] else [collection mapItem !keyString ?let @gtlData subContext] result = [[path itemAtIndex !0] getInContext !exeContext !subContext !vars !lib ![path subListFromIndex !1] ] end case == @gtlInt keyInt: if [path length] == 0 then [collection itemAtIndex ?result !keyInt] else [collection itemAtIndex ?let @gtlData subContext !keyInt] result = [[path itemAtIndex !0] getInContext !exeContext !subContext !vars !lib ![path subListFromIndex !1] ] end else error key : "string ot int expected" : result end } #-----------------------------------------------------------------------------* # getter to test the existence of a data in a list or map context #-----------------------------------------------------------------------------* override getter @gtlVarItemCollection existsInContext ?let @gtlContext exeContext ?let @gtlData context ?let @gtlData vars ?let @library lib ?let @gtlVarPath path ->@bool result { if [context hasStructField !field] then [context structField !field ?let @gtlData collection ?*] cast [key eval !exeContext !vars !lib] case == @gtlString keyString: if [path length] == 0 then result = [collection hasMapItem !keyString] else if [collection hasMapItem !keyString] then [collection mapItem !keyString ?let @gtlData subContext] result = [[path itemAtIndex !0] existsInContext !exeContext !subContext !vars !lib ![path subListFromIndex !1] ] else result = false end end case == @gtlInt keyInt: if [path length] == 0 then result = [collection hasItemAtIndex !keyInt] else if [collection hasItemAtIndex !keyInt] then [collection itemAtIndex ?let @gtlData subContext !keyInt] result = [[path itemAtIndex !0] existsInContext !exeContext !subContext !vars !lib ![path subListFromIndex !1] ] else result = false end end else error key : "string ot int expected" : result end else result = false end } #-----------------------------------------------------------------------------* # method to set a data in a list or map context #-----------------------------------------------------------------------------* override method @gtlVarItemCollection deleteInContext ?let @gtlContext exeContext ?! @gtlData context ?let @gtlData vars ?let @library lib ?let @gtlVarPath path { cast [key eval !exeContext !vars !lib] case == @gtlString keyString: if [context hasStructField !field] then [context structField !field ?@gtlData data ?*] if [path length] == 0 then if [data hasMapItem !keyString] then [!?data deleteMapItem !keyString] end else [data mapItem !keyString ?@gtlData subContext] [[path itemAtIndex !0] deleteInContext !exeContext !?subContext !vars !lib ![path subListFromIndex !1] ] [!?data setMapItem !keyString !subContext] end [!?context setStructField !field !data] end case == @gtlInt keyInt: if [context hasStructField !field] then [context structField !field ?@gtlData data ?*] if [path length] == 0 then if [data hasItemAtIndex !keyInt] then [!?data deleteItemAtIndex !keyInt] end else [data itemAtIndex ?@gtlData subContext !keyInt] [[path itemAtIndex !0] deleteInContext !exeContext !?subContext !vars !lib ![path subListFromIndex !1] ] [!?data setItemAtIndex !subContext !keyInt] end [!?context setStructField !field !data] end else error key : "string ot int expected" end } #=============================================================================* # Subcollection, # in a["key"][3] a["key"] is a @gtlVarItemCollection and [3] is # a @gtlVarItemSubCollection #-----------------------------------------------------------------------------* class @gtlVarItemSubCollection : @gtlVarItem { @location subCollectionlocation @gtlExpression key } override getter @gtlVarItemSubCollection location -> @location loc { loc = subCollectionlocation } override getter @gtlVarItemSubCollection stringPath ?let @gtlContext exeContext ?let @gtlData vars ?let @library lib -> @string result { result = "[" let @gtlData keyValue = [key eval !exeContext !vars !lib] cast keyValue case == @gtlString keyString: result += "\"" + keyString + "\"" case == @gtlInt keyInt: result += keyInt end result += "]" } #-----------------------------------------------------------------------------* # method to set a data in a list or map subcontext #-----------------------------------------------------------------------------* override method @gtlVarItemSubCollection setInContext ?let @gtlContext exeContext ?! @gtlData context ?let @gtlData vars ?let @library lib ?let @gtlVarPath path ?let @gtlData newData { cast [key eval !exeContext !vars !lib] case == @gtlString keyString: context = wantGtlMap(!context) if [path length] == 0 then [!?context setMapItem !keyString !newData] else [context mapItem !keyString ?@gtlData subContext] [[path itemAtIndex !0] setInContext !exeContext !?subContext !vars !lib ![path subListFromIndex !1] !newData ] [!?context setMapItem !keyString !subContext] end case == @gtlInt keyInt: context = wantGtlList(!context) if [path length] == 0 then [!?context setItemAtIndex !newData !keyInt] else [context itemAtIndex ?@gtlData subContext !keyInt] [[path itemAtIndex !0] setInContext !exeContext !?subContext !vars !lib ![path subListFromIndex !1] !newData ] [!?context setItemAtIndex !subContext !keyInt] end else error key : "string ot int expected" end } #-----------------------------------------------------------------------------* # getter to get a data in a list or map context #-----------------------------------------------------------------------------* override getter @gtlVarItemSubCollection getInContext ?let @gtlContext exeContext ?let @gtlData context ?let @gtlData vars ?let @library lib ?let @gtlVarPath path -> @gtlData result { cast [key eval !exeContext !vars !lib] case == @gtlString keyString: if [path length] == 0 then [context mapItem !keyString ?result] else [context mapItem !keyString ?let @gtlData subContext] result = [[path itemAtIndex !0] getInContext !exeContext !subContext !vars !lib ![path subListFromIndex !1] ] end case == @gtlInt keyInt: if [path length] == 0 then [context itemAtIndex ?result !keyInt] else [context itemAtIndex ?let @gtlData subContext !keyInt] result = [[path itemAtIndex !0] getInContext !exeContext !subContext !vars !lib ![path subListFromIndex !1] ] end else error key : "string ot int expected" : result end } #-----------------------------------------------------------------------------* # getter to test the existence of a data in a list or map subcontext #-----------------------------------------------------------------------------* override getter @gtlVarItemSubCollection existsInContext ?let @gtlContext exeContext ?let @gtlData context ?let @gtlData vars ?let @library lib ?let @gtlVarPath path ->@bool result { cast [key eval !exeContext !vars !lib] case == @gtlString keyString: if [path length] == 0 then result = [context hasMapItem !keyString] else if [context hasMapItem !keyString] then [context mapItem !keyString ?let @gtlData subContext] result = [[path itemAtIndex !0] existsInContext !exeContext !subContext !vars !lib ![path subListFromIndex !1] ] else result = false end end case == @gtlInt keyInt: if [path length] == 0 then result = [context hasItemAtIndex !keyInt] else if [context hasItemAtIndex !keyInt] then [context itemAtIndex ?let @gtlData subContext !keyInt] result = [[path itemAtIndex !0] existsInContext !exeContext !subContext !vars !lib ![path subListFromIndex !1] ] else result = false end end else error key : "string ot int expected" : result end } #-----------------------------------------------------------------------------* # method to set a data in a list or map subcontext #-----------------------------------------------------------------------------* override method @gtlVarItemSubCollection deleteInContext ?let @gtlContext exeContext ?! @gtlData context ?let @gtlData vars ?let @library lib ?let @gtlVarPath path { cast [key eval !exeContext !vars !lib] case == @gtlString keyString: if [context hasMapItem !keyString] then if [path length] == 0 then [!?context deleteMapItem !keyString] else [context mapItem !keyString ?@gtlData subContext] [[path itemAtIndex !0] deleteInContext !exeContext !?subContext !vars !lib ![path subListFromIndex !1] ] [!?context setMapItem !keyString !subContext] end end case == @gtlInt keyInt: if [context hasItemAtIndex !keyInt] then if [path length] == 0 then [!?context deleteItemAtIndex !keyInt] else [context itemAtIndex ?@gtlData subContext !keyInt] [[path itemAtIndex !0] deleteInContext !exeContext !?subContext !vars !lib ![path subListFromIndex !1] ] [!?context setItemAtIndex !subContext !keyInt] end end else error key : "string ot int expected" end } #=============================================================================* # A variable path is a list of variable items #-----------------------------------------------------------------------------* list @gtlVarPath { @gtlVarItem item } #-----------------------------------------------------------------------------* # variable path as functionName #-----------------------------------------------------------------------------* getter @gtlVarPath pathAsFunctionName -> @lstring result { let @gtlVarItem firstItem = [self itemAtIndex !0] cast firstItem case >= @gtlVarItemField namedField : result = [namedField field] else error firstItem : "INTERNAL ERROR. A @gtlVarPath should not begin with a subcollection" : result end } #-----------------------------------------------------------------------------* # variable path as string #-----------------------------------------------------------------------------* getter @gtlVarPath stringPath ?let @gtlContext exeContext ?let @gtlData vars ?let @library lib -> @string result { result = "" for (item) in self do result += [item stringPath !exeContext !vars !lib] between result += "::" end } #-----------------------------------------------------------------------------* # Set a data in a path #-----------------------------------------------------------------------------* method @gtlVarPath set ?let @gtlContext exeContext ?!@gtlData vars ?let @library lib ?let @gtlData data { if [self length] > 0 then let @gtlVarItem item = [self itemAtIndex !0] cast item case >= @gtlVarItemField itemField: [itemField setInContext !exeContext !?vars !vars !lib ![self subListFromIndex !1] !data ] else error item : "INTERNAL ERROR. A @gtlVarPath may not begin with a subcollection" end else error .here : "INTERNAL ERROR. A @gtlVarPath should not be an empty list" end } #-----------------------------------------------------------------------------* # Get a data in a path #-----------------------------------------------------------------------------* getter @gtlVarPath get ?let @gtlContext exeContext ?let @gtlData context ?let @library lib -> @gtlData variableValue { if [self length] > 0 then let @gtlVarItem item = [self itemAtIndex !0] variableValue = [item getInContext !exeContext !context !context !lib ![self subListFromIndex !1]] else error .here : "INTERNAL ERROR. A @gtlVarPath should not be an empty list" : variableValue end } #-----------------------------------------------------------------------------* # test the existence of a path #-----------------------------------------------------------------------------* getter @gtlVarPath exists ?let @gtlContext exeContext ?let @gtlData context ?let @library lib -> @bool result { if [self length] > 0 then let @gtlVarItem item = [self itemAtIndex !0] result = [item existsInContext !exeContext !context !context !lib ![self subListFromIndex !1]] else error .here : "INTERNAL ERROR. A @gtlVarPath should not be an empty list" : result end } #-----------------------------------------------------------------------------* # Set a data in a path #-----------------------------------------------------------------------------* method @gtlVarPath delete ?let @gtlContext exeContext ?!@gtlData vars ?let @library lib { if [self length] > 0 then let @gtlVarItem item = [self itemAtIndex !0] [item deleteInContext !exeContext !?vars !vars !lib ![self subListFromIndex !1] ] else error .here : "INTERNAL ERROR. A @gtlVarPath should not be an empty list" end } #-----------------------------------------------------------------------------* # location of a path is the location of the last element #-----------------------------------------------------------------------------* getter @gtlVarPath location -> @location where { [self last ?let @gtlVarItem lastOne] where = [lastOne location] } #=============================================================================* # abstract classes for an expression #-----------------------------------------------------------------------------* abstract class @gtlExpression { @location where } getter @gtlExpression location -> @location result { result = where } abstract class @gtlUnaryExpression : @gtlExpression { @gtlExpression son } abstract class @gtlBinaryExpression : @gtlExpression { @gtlExpression lSon @gtlExpression rSon } abstract getter @gtlExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData #=============================================================================* # Expression list #-----------------------------------------------------------------------------* list @gtlExpressionList { @gtlExpression expression } #=============================================================================* # class for a literal terminal #-----------------------------------------------------------------------------* class @gtlTerminal : @gtlExpression { @gtlData value } override getter @gtlTerminal eval ?let @gtlContext unused context ?let @gtlData unused vars ?let @library unused lib -> @gtlData result { result = value } #=============================================================================* # class for a variable reference #-----------------------------------------------------------------------------* class @gtlVarRef : @gtlExpression { @gtlVarPath variableName } override getter @gtlVarRef eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [variableName get !context !vars !lib] [!?result setWhere !where] } #=============================================================================* # class for a reference to the special __VARS__ variable #-----------------------------------------------------------------------------* class @gtlAllVarsRef : @gtlExpression {} override getter @gtlAllVarsRef eval ?let @gtlContext unused context ?let @gtlData vars ?let @library unused lib -> @gtlData result { result = vars } #=============================================================================* # classes for unary expressions #-----------------------------------------------------------------------------* # @gtlParenthesizedExpression : ( son ) #-----------------------------------------------------------------------------* class @gtlParenthesizedExpression : @gtlUnaryExpression {} override getter @gtlParenthesizedExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [son eval !context !vars !lib] [!?result setWhere !where] } #-----------------------------------------------------------------------------* # @gtlMinusExpression : unary -. Does a - son #-----------------------------------------------------------------------------* class @gtlMinusExpression : @gtlUnaryExpression {} override getter @gtlMinusExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [[son eval !context !vars !lib] minusOp] } #-----------------------------------------------------------------------------* # @gtlPlusExpression : unary +. Does a + son #-----------------------------------------------------------------------------* class @gtlPlusExpression : @gtlUnaryExpression {} override getter @gtlPlusExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [[son eval !context !vars !lib] plusOp] } #-----------------------------------------------------------------------------* # @gtlTildeExpression : unary bitwise not or boolean not. Does a ~ son #-----------------------------------------------------------------------------* class @gtlNotExpression : @gtlUnaryExpression {} override getter @gtlNotExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [[son eval !context !vars !lib] notOp] } #=============================================================================* # classes for binary expressions #-----------------------------------------------------------------------------* # @gtlAddExpression : binary add. Does a lSon + rSon #-----------------------------------------------------------------------------* class @gtlAddExpression : @gtlBinaryExpression {} override getter @gtlAddExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [[lSon eval !context !vars !lib] addOp ![rSon eval !context !vars !lib]] } #-----------------------------------------------------------------------------* # @gtlSubstractExpression : binary substract. Does a lSon - rSon #-----------------------------------------------------------------------------* class @gtlSubstractExpression : @gtlBinaryExpression {} override getter @gtlSubstractExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [[lSon eval !context !vars !lib] subOp ![rSon eval !context !vars !lib]] } #-----------------------------------------------------------------------------* # @gtlMultiplyExpression : binary multiply. Does a lSon * rSon #-----------------------------------------------------------------------------* class @gtlMultiplyExpression : @gtlBinaryExpression {} override getter @gtlMultiplyExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [[lSon eval !context !vars !lib] mulOp ![rSon eval !context !vars !lib]] } #-----------------------------------------------------------------------------* # @gtlDivideExpression : binary divide. Does a lSon / rSon #-----------------------------------------------------------------------------* class @gtlDivideExpression : @gtlBinaryExpression {} override getter @gtlDivideExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [[lSon eval !context !vars !lib] divOp ![rSon eval !context !vars !lib]] } #-----------------------------------------------------------------------------* # @gtlModulusExpression : binary modulus. Does a lSon mod (or %) rSon #-----------------------------------------------------------------------------* class @gtlModulusExpression : @gtlBinaryExpression {} override getter @gtlModulusExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [[lSon eval !context !vars !lib] modOp ![rSon eval !context !vars !lib]] } #-----------------------------------------------------------------------------* # @gtlAndExpression : binary and. Does a lSon & rSon #-----------------------------------------------------------------------------* class @gtlAndExpression : @gtlBinaryExpression {} override getter @gtlAndExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [[lSon eval !context !vars !lib] andOp ![rSon eval !context !vars !lib]] } #-----------------------------------------------------------------------------* # @gtlOrExpression : binary or. Does a lSon | rSon #-----------------------------------------------------------------------------* class @gtlOrExpression : @gtlBinaryExpression {} override getter @gtlOrExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [[lSon eval !context !vars !lib] orOp ![rSon eval !context !vars !lib]] } #-----------------------------------------------------------------------------* # @gtlXorExpression : binary or. Does a lSon ^ rSon #-----------------------------------------------------------------------------* class @gtlXorExpression : @gtlBinaryExpression {} override getter @gtlXorExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [[lSon eval !context !vars !lib] xorOp ![rSon eval !context !vars !lib]] } #-----------------------------------------------------------------------------* # @gtlShiftLeftExpression : Does a lSon << rSon #-----------------------------------------------------------------------------* class @gtlShiftLeftExpression : @gtlBinaryExpression {} override getter @gtlShiftLeftExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [[lSon eval !context !vars !lib] slOp ![rSon eval !context !vars !lib]] } #-----------------------------------------------------------------------------* # @gtlShiftRightExpression : Does a lSon >> rSon #-----------------------------------------------------------------------------* class @gtlShiftRightExpression : @gtlBinaryExpression {} override getter @gtlShiftRightExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [[lSon eval !context !vars !lib] srOp ![rSon eval !context !vars !lib]] } #-----------------------------------------------------------------------------* # @gtlNotEqualExpression : Does a lSon != rSon #-----------------------------------------------------------------------------* class @gtlNotEqualExpression : @gtlBinaryExpression {} override getter @gtlNotEqualExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [[lSon eval !context !vars !lib] neqOp ![rSon eval !context !vars !lib]] } #-----------------------------------------------------------------------------* # @gtlEqualExpression : Does a lSon == rSon #-----------------------------------------------------------------------------* class @gtlEqualExpression : @gtlBinaryExpression {} override getter @gtlEqualExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [[lSon eval !context !vars !lib] eqOp ![rSon eval !context !vars !lib]] } #-----------------------------------------------------------------------------* # @gtlLowerThanExpression : Does a lSon < rSon #-----------------------------------------------------------------------------* class @gtlLowerThanExpression : @gtlBinaryExpression {} override getter @gtlLowerThanExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [[lSon eval !context !vars !lib] ltOp ![rSon eval !context !vars !lib]] } #-----------------------------------------------------------------------------* # @gtlLowerOrEqualExpression : Does a lSon < rSon #-----------------------------------------------------------------------------* class @gtlLowerOrEqualExpression : @gtlBinaryExpression {} override getter @gtlLowerOrEqualExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [[lSon eval !context !vars !lib] leOp ![rSon eval !context !vars !lib]] } #-----------------------------------------------------------------------------* # @gtlGreaterThanExpression : Does a lSon < rSon #-----------------------------------------------------------------------------* class @gtlGreaterThanExpression : @gtlBinaryExpression {} override getter @gtlGreaterThanExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [[lSon eval !context !vars !lib] gtOp ![rSon eval !context !vars !lib]] } #-----------------------------------------------------------------------------* # @gtlGreaterOrEqualExpression : Does a lSon < rSon #-----------------------------------------------------------------------------* class @gtlGreaterOrEqualExpression : @gtlBinaryExpression {} override getter @gtlGreaterOrEqualExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = [[lSon eval !context !vars !lib] geOp ![rSon eval !context !vars !lib]] } #-----------------------------------------------------------------------------* # @gtlGetterCallExpression : Does a getter call #-----------------------------------------------------------------------------* class @gtlGetterCallExpression : @gtlExpression { @gtlExpression target @lstring getterName @gtlExpressionList arguments } override getter @gtlGetterCallExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { @gtlDataList dataArguments = .emptyList for () in arguments do dataArguments += ![expression eval !context !vars !lib] end let @gtlData targetData = [target eval !context !vars !lib] result = [targetData performGetter !getterName !dataArguments !context !lib] } proc checkArgumentError ?let @lstring name ?let @type formalType ?let @gtlData actualArgument ?let @uint argumentNum { if formalType != [actualArgument embeddedType] then error name : [formalType typeName] + " expected for argument " + argumentNum + ", " + [[actualArgument dynamicType] typeName] + " provided" end } func validateReturnValue ?let @lstring functionName ?let @object returnedValue ->@gtlData result { let @type returnedType = [returnedValue objectDynamicType] let @location loc = [functionName location] if returnedType == `@bigint then result = @gtlInt.new { !loc !emptylstring() !returnedValue as @bigint } elsif returnedType == `@double then result = @gtlFloat.new { !loc !emptylstring() !returnedValue as @double } elsif returnedType == `@string then result = @gtlString.new { !loc !emptylstring() !returnedValue as @string } elsif returnedType == `@bool then result = @gtlBool.new { !loc !emptylstring() !returnedValue as @bool } elsif returnedType == `@list then result = @gtlList.new { !loc !emptylstring() !returnedValue as @list } else error functionName : "this function does not return a compatible type" : result end } #-----------------------------------------------------------------------------* # @gtlFunctionCallExpression : Does a function call #-----------------------------------------------------------------------------* class @gtlFunctionCallExpression : @gtlExpression { @lstring functionName @gtlExpressionList functionArguments } override getter @gtlFunctionCallExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { let @uint currentErrorCount = @uint.errorCount if @function.isFunctionDefined { ![functionName string] } then # built in function @objectlist arguments = .emptyList @gtlDataList dataArguments = .emptyList for () in functionArguments do let @gtlData arg = [expression eval !context !vars !lib] dataArguments += !arg [arg addMyValue !?arguments] end let @function function = .functionWithName { ![functionName string] } let @typelist formalParameterList = [function formalParameterTypeList] if [formalParameterList length] != [arguments length] then error functionName: "this function is invoked with " + [arguments length] + " argument" + if [arguments length] > 1 then "s" else "" end + ", but requires " + [formalParameterList length] + " argument" + if [formalParameterList length] > 1 then "s" else "" end : result else for (formal) in formalParameterList, (actual) in dataArguments do (index) checkArgumentError(!functionName !formal !actual !index) end if currentErrorCount == @uint.errorCount then let @object returnedValue = [function invoke !arguments ![functionName location]] result = validateReturnValue(!functionName !returnedValue) else result = @gtlUnconstructed.new { ![functionName location] !emptylstring() } end end else let @gtlFunction function = [lib getFunction !functionName] @gtlDataList arguments = .emptyList for () in functionArguments do arguments += ![expression eval !context !vars !lib] end result = [function call ![functionName location] !context !lib !arguments] end } #-----------------------------------------------------------------------------* # @gtlExistsExpression : returns true if the variable exists false otherwise #-----------------------------------------------------------------------------* class @gtlExistsExpression : @gtlExpression { @gtlVarPath variable } override getter @gtlExistsExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { result = @gtlBool.new { !where !emptylstring() ![variable exists !context !vars !lib] } } #-----------------------------------------------------------------------------* # @gtlExistsDefaultExpression : returns the variable if it exists # or a default value if it does not exist #-----------------------------------------------------------------------------* class @gtlExistsDefaultExpression : @gtlExistsExpression { @gtlExpression defaultValue } override getter @gtlExistsDefaultExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { if [variable exists !context !vars !lib] then result = [variable get !context !vars !lib] else result = [defaultValue eval !context !vars !lib] end } #-----------------------------------------------------------------------------* # @gtlTypeOfExpression : the type of the variable #-----------------------------------------------------------------------------* class @gtlTypeOfExpression : @gtlExpression { @gtlVarPath variable } override getter @gtlTypeOfExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { let @gtlData variableValue = [variable get !context !vars !lib] result = @gtlType.new { !where !emptylstring() ![variableValue dynamicType] } } #-----------------------------------------------------------------------------* # @gtlStructOfStructExpression : convert a struct to a map #-----------------------------------------------------------------------------* class @gtlMapOfStructExpression : @gtlExpression { @gtlExpression expression } override getter @gtlMapOfStructExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { let @gtlData expressionValue = [expression eval !context !vars !lib] cast expressionValue case == @gtlStruct expressionValueStruct: result = @gtlMap.new { !where !emptylstring() ![expressionValueStruct value] } else error where : "struct expected" : result end } #-----------------------------------------------------------------------------* # @gtlMapOfListExpression : convert a list of structs to a map #-----------------------------------------------------------------------------* class @gtlMapOfListExpression : @gtlMapOfStructExpression { @lstring key } override getter @gtlMapOfListExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { let @gtlData expressionValue = [expression eval !context !vars !lib] cast expressionValue case == @gtlList expressionValueList: @gtlVarMap resultMap = .emptyMap for (item) in [expressionValueList value] do (index) cast item case == @gtlStruct itemStruct: if [[itemStruct value] hasKey ![key string]] then [[itemStruct value] get !key ?let @gtlData keyValue] [!?resultMap put ![keyValue lstring] !item ] else error [expressionValue where] : "item at index " + index + " does not have field named " + key end else error [expressionValue where] : "list of struct expected" end end result = @gtlMap.new { !where !emptylstring() !resultMap } else error [expressionValue where] : "list expected" : result end } #-----------------------------------------------------------------------------* # @gtlListOfExpression : convert a map to a list #-----------------------------------------------------------------------------* class @gtlListOfExpression : @gtlExpression { @gtlExpression expression } override getter @gtlListOfExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { let @gtlData expressionValue = [expression eval !context !vars !lib] cast expressionValue case == @gtlMap expressionValueMap: @list resultList = .emptyList for (unused key item) in [expressionValueMap value] do resultList += !item end result = @gtlList.new { !where !emptylstring() !resultList } else error where : "map expected" : result end } #-----------------------------------------------------------------------------* # @gtlLiteralStructExpression #-----------------------------------------------------------------------------* class @gtlLiteralStructExpression : @gtlExpression { @gtlExpressionMap value } override getter @gtlLiteralStructExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { @gtlVarMap resultStruct = .emptyMap for (key item) in value do [!?resultStruct put !key ![item eval !context !vars !lib]] end result = @gtlStruct.new { !where !emptylstring() !resultStruct } } #-----------------------------------------------------------------------------* # @gtlLiteralMapExpression #-----------------------------------------------------------------------------* class @gtlLiteralMapExpression : @gtlExpression { @gtlExpressionMap value } override getter @gtlLiteralMapExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { @gtlVarMap resultStruct = .emptyMap for (key item) in value do [!?resultStruct put !key ![item eval !context !vars !lib]] end result = @gtlMap.new { !where !emptylstring() !resultStruct } } #-----------------------------------------------------------------------------* # @gtlLiteralListExpression #-----------------------------------------------------------------------------* class @gtlLiteralListExpression : @gtlExpression { @gtlExpressionList value } override getter @gtlLiteralListExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { @list resultList = .emptyList for (item) in value do resultList += ![item eval !context !vars !lib] end result = @gtlList.new { !where !emptylstring() !resultList } } #-----------------------------------------------------------------------------* # @gtlLiteralSetExpression #-----------------------------------------------------------------------------* class @gtlLiteralSetExpression : @gtlExpression { @gtlExpressionList value } override getter @gtlLiteralSetExpression eval ?let @gtlContext context ?let @gtlData vars ?let @library lib -> @gtlData result { @lstringset resultSet = .emptyMap for (item) in value do let @lstring itemValue = [[item eval !context !vars !lib] lstring] if [resultSet hasKey !itemValue] then [!?resultSet del !itemValue] end [!?resultSet put !itemValue] end result = @gtlSet.new { !where !emptylstring() !resultSet } }