go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/llx/builtin.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package llx
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  
    10  	"github.com/rs/zerolog/log"
    11  	"go.mondoo.com/cnquery/providers-sdk/v1/resources"
    12  	"go.mondoo.com/cnquery/types"
    13  )
    14  
    15  type chunkHandlerV2 struct {
    16  	Compiler func(types.Type, types.Type) (string, error)
    17  	f        func(*blockExecutor, *RawData, *Chunk, uint64) (*RawData, uint64, error)
    18  	Label    string
    19  	Typ      types.Type
    20  }
    21  
    22  // BuiltinFunctions for all builtin types
    23  var BuiltinFunctionsV2 map[types.Type]map[string]chunkHandlerV2
    24  
    25  func init() {
    26  	BuiltinFunctionsV2 = map[types.Type]map[string]chunkHandlerV2{
    27  		types.Nil: {
    28  			// == / !=
    29  			string("==" + types.Nil):          {f: chunkEqTrueV2, Label: "=="},
    30  			string("!=" + types.Nil):          {f: chunkNeqFalseV2, Label: "!="},
    31  			string("==" + types.Bool):         {f: chunkEqFalseV2, Label: "=="},
    32  			string("!=" + types.Bool):         {f: chunkNeqTrueV2, Label: "!="},
    33  			string("==" + types.Int):          {f: chunkEqFalseV2, Label: "=="},
    34  			string("!=" + types.Int):          {f: chunkNeqTrueV2, Label: "!="},
    35  			string("==" + types.Float):        {f: chunkEqFalseV2, Label: "=="},
    36  			string("!=" + types.Float):        {f: chunkNeqTrueV2, Label: "!="},
    37  			string("==" + types.String):       {f: chunkEqFalseV2, Label: "=="},
    38  			string("!=" + types.String):       {f: chunkNeqTrueV2, Label: "!="},
    39  			string("==" + types.Regex):        {f: chunkEqFalseV2, Label: "=="},
    40  			string("!=" + types.Regex):        {f: chunkNeqTrueV2, Label: "!="},
    41  			string("==" + types.Time):         {f: chunkEqFalseV2, Label: "=="},
    42  			string("!=" + types.Time):         {f: chunkNeqTrueV2, Label: "!="},
    43  			string("==" + types.Dict):         {f: chunkEqFalseV2, Label: "=="},
    44  			string("!=" + types.Dict):         {f: chunkNeqTrueV2, Label: "!="},
    45  			string("==" + types.Empty):        {f: chunkEqTrueV2, Label: "=="},
    46  			string("!=" + types.Empty):        {f: chunkNeqTrueV2, Label: "!="},
    47  			string("==" + types.ArrayLike):    {f: chunkEqFalseV2, Label: "=="},
    48  			string("!=" + types.ArrayLike):    {f: chunkNeqTrueV2, Label: "!="},
    49  			string("==" + types.MapLike):      {f: chunkEqFalseV2, Label: "=="},
    50  			string("!=" + types.MapLike):      {f: chunkNeqTrueV2, Label: "!="},
    51  			string("==" + types.ResourceLike): {f: chunkEqFalseV2, Label: "=="},
    52  			string("!=" + types.ResourceLike): {f: chunkNeqTrueV2, Label: "!="},
    53  			string("==" + types.FunctionLike): {f: chunkEqFalseV2, Label: "=="},
    54  			string("!=" + types.FunctionLike): {f: chunkNeqTrueV2, Label: "!="},
    55  		},
    56  		types.Bool: {
    57  			// == / !=
    58  			string("==" + types.Nil):                 {f: boolCmpNilV2, Label: "=="},
    59  			string("!=" + types.Nil):                 {f: boolNotNilV2, Label: "!="},
    60  			string("==" + types.Bool):                {f: boolCmpBoolV2, Label: "=="},
    61  			string("!=" + types.Bool):                {f: boolNotBoolV2, Label: "!="},
    62  			string("==" + types.Int):                 {f: chunkEqFalseV2, Label: "=="},
    63  			string("!=" + types.Int):                 {f: chunkNeqTrueV2, Label: "!="},
    64  			string("==" + types.Float):               {f: chunkEqFalseV2, Label: "=="},
    65  			string("!=" + types.Float):               {f: chunkNeqTrueV2, Label: "!="},
    66  			string("==" + types.String):              {f: boolCmpStringV2, Label: "=="},
    67  			string("!=" + types.String):              {f: boolNotStringV2, Label: "!="},
    68  			string("==" + types.Regex):               {f: chunkEqFalseV2, Label: "=="},
    69  			string("!=" + types.Regex):               {f: chunkNeqTrueV2, Label: "!="},
    70  			string("==" + types.Time):                {f: chunkEqFalseV2, Label: "=="},
    71  			string("!=" + types.Time):                {f: chunkNeqTrueV2, Label: "!="},
    72  			string("==" + types.Dict):                {f: boolCmpDictV2, Label: "=="},
    73  			string("!=" + types.Dict):                {f: boolNotDictV2, Label: "!="},
    74  			string("==" + types.Empty):               {f: boolCmpNilV2, Label: "=="},
    75  			string("!=" + types.Empty):               {f: boolNotNilV2, Label: "!="},
    76  			string("==" + types.ArrayLike):           {f: chunkEqFalseV2, Label: "=="},
    77  			string("!=" + types.ArrayLike):           {f: chunkNeqTrueV2, Label: "!="},
    78  			string("==" + types.Array(types.Bool)):   {f: boolCmpBoolarrayV2, Label: "=="},
    79  			string("!=" + types.Array(types.Bool)):   {f: boolNotBoolarrayV2, Label: "!="},
    80  			string("==" + types.Array(types.String)): {f: boolCmpStringarrayV2, Label: "=="},
    81  			string("!=" + types.Array(types.String)): {f: boolNotStringarrayV2, Label: "!="},
    82  			string("==" + types.MapLike):             {f: chunkEqFalseV2, Label: "=="},
    83  			string("!=" + types.MapLike):             {f: chunkNeqTrueV2, Label: "!="},
    84  			string("==" + types.ResourceLike):        {f: chunkEqFalseV2, Label: "=="},
    85  			string("!=" + types.ResourceLike):        {f: chunkNeqTrueV2, Label: "!="},
    86  			string("==" + types.FunctionLike):        {f: chunkEqFalseV2, Label: "=="},
    87  			string("!=" + types.FunctionLike):        {f: chunkNeqTrueV2, Label: "!="},
    88  			//
    89  			string("&&" + types.Bool):      {f: boolAndBoolV2, Label: "&&"},
    90  			string("||" + types.Bool):      {f: boolOrBoolV2, Label: "||"},
    91  			string("&&" + types.Int):       {f: boolAndIntV2, Label: "&&"},
    92  			string("||" + types.Int):       {f: boolOrIntV2, Label: "||"},
    93  			string("&&" + types.Float):     {f: boolAndFloatV2, Label: "&&"},
    94  			string("||" + types.Float):     {f: boolOrFloatV2, Label: "||"},
    95  			string("&&" + types.String):    {f: boolAndStringV2, Label: "&&"},
    96  			string("||" + types.String):    {f: boolOrStringV2, Label: "||"},
    97  			string("&&" + types.Regex):     {f: boolAndRegexV2, Label: "&&"},
    98  			string("||" + types.Regex):     {f: boolOrRegexV2, Label: "||"},
    99  			string("&&" + types.Time):      {f: boolAndTimeV2, Label: "&&"},
   100  			string("||" + types.Time):      {f: boolOrTimeV2, Label: "||"},
   101  			string("&&" + types.Dict):      {f: boolAndDictV2, Label: "&&"},
   102  			string("||" + types.Dict):      {f: boolOrDictV2, Label: "||"},
   103  			string("&&" + types.ArrayLike): {f: boolAndArrayV2, Label: "&&"},
   104  			string("||" + types.ArrayLike): {f: boolOrArrayV2, Label: "||"},
   105  			string("&&" + types.MapLike):   {f: boolAndMapV2, Label: "&&"},
   106  			string("||" + types.MapLike):   {f: boolOrMapV2, Label: "||"},
   107  		},
   108  		types.Int: {
   109  			// == / !=
   110  			string("==" + types.Nil):                 {f: intCmpNilV2, Label: "=="},
   111  			string("!=" + types.Nil):                 {f: intNotNilV2, Label: "!="},
   112  			string("==" + types.Int):                 {f: intCmpIntV2, Label: "=="},
   113  			string("!=" + types.Int):                 {f: intNotIntV2, Label: "!="},
   114  			string("==" + types.Float):               {f: intCmpFloatV2, Label: "=="},
   115  			string("!=" + types.Float):               {f: intNotFloatV2, Label: "!="},
   116  			string("==" + types.String):              {f: intCmpStringV2, Label: "=="},
   117  			string("!=" + types.String):              {f: intNotStringV2, Label: "!="},
   118  			string("==" + types.Regex):               {f: intCmpRegexV2, Label: "=="},
   119  			string("!=" + types.Regex):               {f: intNotRegexV2, Label: "!="},
   120  			string("==" + types.Dict):                {f: intCmpDictV2, Label: "=="},
   121  			string("!=" + types.Dict):                {f: intNotDictV2, Label: "!="},
   122  			string("==" + types.Empty):               {f: intCmpNilV2, Label: "=="},
   123  			string("!=" + types.Empty):               {f: intNotNilV2, Label: "!="},
   124  			string("==" + types.ArrayLike):           {f: chunkEqFalseV2, Label: "=="},
   125  			string("!=" + types.ArrayLike):           {f: chunkNeqTrueV2, Label: "!="},
   126  			string("==" + types.Array(types.Int)):    {f: intCmpIntarrayV2, Label: "=="},
   127  			string("!=" + types.Array(types.Int)):    {f: intNotIntarrayV2, Label: "!="},
   128  			string("==" + types.Array(types.Float)):  {f: intCmpFloatarrayV2, Label: "=="},
   129  			string("!=" + types.Array(types.Float)):  {f: intNotFloatarrayV2, Label: "!="},
   130  			string("==" + types.Array(types.String)): {f: intCmpStringarrayV2, Label: "=="},
   131  			string("!=" + types.Array(types.String)): {f: intNotStringarrayV2, Label: "!="},
   132  			string("+" + types.Int):                  {f: intPlusIntV2, Label: "+", Typ: types.Int},
   133  			string("-" + types.Int):                  {f: intMinusIntV2, Label: "-", Typ: types.Int},
   134  			string("*" + types.Int):                  {f: intTimesIntV2, Label: "*", Typ: types.Int},
   135  			string("/" + types.Int):                  {f: intDividedIntV2, Label: "/", Typ: types.Int},
   136  			string("+" + types.Float):                {f: intPlusFloatV2, Label: "+", Typ: types.Float},
   137  			string("-" + types.Float):                {f: intMinusFloatV2, Label: "-", Typ: types.Float},
   138  			string("*" + types.Float):                {f: intTimesFloatV2, Label: "*", Typ: types.Float},
   139  			string("/" + types.Float):                {f: intDividedFloatV2, Label: "/", Typ: types.Float},
   140  			string("+" + types.Dict):                 {f: intPlusDictV2, Label: "+", Typ: types.Float},
   141  			string("-" + types.Dict):                 {f: intMinusDictV2, Label: "-", Typ: types.Float},
   142  			string("*" + types.Dict):                 {f: intTimesDictV2, Label: "*", Typ: types.Float},
   143  			string("/" + types.Dict):                 {f: intDividedDictV2, Label: "/", Typ: types.Float},
   144  			string("*" + types.Time):                 {f: intTimesTimeV2, Label: "*", Typ: types.Time},
   145  			string("<" + types.Int):                  {f: intLTIntV2, Label: "<"},
   146  			string("<=" + types.Int):                 {f: intLTEIntV2, Label: "<="},
   147  			string(">" + types.Int):                  {f: intGTIntV2, Label: ">"},
   148  			string(">=" + types.Int):                 {f: intGTEIntV2, Label: ">="},
   149  			string("<" + types.Float):                {f: intLTFloatV2, Label: "<"},
   150  			string("<=" + types.Float):               {f: intLTEFloatV2, Label: "<="},
   151  			string(">" + types.Float):                {f: intGTFloatV2, Label: ">"},
   152  			string(">=" + types.Float):               {f: intGTEFloatV2, Label: ">="},
   153  			string("<" + types.String):               {f: intLTStringV2, Label: "<"},
   154  			string("<=" + types.String):              {f: intLTEStringV2, Label: "<="},
   155  			string(">" + types.String):               {f: intGTStringV2, Label: ">"},
   156  			string(">=" + types.String):              {f: intGTEStringV2, Label: ">="},
   157  			string("<" + types.Dict):                 {f: intLTDictV2, Label: "<"},
   158  			string("<=" + types.Dict):                {f: intLTEDictV2, Label: "<="},
   159  			string(">" + types.Dict):                 {f: intGTDictV2, Label: ">"},
   160  			string(">=" + types.Dict):                {f: intGTEDictV2, Label: ">="},
   161  			string("&&" + types.Bool):                {f: intAndBoolV2, Label: "&&"},
   162  			string("||" + types.Bool):                {f: intOrBoolV2, Label: "||"},
   163  			string("&&" + types.Int):                 {f: intAndIntV2, Label: "&&"},
   164  			string("||" + types.Int):                 {f: intOrIntV2, Label: "||"},
   165  			string("&&" + types.Float):               {f: intAndFloatV2, Label: "&&"},
   166  			string("||" + types.Float):               {f: intOrFloatV2, Label: "||"},
   167  			string("&&" + types.String):              {f: intAndStringV2, Label: "&&"},
   168  			string("||" + types.String):              {f: intOrStringV2, Label: "||"},
   169  			string("&&" + types.Regex):               {f: intAndRegexV2, Label: "&&"},
   170  			string("||" + types.Regex):               {f: intOrRegexV2, Label: "||"},
   171  			string("&&" + types.Time):                {f: intAndTimeV2, Label: "&&"},
   172  			string("||" + types.Time):                {f: intOrTimeV2, Label: "||"},
   173  			string("&&" + types.Dict):                {f: intAndDictV2, Label: "&&"},
   174  			string("||" + types.Dict):                {f: intOrDictV2, Label: "||"},
   175  			string("&&" + types.ArrayLike):           {f: intAndArrayV2, Label: "&&"},
   176  			string("||" + types.ArrayLike):           {f: intOrArrayV2, Label: "||"},
   177  			string("&&" + types.MapLike):             {f: intAndMapV2, Label: "&&"},
   178  			string("||" + types.MapLike):             {f: intOrMapV2, Label: "||"},
   179  		},
   180  		types.Float: {
   181  			// == / !=
   182  			string("==" + types.Nil):                 {f: floatCmpNilV2, Label: "=="},
   183  			string("!=" + types.Nil):                 {f: floatNotNilV2, Label: "!="},
   184  			string("==" + types.Float):               {f: floatCmpFloatV2, Label: "=="},
   185  			string("!=" + types.Float):               {f: floatNotFloatV2, Label: "!="},
   186  			string("==" + types.String):              {f: floatCmpStringV2, Label: "=="},
   187  			string("!=" + types.String):              {f: floatNotStringV2, Label: "!="},
   188  			string("==" + types.Regex):               {f: floatCmpRegexV2, Label: "=="},
   189  			string("!=" + types.Regex):               {f: floatNotRegexV2, Label: "!="},
   190  			string("==" + types.Dict):                {f: floatCmpDictV2, Label: "=="},
   191  			string("!=" + types.Dict):                {f: floatNotDictV2, Label: "!="},
   192  			string("==" + types.Empty):               {f: floatCmpNilV2, Label: "=="},
   193  			string("!=" + types.Empty):               {f: floatNotNilV2, Label: "!="},
   194  			string("==" + types.ArrayLike):           {f: chunkEqFalseV2, Label: "=="},
   195  			string("!=" + types.ArrayLike):           {f: chunkNeqTrueV2, Label: "!="},
   196  			string("==" + types.Array(types.Int)):    {f: floatCmpIntarrayV2, Label: "=="},
   197  			string("!=" + types.Array(types.Int)):    {f: floatNotIntarrayV2, Label: "!="},
   198  			string("==" + types.Array(types.Float)):  {f: floatCmpFloatarrayV2, Label: "=="},
   199  			string("!=" + types.Array(types.Float)):  {f: floatNotFloatarrayV2, Label: "!="},
   200  			string("==" + types.Array(types.String)): {f: floatCmpStringarrayV2, Label: "=="},
   201  			string("!=" + types.Array(types.String)): {f: floatNotStringarrayV2, Label: "!="},
   202  			string("+" + types.Int):                  {f: floatPlusIntV2, Label: "+", Typ: types.Float},
   203  			string("-" + types.Int):                  {f: floatMinusIntV2, Label: "-", Typ: types.Float},
   204  			string("*" + types.Int):                  {f: floatTimesIntV2, Label: "*", Typ: types.Float},
   205  			string("/" + types.Int):                  {f: floatDividedIntV2, Label: "/", Typ: types.Float},
   206  			string("+" + types.Float):                {f: floatPlusFloatV2, Label: "+", Typ: types.Float},
   207  			string("-" + types.Float):                {f: floatMinusFloatV2, Label: "-", Typ: types.Float},
   208  			string("*" + types.Float):                {f: floatTimesFloatV2, Label: "*", Typ: types.Float},
   209  			string("/" + types.Float):                {f: floatDividedFloatV2, Label: "/", Typ: types.Float},
   210  			string("+" + types.Dict):                 {f: floatPlusDictV2, Label: "+", Typ: types.Float},
   211  			string("-" + types.Dict):                 {f: floatMinusDictV2, Label: "-", Typ: types.Float},
   212  			string("*" + types.Dict):                 {f: floatTimesDictV2, Label: "*", Typ: types.Float},
   213  			string("/" + types.Dict):                 {f: floatDividedDictV2, Label: "/", Typ: types.Float},
   214  			string("*" + types.Time):                 {f: floatTimesTimeV2, Label: "*", Typ: types.Time},
   215  			string("<" + types.Int):                  {f: floatLTIntV2, Label: "<"},
   216  			string("<=" + types.Int):                 {f: floatLTEIntV2, Label: "<="},
   217  			string(">" + types.Int):                  {f: floatGTIntV2, Label: ">"},
   218  			string(">=" + types.Int):                 {f: floatGTEIntV2, Label: ">="},
   219  			string("<" + types.Float):                {f: floatLTFloatV2, Label: "<"},
   220  			string("<=" + types.Float):               {f: floatLTEFloatV2, Label: "<="},
   221  			string(">" + types.Float):                {f: floatGTFloatV2, Label: ">"},
   222  			string(">=" + types.Float):               {f: floatGTEFloatV2, Label: ">="},
   223  			string("<" + types.String):               {f: floatLTStringV2, Label: "<"},
   224  			string("<=" + types.String):              {f: floatLTEStringV2, Label: "<="},
   225  			string(">" + types.String):               {f: floatGTStringV2, Label: ">"},
   226  			string(">=" + types.String):              {f: floatGTEStringV2, Label: ">="},
   227  			string("<" + types.Dict):                 {f: floatLTDictV2, Label: "<"},
   228  			string("<=" + types.Dict):                {f: floatLTEDictV2, Label: "<="},
   229  			string(">" + types.Dict):                 {f: floatGTDictV2, Label: ">"},
   230  			string(">=" + types.Dict):                {f: floatGTEDictV2, Label: ">="},
   231  			string("&&" + types.Bool):                {f: floatAndBoolV2, Label: "&&"},
   232  			string("||" + types.Bool):                {f: floatOrBoolV2, Label: "||"},
   233  			string("&&" + types.Int):                 {f: floatAndIntV2, Label: "&&"},
   234  			string("||" + types.Int):                 {f: floatOrIntV2, Label: "||"},
   235  			string("&&" + types.Float):               {f: floatAndFloatV2, Label: "&&"},
   236  			string("||" + types.Float):               {f: floatOrFloatV2, Label: "||"},
   237  			string("&&" + types.String):              {f: floatAndStringV2, Label: "&&"},
   238  			string("||" + types.String):              {f: floatOrStringV2, Label: "||"},
   239  			string("&&" + types.Regex):               {f: floatAndRegexV2, Label: "&&"},
   240  			string("||" + types.Regex):               {f: floatOrRegexV2, Label: "||"},
   241  			string("&&" + types.Time):                {f: floatAndTimeV2, Label: "&&"},
   242  			string("||" + types.Time):                {f: floatOrTimeV2, Label: "||"},
   243  			string("&&" + types.Dict):                {f: floatAndDictV2, Label: "&&"},
   244  			string("||" + types.Dict):                {f: floatOrDictV2, Label: "||"},
   245  			string("&&" + types.ArrayLike):           {f: floatAndArrayV2, Label: "&&"},
   246  			string("||" + types.ArrayLike):           {f: floatOrArrayV2, Label: "||"},
   247  			string("&&" + types.MapLike):             {f: floatAndMapV2, Label: "&&"},
   248  			string("||" + types.MapLike):             {f: floatOrMapV2, Label: "&&"},
   249  		},
   250  		types.String: {
   251  			// == / !=
   252  			string("==" + types.Nil):                 {f: stringCmpNilV2, Label: "=="},
   253  			string("!=" + types.Nil):                 {f: stringNotNilV2, Label: "!="},
   254  			string("==" + types.Empty):               {f: stringCmpEmptyV2, Label: "=="},
   255  			string("!=" + types.Empty):               {f: stringNotEmptyV2, Label: "!="},
   256  			string("==" + types.String):              {f: stringCmpStringV2, Label: "=="},
   257  			string("!=" + types.String):              {f: stringNotStringV2, Label: "!="},
   258  			string("==" + types.Regex):               {f: stringCmpRegexV2, Label: "=="},
   259  			string("!=" + types.Regex):               {f: stringNotRegexV2, Label: "!="},
   260  			string("==" + types.Bool):                {f: stringCmpBoolV2, Label: "=="},
   261  			string("!=" + types.Bool):                {f: stringNotBoolV2, Label: "!="},
   262  			string("==" + types.Int):                 {f: stringCmpIntV2, Label: "=="},
   263  			string("!=" + types.Int):                 {f: stringNotIntV2, Label: "!="},
   264  			string("==" + types.Float):               {f: stringCmpFloatV2, Label: "=="},
   265  			string("!=" + types.Float):               {f: stringNotFloatV2, Label: "!="},
   266  			string("==" + types.Dict):                {f: stringCmpDictV2, Label: "=="},
   267  			string("!=" + types.Dict):                {f: stringNotDictV2, Label: "!="},
   268  			string("==" + types.ArrayLike):           {f: chunkEqFalseV2, Label: "=="},
   269  			string("!=" + types.ArrayLike):           {f: chunkNeqTrueV2, Label: "!="},
   270  			string("==" + types.Array(types.String)): {f: stringCmpStringarrayV2, Label: "=="},
   271  			string("!=" + types.Array(types.String)): {f: stringNotStringarrayV2, Label: "!="},
   272  			string("==" + types.Array(types.Bool)):   {f: stringCmpBoolarrayV2, Label: "=="},
   273  			string("!=" + types.Array(types.Bool)):   {f: stringNotBoolarrayV2, Label: "!="},
   274  			string("==" + types.Array(types.Int)):    {f: stringCmpIntarrayV2, Label: "=="},
   275  			string("!=" + types.Array(types.Int)):    {f: stringNotIntarrayV2, Label: "!="},
   276  			string("==" + types.Array(types.Float)):  {f: stringCmpFloatarrayV2, Label: "=="},
   277  			string("!=" + types.Array(types.Float)):  {f: stringNotFloatarrayV2, Label: "!="},
   278  			string("<" + types.Int):                  {f: stringLTIntV2, Label: "<"},
   279  			string("<=" + types.Int):                 {f: stringLTEIntV2, Label: "<="},
   280  			string(">" + types.Int):                  {f: stringGTIntV2, Label: ">"},
   281  			string(">=" + types.Int):                 {f: stringGTEIntV2, Label: ">="},
   282  			string("<" + types.Float):                {f: stringLTFloatV2, Label: "<"},
   283  			string("<=" + types.Float):               {f: stringLTEFloatV2, Label: "<="},
   284  			string(">" + types.Float):                {f: stringGTFloatV2, Label: ">"},
   285  			string(">=" + types.Float):               {f: stringGTEFloatV2, Label: ">="},
   286  			string("<" + types.String):               {f: stringLTStringV2, Label: "<"},
   287  			string("<=" + types.String):              {f: stringLTEStringV2, Label: "<="},
   288  			string(">" + types.String):               {f: stringGTStringV2, Label: ">"},
   289  			string(">=" + types.String):              {f: stringGTEStringV2, Label: ">="},
   290  			string("<" + types.Dict):                 {f: stringLTDictV2, Label: "<"},
   291  			string("<=" + types.Dict):                {f: stringLTEDictV2, Label: "<="},
   292  			string(">" + types.Dict):                 {f: stringGTDictV2, Label: ">"},
   293  			string(">=" + types.Dict):                {f: stringGTEDictV2, Label: ">="},
   294  			string("&&" + types.Bool):                {f: stringAndBoolV2, Label: "&&"},
   295  			string("||" + types.Bool):                {f: stringOrBoolV2, Label: "||"},
   296  			string("&&" + types.Int):                 {f: stringAndIntV2, Label: "&&"},
   297  			string("||" + types.Int):                 {f: stringOrIntV2, Label: "||"},
   298  			string("&&" + types.Float):               {f: stringAndFloatV2, Label: "&&"},
   299  			string("||" + types.Float):               {f: stringOrFloatV2, Label: "||"},
   300  			string("&&" + types.String):              {f: stringAndStringV2, Label: "&&"},
   301  			string("||" + types.String):              {f: stringOrStringV2, Label: "||"},
   302  			string("&&" + types.Regex):               {f: stringAndRegexV2, Label: "&&"},
   303  			string("||" + types.Regex):               {f: stringOrRegexV2, Label: "||"},
   304  			string("&&" + types.Time):                {f: stringAndTimeV2, Label: "&&"},
   305  			string("||" + types.Time):                {f: stringOrTimeV2, Label: "||"},
   306  			string("&&" + types.Dict):                {f: stringAndDictV2, Label: "&&"},
   307  			string("||" + types.Dict):                {f: stringOrDictV2, Label: "||"},
   308  			string("&&" + types.ArrayLike):           {f: stringAndArrayV2, Label: "&&"},
   309  			string("||" + types.ArrayLike):           {f: stringOrArrayV2, Label: "||"},
   310  			string("&&" + types.MapLike):             {f: stringAndMapV2, Label: "&&"},
   311  			string("||" + types.MapLike):             {f: stringOrMapV2, Label: "&&"},
   312  			string("+" + types.String):               {f: stringPlusStringV2, Label: "+"},
   313  			// fields
   314  			string("contains" + types.String):              {f: stringContainsStringV2, Label: "contains"},
   315  			string("contains" + types.Array(types.String)): {f: stringContainsArrayStringV2, Label: "contains"},
   316  			string("contains" + types.Int):                 {f: stringContainsIntV2, Label: "contains"},
   317  			string("contains" + types.Array(types.Int)):    {f: stringContainsArrayIntV2, Label: "contains"},
   318  			string("contains" + types.Regex):               {f: stringContainsRegex, Label: "contains"},
   319  			string("contains" + types.Array(types.Regex)):  {f: stringContainsArrayRegex, Label: "contains"},
   320  			string("find"):      {f: stringFindV2, Label: "find"},
   321  			string("camelcase"): {f: stringCamelcaseV2, Label: "camelcase"},
   322  			string("downcase"):  {f: stringDowncaseV2, Label: "downcase"},
   323  			string("upcase"):    {f: stringUpcaseV2, Label: "upcase"},
   324  			string("length"):    {f: stringLengthV2, Label: "length"},
   325  			string("lines"):     {f: stringLinesV2, Label: "lines"},
   326  			string("split"):     {f: stringSplitV2, Label: "split"},
   327  			string("trim"):      {f: stringTrimV2, Label: "trim"},
   328  		},
   329  		types.StringSlice: {
   330  			// TODO: implement the remaining calls for this type
   331  			// string("==" + types.Nil):                 {f: chunkEqFalseV2, Label: "=="},
   332  			// string("!=" + types.Nil):                 {f: chunkNeqFalseV2, Label: "!="},
   333  			string("==" + types.String): {f: stringsliceEqString, Label: "=="},
   334  			// string("!=" + types.String):              {f: stringNotStringV2, Label: "!="},
   335  			// string("==" + types.Regex):               {f: stringCmpRegexV2, Label: "=="},
   336  			// string("!=" + types.Regex):               {f: stringNotRegexV2, Label: "!="},
   337  			// string("==" + types.Bool):                {f: stringCmpBoolV2, Label: "=="},
   338  			// string("!=" + types.Bool):                {f: stringNotBoolV2, Label: "!="},
   339  			// string("==" + types.Int):                 {f: stringCmpIntV2, Label: "=="},
   340  			// string("!=" + types.Int):                 {f: stringNotIntV2, Label: "!="},
   341  			// string("==" + types.Float):               {f: stringCmpFloatV2, Label: "=="},
   342  			// string("!=" + types.Float):               {f: stringNotFloatV2, Label: "!="},
   343  			// string("==" + types.Dict):                {f: stringCmpDictV2, Label: "=="},
   344  			// string("!=" + types.Dict):                {f: stringNotDictV2, Label: "!="},
   345  			string("==" + types.Array(types.String)): {f: stringsliceEqArrayString, Label: "=="},
   346  		},
   347  		types.Regex: {
   348  			// == / !=
   349  			string("==" + types.Nil):                 {f: stringCmpNilV2, Label: "=="},
   350  			string("!=" + types.Nil):                 {f: stringNotNilV2, Label: "!="},
   351  			string("==" + types.Empty):               {f: stringCmpEmptyV2, Label: "=="},
   352  			string("!=" + types.Empty):               {f: stringNotEmptyV2, Label: "!="},
   353  			string("==" + types.Regex):               {f: stringCmpStringV2, Label: "=="},
   354  			string("!=" + types.Regex):               {f: stringNotStringV2, Label: "!="},
   355  			string("==" + types.Bool):                {f: chunkEqFalseV2, Label: "=="},
   356  			string("!=" + types.Bool):                {f: chunkNeqFalseV2, Label: "!="},
   357  			string("==" + types.Int):                 {f: regexCmpIntV2, Label: "=="},
   358  			string("!=" + types.Int):                 {f: regexNotIntV2, Label: "!="},
   359  			string("==" + types.Float):               {f: regexCmpFloatV2, Label: "=="},
   360  			string("!=" + types.Float):               {f: regexNotFloatV2, Label: "!="},
   361  			string("==" + types.Dict):                {f: regexCmpDictV2, Label: "=="},
   362  			string("!=" + types.Dict):                {f: regexNotDictV2, Label: "!="},
   363  			string("==" + types.String):              {f: regexCmpStringV2, Label: "=="},
   364  			string("!=" + types.String):              {f: regexNotStringV2, Label: "!="},
   365  			string("==" + types.ArrayLike):           {f: chunkEqFalseV2, Label: "=="},
   366  			string("!=" + types.ArrayLike):           {f: chunkNeqTrueV2, Label: "!="},
   367  			string("==" + types.Array(types.Regex)):  {f: stringCmpStringarrayV2, Label: "=="},
   368  			string("!=" + types.Array(types.Regex)):  {f: stringNotStringarrayV2, Label: "!="},
   369  			string("==" + types.Array(types.Int)):    {f: regexCmpIntarrayV2, Label: "=="},
   370  			string("!=" + types.Array(types.Int)):    {f: regexNotIntarrayV2, Label: "!="},
   371  			string("==" + types.Array(types.Float)):  {f: regexCmpFloatarrayV2, Label: "=="},
   372  			string("!=" + types.Array(types.Float)):  {f: regexNotFloatarrayV2, Label: "!="},
   373  			string("==" + types.Array(types.String)): {f: regexCmpStringarrayV2, Label: "=="},
   374  			string("!=" + types.Array(types.String)): {f: regexNotStringarrayV2, Label: "!="},
   375  			string("&&" + types.Bool):                {f: regexAndBoolV2, Label: "&&"},
   376  			string("||" + types.Bool):                {f: regexOrBoolV2, Label: "||"},
   377  			string("&&" + types.Int):                 {f: regexAndIntV2, Label: "&&"},
   378  			string("||" + types.Int):                 {f: regexOrIntV2, Label: "||"},
   379  			string("&&" + types.Float):               {f: regexAndFloatV2, Label: "&&"},
   380  			string("||" + types.Float):               {f: regexOrFloatV2, Label: "||"},
   381  			string("&&" + types.String):              {f: regexAndStringV2, Label: "&&"},
   382  			string("||" + types.String):              {f: regexOrStringV2, Label: "||"},
   383  			string("&&" + types.Regex):               {f: regexAndRegexV2, Label: "&&"},
   384  			string("||" + types.Regex):               {f: regexOrRegexV2, Label: "||"},
   385  			string("&&" + types.Time):                {f: regexAndTimeV2, Label: "&&"},
   386  			string("||" + types.Time):                {f: regexOrTimeV2, Label: "||"},
   387  			string("&&" + types.Dict):                {f: regexAndDictV2, Label: "&&"},
   388  			string("||" + types.Dict):                {f: regexOrDictV2, Label: "||"},
   389  			string("&&" + types.ArrayLike):           {f: regexAndArrayV2, Label: "&&"},
   390  			string("||" + types.ArrayLike):           {f: regexOrArrayV2, Label: "||"},
   391  			string("&&" + types.MapLike):             {f: regexAndMapV2, Label: "&&"},
   392  			string("||" + types.MapLike):             {f: regexOrMapV2, Label: "&&"},
   393  		},
   394  		types.Time: {
   395  			string("==" + types.Nil):       {f: timeCmpNilV2, Label: "=="},
   396  			string("!=" + types.Nil):       {f: timeNotNilV2, Label: "!="},
   397  			string("==" + types.Empty):     {f: timeCmpNilV2, Label: "=="},
   398  			string("!=" + types.Empty):     {f: timeNotNilV2, Label: "!="},
   399  			string("==" + types.Time):      {f: timeCmpTimeV2, Label: "=="},
   400  			string("!=" + types.Time):      {f: timeNotTimeV2, Label: "!="},
   401  			string("<" + types.Time):       {f: timeLTTimeV2, Label: "<"},
   402  			string("<=" + types.Time):      {f: timeLTETimeV2, Label: "<="},
   403  			string(">" + types.Time):       {f: timeGTTimeV2, Label: ">"},
   404  			string(">=" + types.Time):      {f: timeGTETimeV2, Label: ">="},
   405  			string("&&" + types.Bool):      {f: timeAndBoolV2, Label: "&&"},
   406  			string("||" + types.Bool):      {f: timeOrBoolV2, Label: "||"},
   407  			string("&&" + types.Int):       {f: timeAndIntV2, Label: "&&"},
   408  			string("||" + types.Int):       {f: timeOrIntV2, Label: "||"},
   409  			string("&&" + types.Float):     {f: timeAndFloatV2, Label: "&&"},
   410  			string("||" + types.Float):     {f: timeOrFloatV2, Label: "||"},
   411  			string("&&" + types.String):    {f: timeAndStringV2, Label: "&&"},
   412  			string("||" + types.String):    {f: timeOrStringV2, Label: "||"},
   413  			string("&&" + types.Regex):     {f: timeAndRegexV2, Label: "&&"},
   414  			string("||" + types.Regex):     {f: timeOrRegexV2, Label: "||"},
   415  			string("&&" + types.Time):      {f: timeAndTimeV2, Label: "&&"},
   416  			string("||" + types.Time):      {f: timeOrTimeV2, Label: "||"},
   417  			string("&&" + types.Dict):      {f: timeAndDictV2, Label: "&&"},
   418  			string("||" + types.Dict):      {f: timeOrDictV2, Label: "||"},
   419  			string("&&" + types.ArrayLike): {f: timeAndArrayV2, Label: "&&"},
   420  			string("||" + types.ArrayLike): {f: timeOrArrayV2, Label: "||"},
   421  			string("&&" + types.MapLike):   {f: timeAndMapV2, Label: "&&"},
   422  			string("||" + types.MapLike):   {f: timeOrMapV2, Label: "||"},
   423  			string("-" + types.Time):       {f: timeMinusTimeV2, Label: "-"},
   424  			string("+" + types.Time):       {f: timePlusTimeV2, Label: "+"},
   425  			string("*" + types.Int):        {f: timeTimesIntV2, Label: "*", Typ: types.Time},
   426  			string("*" + types.Float):      {f: timeTimesFloatV2, Label: "*", Typ: types.Time},
   427  			string("*" + types.Dict):       {f: timeTimesDictV2, Label: "*", Typ: types.Time},
   428  			// fields
   429  			string("seconds"): {f: timeSecondsV2, Label: "seconds"},
   430  			string("minutes"): {f: timeMinutesV2, Label: "minutes"},
   431  			string("hours"):   {f: timeHoursV2, Label: "hours"},
   432  			string("days"):    {f: timeDaysV2, Label: "days"},
   433  			string("unix"):    {f: timeUnixV2, Label: "unix"},
   434  		},
   435  		types.Dict: {
   436  			string("==" + types.Nil):                 {f: dictCmpNilV2, Label: "=="},
   437  			string("!=" + types.Nil):                 {f: dictNotNilV2, Label: "!="},
   438  			string("==" + types.Empty):               {f: dictCmpEmpty, Label: "=="},
   439  			string("!=" + types.Empty):               {f: dictNotEmpty, Label: "!="},
   440  			string("==" + types.Bool):                {f: dictCmpBoolV2, Label: "=="},
   441  			string("!=" + types.Bool):                {f: dictNotBoolV2, Label: "!="},
   442  			string("==" + types.Int):                 {f: dictCmpIntV2, Label: "=="},
   443  			string("!=" + types.Int):                 {f: dictNotIntV2, Label: "!="},
   444  			string("==" + types.Float):               {f: dictCmpFloatV2, Label: "=="},
   445  			string("!=" + types.Float):               {f: dictNotFloatV2, Label: "!="},
   446  			string("==" + types.Dict):                {f: dictCmpDictV2, Label: "=="},
   447  			string("!=" + types.Dict):                {f: dictNotDictV2, Label: "!="},
   448  			string("==" + types.String):              {f: dictCmpStringV2, Label: "=="},
   449  			string("!=" + types.String):              {f: dictNotStringV2, Label: "!="},
   450  			string("==" + types.Regex):               {f: dictCmpRegexV2, Label: "=="},
   451  			string("!=" + types.Regex):               {f: dictNotRegexV2, Label: "!="},
   452  			string("==" + types.ArrayLike):           {f: dictCmpArrayV2, Label: "=="},
   453  			string("!=" + types.ArrayLike):           {f: dictNotArrayV2, Label: "!="},
   454  			string("==" + types.Array(types.String)): {f: dictCmpStringarrayV2, Label: "=="},
   455  			string("!=" + types.Array(types.String)): {f: dictNotStringarrayV2, Label: "!="},
   456  			string("==" + types.Array(types.Bool)):   {f: dictCmpBoolarrayV2, Label: "=="},
   457  			string("!=" + types.Array(types.Bool)):   {f: dictNotBoolarrayV2, Label: "!="},
   458  			string("==" + types.Array(types.Int)):    {f: dictCmpIntarrayV2, Label: "=="},
   459  			string("!=" + types.Array(types.Int)):    {f: dictNotIntarrayV2, Label: "!="},
   460  			string("==" + types.Array(types.Float)):  {f: dictCmpFloatarrayV2, Label: "=="},
   461  			string("!=" + types.Array(types.Float)):  {f: dictNotFloatarrayV2, Label: "!="},
   462  			string("<" + types.Int):                  {f: dictLTIntV2, Label: "<"},
   463  			string("<=" + types.Int):                 {f: dictLTEIntV2, Label: "<="},
   464  			string(">" + types.Int):                  {f: dictGTIntV2, Label: ">"},
   465  			string(">=" + types.Int):                 {f: dictGTEIntV2, Label: ">="},
   466  			string("<" + types.Float):                {f: dictLTFloatV2, Label: "<"},
   467  			string("<=" + types.Float):               {f: dictLTEFloatV2, Label: "<="},
   468  			string(">" + types.Float):                {f: dictGTFloatV2, Label: ">"},
   469  			string(">=" + types.Float):               {f: dictGTEFloatV2, Label: ">="},
   470  			string("<" + types.String):               {f: dictLTStringV2, Label: "<"},
   471  			string("<=" + types.String):              {f: dictLTEStringV2, Label: "<="},
   472  			string(">" + types.String):               {f: dictGTStringV2, Label: ">"},
   473  			string(">=" + types.String):              {f: dictGTEStringV2, Label: ">="},
   474  			string("<" + types.Dict):                 {f: dictLTDictV2, Label: "<"},
   475  			string("<=" + types.Dict):                {f: dictLTEDictV2, Label: "<="},
   476  			string(">" + types.Dict):                 {f: dictGTDictV2, Label: ">"},
   477  			string(">=" + types.Dict):                {f: dictGTEDictV2, Label: ">="},
   478  			string("&&" + types.Bool):                {f: dictAndBoolV2, Label: "&&"},
   479  			string("||" + types.Bool):                {f: dictOrBoolV2, Label: "||"},
   480  			string("&&" + types.Int):                 {f: dictAndIntV2, Label: "&&"},
   481  			string("||" + types.Int):                 {f: dictOrIntV2, Label: "||"},
   482  			string("&&" + types.Float):               {f: dictAndFloatV2, Label: "&&"},
   483  			string("||" + types.Float):               {f: dictOrFloatV2, Label: "||"},
   484  			string("&&" + types.String):              {f: dictAndStringV2, Label: "&&"},
   485  			string("||" + types.String):              {f: dictOrStringV2, Label: "||"},
   486  			string("&&" + types.Regex):               {f: dictAndRegexV2, Label: "&&"},
   487  			string("||" + types.Regex):               {f: dictOrRegexV2, Label: "||"},
   488  			string("&&" + types.Time):                {f: dictAndTimeV2, Label: "&&"},
   489  			string("||" + types.Time):                {f: dictOrTimeV2, Label: "||"},
   490  			string("&&" + types.Dict):                {f: dictAndDictV2, Label: "&&"},
   491  			string("||" + types.Dict):                {f: dictOrDictV2, Label: "||"},
   492  			string("&&" + types.ArrayLike):           {f: dictAndArrayV2, Label: "&&"},
   493  			string("||" + types.ArrayLike):           {f: dictOrArrayV2, Label: "||"},
   494  			string("&&" + types.MapLike):             {f: dictAndMapV2, Label: "&&"},
   495  			string("||" + types.MapLike):             {f: dictOrMapV2, Label: "||"},
   496  			string("+" + types.String):               {f: dictPlusStringV2, Label: "+"},
   497  			string("+" + types.Int):                  {f: dictPlusIntV2, Label: "+"},
   498  			string("-" + types.Int):                  {f: dictMinusIntV2, Label: "-"},
   499  			string("*" + types.Int):                  {f: dictTimesIntV2, Label: "*"},
   500  			string("/" + types.Int):                  {f: dictDividedIntV2, Label: "/"},
   501  			string("+" + types.Float):                {f: dictPlusFloatV2, Label: "+"},
   502  			string("-" + types.Float):                {f: dictMinusFloatV2, Label: "-"},
   503  			string("*" + types.Float):                {f: dictTimesFloatV2, Label: "*"},
   504  			string("/" + types.Float):                {f: dictDividedFloatV2, Label: "/"},
   505  			string("*" + types.Time):                 {f: dictTimesTimeV2, Label: "*"},
   506  			// fields
   507  			"[]":                              {f: dictGetIndexV2},
   508  			"first":                           {f: dictGetFirstIndexV2},
   509  			"last":                            {f: dictGetLastIndexV2},
   510  			"{}":                              {f: dictBlockCallV2},
   511  			"length":                          {f: dictLengthV2},
   512  			"camelcase":                       {f: dictCamelcaseV2, Label: "camelcase"},
   513  			"downcase":                        {f: dictDowncaseV2, Label: "downcase"},
   514  			"upcase":                          {f: dictUpcaseV2, Label: "upcase"},
   515  			"lines":                           {f: dictLinesV2, Label: "lines"},
   516  			"split":                           {f: dictSplitV2, Label: "split"},
   517  			"trim":                            {f: dictTrimV2, Label: "trim"},
   518  			"keys":                            {f: dictKeysV2, Label: "keys"},
   519  			"values":                          {f: dictValuesV2, Label: "values"},
   520  			"where":                           {f: dictWhereV2, Label: "where"},
   521  			"$whereNot":                       {f: dictWhereNotV2},
   522  			"$all":                            {f: dictAllV2},
   523  			"$none":                           {f: dictNoneV2},
   524  			"$any":                            {f: dictAnyV2},
   525  			"$one":                            {f: dictOneV2},
   526  			"map":                             {f: dictMapV2},
   527  			"flat":                            {f: dictFlat},
   528  			"difference":                      {f: dictDifferenceV2},
   529  			"containsNone":                    {f: dictContainsNoneV2},
   530  			string("contains" + types.String): {f: dictContainsStringV2, Label: "contains"},
   531  			string("contains" + types.Array(types.String)): {f: dictContainsArrayStringV2, Label: "contains"},
   532  			string("contains" + types.Int):                 {f: dictContainsIntV2, Label: "contains"},
   533  			string("contains" + types.Array(types.Int)):    {f: dictContainsArrayIntV2, Label: "contains"},
   534  			string("contains" + types.Regex):               {f: dictContainsRegex, Label: "contains"},
   535  			string("contains" + types.Array(types.Regex)):  {f: dictContainsArrayRegex, Label: "contains"},
   536  			string("find"): {f: dictFindV2, Label: "find"},
   537  			// NOTE: the following functions are internal ONLY!
   538  			// We have not yet decided if and how these may be exposed to users
   539  			"notEmpty": {f: dictNotEmptyV2},
   540  		},
   541  		types.ArrayLike: {
   542  			"[]":                       {f: arrayGetIndexV2},
   543  			"first":                    {f: arrayGetFirstIndexV2},
   544  			"last":                     {f: arrayGetLastIndexV2},
   545  			"{}":                       {f: arrayBlockListV2},
   546  			"${}":                      {f: arrayBlockV2},
   547  			"length":                   {f: arrayLengthV2},
   548  			"where":                    {f: arrayWhereV2},
   549  			"$whereNot":                {f: arrayWhereNotV2},
   550  			"$all":                     {f: arrayAllV2},
   551  			"$none":                    {f: arrayNoneV2},
   552  			"$any":                     {f: arrayAnyV2},
   553  			"$one":                     {f: arrayOneV2},
   554  			"map":                      {f: arrayMapV2},
   555  			"flat":                     {f: arrayFlat},
   556  			"duplicates":               {f: arrayDuplicatesV2},
   557  			"fieldDuplicates":          {f: arrayFieldDuplicatesV2},
   558  			"unique":                   {f: arrayUniqueV2},
   559  			"difference":               {f: arrayDifferenceV2},
   560  			"containsNone":             {f: arrayContainsNoneV2},
   561  			"==":                       {Compiler: compileArrayOpArray("=="), f: tarrayCmpTarrayV2, Label: "=="},
   562  			"!=":                       {Compiler: compileArrayOpArray("!="), f: tarrayNotTarrayV2, Label: "!="},
   563  			"==" + string(types.Nil):   {f: arrayCmpNilV2},
   564  			"!=" + string(types.Nil):   {f: arrayNotNilV2},
   565  			"==" + string(types.Empty): {f: arrayCmpEmpty},
   566  			"!=" + string(types.Empty): {f: arrayNotEmpty},
   567  			"&&":                       {Compiler: compileLogicalArrayOp(types.ArrayLike, "&&")},
   568  			"||":                       {Compiler: compileLogicalArrayOp(types.ArrayLike, "||")},
   569  			"+":                        {Compiler: compileArrayOpArray("+"), f: tarrayConcatTarrayV2, Label: "+"},
   570  			"-":                        {Compiler: compileArrayOpArray("-"), f: tarrayDeleteTarrayV2, Label: "-"},
   571  			// logical operations []<T> -- K
   572  			string(types.Any + "&&" + types.Bool):      {f: arrayAndBoolV2, Label: "&&"},
   573  			string(types.Any + "||" + types.Bool):      {f: arrayOrBoolV2, Label: "||"},
   574  			string(types.Any + "&&" + types.Int):       {f: arrayAndIntV2, Label: "&&"},
   575  			string(types.Any + "||" + types.Int):       {f: arrayOrIntV2, Label: "||"},
   576  			string(types.Any + "&&" + types.Float):     {f: arrayAndFloatV2, Label: "&&"},
   577  			string(types.Any + "||" + types.Float):     {f: arrayOrFloatV2, Label: "||"},
   578  			string(types.Any + "&&" + types.String):    {f: arrayAndStringV2, Label: "&&"},
   579  			string(types.Any + "||" + types.String):    {f: arrayOrStringV2, Label: "||"},
   580  			string(types.Any + "&&" + types.Regex):     {f: arrayAndRegexV2, Label: "&&"},
   581  			string(types.Any + "||" + types.Regex):     {f: arrayOrRegexV2, Label: "||"},
   582  			string(types.Any + "&&" + types.ArrayLike): {f: arrayAndArrayV2, Label: "&&"},
   583  			string(types.Any + "||" + types.ArrayLike): {f: arrayOrArrayV2, Label: "||"},
   584  			string(types.Any + "&&" + types.MapLike):   {f: arrayAndMapV2, Label: "&&"},
   585  			string(types.Any + "||" + types.MapLike):   {f: arrayOrMapV2, Label: "||"},
   586  			// []T -- []T
   587  			string(types.Bool + "==" + types.Array(types.Bool)):     {f: boolarrayCmpBoolarrayV2, Label: "=="},
   588  			string(types.Bool + "!=" + types.Array(types.Bool)):     {f: boolarrayNotBoolarrayV2, Label: "!="},
   589  			string(types.Int + "==" + types.Array(types.Int)):       {f: intarrayCmpIntarrayV2, Label: "=="},
   590  			string(types.Int + "!=" + types.Array(types.Int)):       {f: intarrayNotIntarrayV2, Label: "!="},
   591  			string(types.Float + "==" + types.Array(types.Float)):   {f: floatarrayCmpFloatarrayV2, Label: "=="},
   592  			string(types.Float + "!=" + types.Array(types.Float)):   {f: floatarrayNotFloatarrayV2, Label: "!="},
   593  			string(types.String + "==" + types.Array(types.String)): {f: stringarrayCmpStringarrayV2, Label: "=="},
   594  			string(types.String + "!=" + types.Array(types.String)): {f: stringarrayNotStringarrayV2, Label: "!="},
   595  			string(types.Regex + "==" + types.Array(types.Regex)):   {f: stringarrayCmpStringarrayV2, Label: "=="},
   596  			string(types.Regex + "!=" + types.Array(types.Regex)):   {f: stringarrayNotStringarrayV2, Label: "!="},
   597  			// []T -- T
   598  			string(types.Bool + "==" + types.Bool):     {f: boolarrayCmpBoolV2, Label: "=="},
   599  			string(types.Bool + "!=" + types.Bool):     {f: boolarrayNotBoolV2, Label: "!="},
   600  			string(types.Int + "==" + types.Int):       {f: intarrayCmpIntV2, Label: "=="},
   601  			string(types.Int + "!=" + types.Int):       {f: intarrayNotIntV2, Label: "!="},
   602  			string(types.Float + "==" + types.Float):   {f: floatarrayCmpFloatV2, Label: "=="},
   603  			string(types.Float + "!=" + types.Float):   {f: floatarrayNotFloatV2, Label: "!="},
   604  			string(types.String + "==" + types.String): {f: stringarrayCmpStringV2, Label: "=="},
   605  			string(types.String + "!=" + types.String): {f: stringarrayNotStringV2, Label: "!="},
   606  			string(types.Regex + "==" + types.Regex):   {f: stringarrayCmpStringV2, Label: "=="},
   607  			string(types.Regex + "!=" + types.Regex):   {f: stringarrayNotStringV2, Label: "!="},
   608  			// []int/float
   609  			string(types.Int + "==" + types.Float): {f: intarrayCmpFloatV2, Label: "=="},
   610  			string(types.Int + "!=" + types.Float): {f: intarrayNotFloatV2, Label: "!="},
   611  			string(types.Float + "==" + types.Int): {f: floatarrayCmpIntV2, Label: "=="},
   612  			string(types.Float + "!=" + types.Int): {f: floatarrayNotIntV2, Label: "!="},
   613  			// []string -- T
   614  			string(types.String + "==" + types.Bool):  {f: stringarrayCmpBoolV2, Label: "=="},
   615  			string(types.String + "!=" + types.Bool):  {f: stringarrayNotBoolV2, Label: "!="},
   616  			string(types.String + "==" + types.Int):   {f: stringarrayCmpIntV2, Label: "=="},
   617  			string(types.String + "!=" + types.Int):   {f: stringarrayNotIntV2, Label: "!="},
   618  			string(types.String + "==" + types.Float): {f: stringarrayCmpFloatV2, Label: "=="},
   619  			string(types.String + "!=" + types.Float): {f: stringarrayNotFloatV2, Label: "!="},
   620  			// []T -- string
   621  			string(types.Bool + "==" + types.String):  {f: boolarrayCmpStringV2, Label: "=="},
   622  			string(types.Bool + "!=" + types.String):  {f: boolarrayNotStringV2, Label: "!="},
   623  			string(types.Int + "==" + types.String):   {f: intarrayCmpStringV2, Label: "=="},
   624  			string(types.Int + "!=" + types.String):   {f: intarrayNotStringV2, Label: "!="},
   625  			string(types.Float + "==" + types.String): {f: floatarrayCmpStringV2, Label: "=="},
   626  			string(types.Float + "!=" + types.String): {f: floatarrayNotStringV2, Label: "!="},
   627  			// []T -- regex
   628  			string(types.Int + "==" + types.Regex):    {f: intarrayCmpRegexV2, Label: "=="},
   629  			string(types.Int + "!=" + types.Regex):    {f: intarrayNotRegexV2, Label: "!="},
   630  			string(types.Float + "==" + types.Regex):  {f: floatarrayCmpRegexV2, Label: "=="},
   631  			string(types.Float + "!=" + types.Regex):  {f: floatarrayNotRegexV2, Label: "!="},
   632  			string(types.String + "==" + types.Regex): {f: stringarrayCmpRegexV2, Label: "=="},
   633  			string(types.String + "!=" + types.Regex): {f: stringarrayNotRegexV2, Label: "!="},
   634  			// NOTE: the following functions are internal ONLY!
   635  			// We have not yet decided if and how these may be exposed to users
   636  			"notEmpty": {f: arrayNotEmptyV2},
   637  		},
   638  		types.MapLike: {
   639  			"[]":                       {f: mapGetIndexV2},
   640  			"length":                   {f: mapLengthV2},
   641  			"where":                    {f: mapWhereV2},
   642  			"$whereNot":                {f: mapWhereNotV2},
   643  			"{}":                       {f: mapBlockCallV2},
   644  			"keys":                     {f: mapKeysV2, Label: "keys"},
   645  			"values":                   {f: mapValuesV2, Label: "values"},
   646  			"==" + string(types.Nil):   {f: mapCmpNil},
   647  			"!=" + string(types.Nil):   {f: mapNotNil},
   648  			"==" + string(types.Empty): {f: mapCmpEmpty},
   649  			"!=" + string(types.Empty): {f: mapNotEmpty},
   650  			// {}T -- T
   651  			string("&&" + types.Bool):      {f: chunkEqFalseV2, Label: "&&"},
   652  			string("||" + types.Bool):      {f: chunkNeqTrueV2, Label: "||"},
   653  			string("&&" + types.Int):       {f: mapAndIntV2, Label: "&&"},
   654  			string("||" + types.Int):       {f: mapOrIntV2, Label: "||"},
   655  			string("&&" + types.Float):     {f: mapAndFloatV2, Label: "&&"},
   656  			string("||" + types.Float):     {f: mapOrFloatV2, Label: "||"},
   657  			string("&&" + types.String):    {f: mapAndStringV2, Label: "&&"},
   658  			string("||" + types.String):    {f: mapOrStringV2, Label: "||"},
   659  			string("&&" + types.Regex):     {f: mapAndRegexV2, Label: "&&"},
   660  			string("||" + types.Regex):     {f: mapOrRegexV2, Label: "||"},
   661  			string("&&" + types.Time):      {f: mapAndTimeV2, Label: "&&"},
   662  			string("||" + types.Time):      {f: mapOrTimeV2, Label: "||"},
   663  			string("&&" + types.Dict):      {f: mapAndDictV2, Label: "&&"},
   664  			string("||" + types.Dict):      {f: mapOrDictV2, Label: "||"},
   665  			string("&&" + types.ArrayLike): {f: mapAndArrayV2, Label: "&&"},
   666  			string("||" + types.ArrayLike): {f: mapOrArrayV2, Label: "||"},
   667  			string("&&" + types.MapLike):   {f: mapAndMapV2, Label: "&&"},
   668  			string("||" + types.MapLike):   {f: mapOrMapV2, Label: "||"},
   669  		},
   670  		types.ResourceLike: {
   671  			// == / !=
   672  			string("==" + types.Nil): {f: bindingEqNil, Label: "=="},
   673  			string("!=" + types.Nil): {f: bindingNeqNil, Label: "!="},
   674  			// TODO: correctly implement this for list type resources
   675  			string("==" + types.Empty): {f: bindingEqNil, Label: "=="},
   676  			string("!=" + types.Empty): {f: bindingNeqNil, Label: "!="},
   677  			// fields
   678  			"where":     {f: resourceWhereV2},
   679  			"$whereNot": {f: resourceWhereNotV2},
   680  			"map":       {f: resourceMapV2},
   681  			"length":    {f: resourceLengthV2},
   682  			"{}": {f: func(e *blockExecutor, bind *RawData, chunk *Chunk, ref uint64) (*RawData, uint64, error) {
   683  				return e.runBlock(bind, chunk.Function.Args[0], chunk.Function.Args[1:], ref)
   684  			}},
   685  			// TODO: [#32] unique builtin fields that need a long-term support in LR
   686  			string(types.Resource("parse") + ".date"): {f: resourceDateV2},
   687  		},
   688  	}
   689  
   690  	validateBuiltinFunctionsV2()
   691  }
   692  
   693  func validateBuiltinFunctionsV2() {
   694  	missing := []string{}
   695  
   696  	// dict must have all string methods supported
   697  	dictFun := BuiltinFunctionsV2[types.Dict]
   698  	if dictFun == nil {
   699  		dictFun = map[string]chunkHandlerV2{}
   700  	}
   701  
   702  	stringFun := BuiltinFunctionsV2[types.String]
   703  	if stringFun == nil {
   704  		stringFun = map[string]chunkHandlerV2{}
   705  	}
   706  
   707  	for id := range stringFun {
   708  		if _, ok := dictFun[id]; !ok {
   709  			missing = append(missing, fmt.Sprintf("dict> missing dict counterpart of string function %#v", id))
   710  		}
   711  	}
   712  
   713  	// finalize
   714  	if len(missing) == 0 {
   715  		return
   716  	}
   717  	fmt.Println("Missing functions:")
   718  	for _, msg := range missing {
   719  		fmt.Println(msg)
   720  	}
   721  	panic("missing functions must be added")
   722  }
   723  
   724  func runResourceFunction(e *blockExecutor, bind *RawData, chunk *Chunk, ref uint64) (*RawData, uint64, error) {
   725  	rr, ok := bind.Value.(Resource)
   726  	if !ok {
   727  		// TODO: can we get rid of this fmt call
   728  		return nil, 0, fmt.Errorf("cannot cast resource to resource type: %+v", bind.Value)
   729  	}
   730  
   731  	resource := e.ctx.runtime.Schema().Lookup(rr.MqlName())
   732  	if resource == nil {
   733  		return nil, 0, fmt.Errorf("cannot retrieve resource definition for resource %q", rr.MqlName())
   734  	}
   735  
   736  	// record this watcher on the executors watcher IDs
   737  	wid := e.watcherUID(ref)
   738  	// log.Debug().Str("wid", wid).Msg("exec> add watcher id ")
   739  	e.watcherIds.Store(wid)
   740  
   741  	// watch this field in the resource
   742  	err := e.ctx.runtime.WatchAndUpdate(rr, chunk.Id, wid, func(fieldData interface{}, fieldError error) {
   743  		data := &RawData{
   744  			Type:  types.Type(resource.Fields[chunk.Id].Type),
   745  			Value: fieldData,
   746  			Error: fieldError,
   747  		}
   748  		e.cache.Store(ref, &stepCache{
   749  			Result: data,
   750  		})
   751  
   752  		codeID, ok := e.callbackPoints[ref]
   753  		if ok {
   754  			e.callback(&RawResult{Data: data, CodeID: codeID})
   755  		}
   756  
   757  		if fieldError != nil {
   758  			e.triggerChainError(ref, fieldError)
   759  		}
   760  
   761  		e.triggerChain(ref, data)
   762  	})
   763  	if err != nil {
   764  		if _, ok := err.(resources.NotReadyError); !ok {
   765  			fieldType := types.Unset
   766  			if field := resource.Fields[chunk.Id]; field != nil {
   767  				fieldType = types.Type(field.Type)
   768  			}
   769  
   770  			e.cache.Store(ref, &stepCache{
   771  				Result: &RawData{
   772  					Type:  fieldType,
   773  					Value: nil,
   774  					Error: err,
   775  				},
   776  			})
   777  		}
   778  	}
   779  
   780  	// we are done executing this chain
   781  	return nil, 0, err
   782  }
   783  
   784  // BuiltinFunction provides the handler for this type's function
   785  func BuiltinFunctionV2(typ types.Type, name string) (*chunkHandlerV2, error) {
   786  	h, ok := BuiltinFunctionsV2[typ.Underlying()]
   787  	if !ok {
   788  		return nil, errors.New("cannot find functions for type '" + typ.Label() + "' (called '" + name + "')")
   789  	}
   790  	fh, ok := h[name]
   791  	if !ok {
   792  		return nil, errors.New("cannot find function '" + name + "' for type '" + typ.Label() + "'")
   793  	}
   794  	return &fh, nil
   795  }
   796  
   797  // this is called for objects that call a function
   798  func (e *blockExecutor) runBoundFunction(bind *RawData, chunk *Chunk, ref uint64) (*RawData, uint64, error) {
   799  	log.Trace().Uint64("ref", ref).Str("id", chunk.Id).Msg("exec> run bound function")
   800  
   801  	fh, err := BuiltinFunctionV2(bind.Type, chunk.Id)
   802  	if err == nil {
   803  		res, dref, err := fh.f(e, bind, chunk, ref)
   804  		if res != nil {
   805  			e.cache.Store(ref, &stepCache{Result: res})
   806  		}
   807  		if err != nil {
   808  			e.cache.Store(ref, &stepCache{Result: &RawData{
   809  				Error: err,
   810  			}})
   811  		}
   812  		return res, dref, err
   813  	}
   814  
   815  	if bind.Type.IsResource() {
   816  		return runResourceFunction(e, bind, chunk, ref)
   817  	}
   818  	return nil, 0, err
   819  }