...

Source file src/github.com/PaesslerAG/gval/gval_noparameter_test.go

Documentation: github.com/PaesslerAG/gval

     1  package gval
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  	"text/scanner"
     8  )
     9  
    10  func TestNoParameter(t *testing.T) {
    11  	testEvaluate(
    12  		[]evaluationTest{
    13  			{
    14  				name:       "Number",
    15  				expression: "100",
    16  				want:       100.0,
    17  			},
    18  			{
    19  				name:       "Single PLUS",
    20  				expression: "51 + 49",
    21  				want:       100.0,
    22  			},
    23  			{
    24  				name:       "Single MINUS",
    25  				expression: "100 - 51",
    26  				want:       49.0,
    27  			},
    28  			{
    29  				name:       "Single BITWISE AND",
    30  				expression: "100 & 50",
    31  				want:       32.0,
    32  			},
    33  			{
    34  				name:       "Single BITWISE OR",
    35  				expression: "100 | 50",
    36  				want:       118.0,
    37  			},
    38  			{
    39  				name:       "Single BITWISE XOR",
    40  				expression: "100 ^ 50",
    41  				want:       86.0,
    42  			},
    43  			{
    44  				name:       "Single shift left",
    45  				expression: "2 << 1",
    46  				want:       4.0,
    47  			},
    48  			{
    49  				name:       "Single shift right",
    50  				expression: "2 >> 1",
    51  				want:       1.0,
    52  			},
    53  			{
    54  				name:       "Single BITWISE NOT",
    55  				expression: "~10",
    56  				want:       -11.0,
    57  			},
    58  			{
    59  
    60  				name:       "Single MULTIPLY",
    61  				expression: "5 * 20",
    62  				want:       100.0,
    63  			},
    64  			{
    65  
    66  				name:       "Single DIVIDE",
    67  				expression: "100 / 20",
    68  				want:       5.0,
    69  			},
    70  			{
    71  
    72  				name:       "Single even MODULUS",
    73  				expression: "100 % 2",
    74  				want:       0.0,
    75  			},
    76  			{
    77  				name:       "Single odd MODULUS",
    78  				expression: "101 % 2",
    79  				want:       1.0,
    80  			},
    81  			{
    82  
    83  				name:       "Single EXPONENT",
    84  				expression: "10 ** 2",
    85  				want:       100.0,
    86  			},
    87  			{
    88  
    89  				name:       "Compound PLUS",
    90  				expression: "20 + 30 + 50",
    91  				want:       100.0,
    92  			},
    93  			{
    94  
    95  				name:       "Compound BITWISE AND",
    96  				expression: "20 & 30 & 50",
    97  				want:       16.0,
    98  			},
    99  			{
   100  				name:       "Mutiple operators",
   101  				expression: "20 * 5 - 49",
   102  				want:       51.0,
   103  			},
   104  			{
   105  				name:       "Parenthesis usage",
   106  				expression: "100 - (5 * 10)",
   107  				want:       50.0,
   108  			},
   109  			{
   110  
   111  				name:       "Nested parentheses",
   112  				expression: "50 + (5 * (15 - 5))",
   113  				want:       100.0,
   114  			},
   115  			{
   116  
   117  				name:       "Nested parentheses with bitwise",
   118  				expression: "100 ^ (23 * (2 | 5))",
   119  				want:       197.0,
   120  			},
   121  			{
   122  				name:       "Logical OR operation of two clauses",
   123  				expression: "(1 == 1) || (true == true)",
   124  				want:       true,
   125  			},
   126  			{
   127  				name:       "Logical AND operation of two clauses",
   128  				expression: "(1 == 1) && (true == true)",
   129  				want:       true,
   130  			},
   131  			{
   132  
   133  				name:       "Implicit boolean",
   134  				expression: "2 > 1",
   135  				want:       true,
   136  			},
   137  			{
   138  				name:       "Equal test minus numbers and no spaces",
   139  				expression: "-1==-1",
   140  				want:       true,
   141  			},
   142  			{
   143  
   144  				name:       "Compound boolean",
   145  				expression: "5 < 10 && 1 < 5",
   146  				want:       true,
   147  			},
   148  			{
   149  				name:       "Evaluated true && false operation (for issue #8)",
   150  				expression: "1 > 10 && 11 > 10",
   151  				want:       false,
   152  			},
   153  			{
   154  
   155  				name:       "Evaluated true && false operation (for issue #8)",
   156  				expression: "true == true && false == true",
   157  				want:       false,
   158  			},
   159  			{
   160  
   161  				name:       "Parenthesis boolean",
   162  				expression: "10 < 50 && (1 != 2 && 1 > 0)",
   163  				want:       true,
   164  			},
   165  			{
   166  				name:       "Comparison of string constants",
   167  				expression: `"foo" == "foo"`,
   168  				want:       true,
   169  			},
   170  			{
   171  
   172  				name:       "NEQ comparison of string constants",
   173  				expression: `"foo" != "bar"`,
   174  				want:       true,
   175  			},
   176  			{
   177  
   178  				name:       "REQ comparison of string constants",
   179  				expression: `"foobar" =~ "oba"`,
   180  				want:       true,
   181  			},
   182  			{
   183  
   184  				name:       "NREQ comparison of string constants",
   185  				expression: `"foo" !~ "bar"`,
   186  				want:       true,
   187  			},
   188  			{
   189  
   190  				name:       "Multiplicative/additive order",
   191  				expression: "5 + 10 * 2",
   192  				want:       25.0,
   193  			},
   194  			{
   195  				name:       "Multiple constant multiplications",
   196  				expression: "10 * 10 * 10",
   197  				want:       1000.0,
   198  			},
   199  			{
   200  
   201  				name:       "Multiple adds/multiplications",
   202  				expression: "10 * 10 * 10 + 1 * 10 * 10",
   203  				want:       1100.0,
   204  			},
   205  			{
   206  
   207  				name:       "Modulus operatorPrecedence",
   208  				expression: "1 + 101 % 2 * 5",
   209  				want:       6.0,
   210  			},
   211  			{
   212  				name:       "Exponent operatorPrecedence",
   213  				expression: "1 + 5 ** 3 % 2 * 5",
   214  				want:       6.0,
   215  			},
   216  			{
   217  
   218  				name:       "Bit shift operatorPrecedence",
   219  				expression: "50 << 1 & 90",
   220  				want:       64.0,
   221  			},
   222  			{
   223  
   224  				name:       "Bit shift operatorPrecedence",
   225  				expression: "90 & 50 << 1",
   226  				want:       64.0,
   227  			},
   228  			{
   229  
   230  				name:       "Bit shift operatorPrecedence amongst non-bitwise",
   231  				expression: "90 + 50 << 1 * 5",
   232  				want:       4480.0,
   233  			},
   234  			{
   235  				name:       "Order of non-commutative same-operatorPrecedence operators (additive)",
   236  				expression: "1 - 2 - 4 - 8",
   237  				want:       -13.0,
   238  			},
   239  			{
   240  				name:       "Order of non-commutative same-operatorPrecedence operators (multiplicative)",
   241  				expression: "1 * 4 / 2 * 8",
   242  				want:       16.0,
   243  			},
   244  			{
   245  				name:       "Null coalesce operatorPrecedence",
   246  				expression: "true ?? true ? 100 + 200 : 400",
   247  				want:       300.0,
   248  			},
   249  			{
   250  				name:       "Identical date equivalence",
   251  				expression: `"2014-01-02 14:12:22" == "2014-01-02 14:12:22"`,
   252  				want:       true,
   253  			},
   254  			{
   255  				name:       "Positive date GT",
   256  				expression: `"2014-01-02 14:12:22" > "2014-01-02 12:12:22"`,
   257  				want:       true,
   258  			},
   259  			{
   260  				name:       "Negative date GT",
   261  				expression: `"2014-01-02 14:12:22" > "2014-01-02 16:12:22"`,
   262  				want:       false,
   263  			},
   264  			{
   265  				name:       "Positive date GTE",
   266  				expression: `"2014-01-02 14:12:22" >= "2014-01-02 12:12:22"`,
   267  				want:       true,
   268  			},
   269  			{
   270  				name:       "Negative date GTE",
   271  				expression: `"2014-01-02 14:12:22" >= "2014-01-02 16:12:22"`,
   272  				want:       false,
   273  			},
   274  			{
   275  				name:       "Positive date LT",
   276  				expression: `"2014-01-02 14:12:22" < "2014-01-02 16:12:22"`,
   277  				want:       true,
   278  			},
   279  			{
   280  
   281  				name:       "Negative date LT",
   282  				expression: `"2014-01-02 14:12:22" < "2014-01-02 11:12:22"`,
   283  				want:       false,
   284  			},
   285  			{
   286  
   287  				name:       "Positive date LTE",
   288  				expression: `"2014-01-02 09:12:22" <= "2014-01-02 12:12:22"`,
   289  				want:       true,
   290  			},
   291  			{
   292  				name:       "Negative date LTE",
   293  				expression: `"2014-01-02 14:12:22" <= "2014-01-02 11:12:22"`,
   294  				want:       false,
   295  			},
   296  			{
   297  
   298  				name:       "Sign prefix comparison",
   299  				expression: "-1 < 0",
   300  				want:       true,
   301  			},
   302  			{
   303  
   304  				name:       "Lexicographic LT",
   305  				expression: `"ab" < "abc"`,
   306  				want:       true,
   307  			},
   308  			{
   309  				name:       "Lexicographic LTE",
   310  				expression: `"ab" <= "abc"`,
   311  				want:       true,
   312  			},
   313  			{
   314  
   315  				name:       "Lexicographic GT",
   316  				expression: `"aba" > "abc"`,
   317  				want:       false,
   318  			},
   319  			{
   320  
   321  				name:       "Lexicographic GTE",
   322  				expression: `"aba" >= "abc"`,
   323  				want:       false,
   324  			},
   325  			{
   326  
   327  				name:       "Boolean sign prefix comparison",
   328  				expression: "!true == false",
   329  				want:       true,
   330  			},
   331  			{
   332  				name:       "Inversion of clause",
   333  				expression: "!(10 < 0)",
   334  				want:       true,
   335  			},
   336  			{
   337  
   338  				name:       "Negation after modifier",
   339  				expression: "10 * -10",
   340  				want:       -100.0,
   341  			},
   342  			{
   343  
   344  				name:       "Ternary with single boolean",
   345  				expression: "true ? 10",
   346  				want:       10.0,
   347  			},
   348  			{
   349  
   350  				name:       "Ternary nil with single boolean",
   351  				expression: "false ? 10",
   352  				want:       nil,
   353  			},
   354  			{
   355  				name:       "Ternary with comparator boolean",
   356  				expression: "10 > 5 ? 35.50",
   357  				want:       35.50,
   358  			},
   359  			{
   360  
   361  				name:       "Ternary nil with comparator boolean",
   362  				expression: "1 > 5 ? 35.50",
   363  				want:       nil,
   364  			},
   365  			{
   366  
   367  				name:       "Ternary with parentheses",
   368  				expression: "(5 * (15 - 5)) > 5 ? 35.50",
   369  				want:       35.50,
   370  			},
   371  			{
   372  
   373  				name:       "Ternary operatorPrecedence",
   374  				expression: "true ? 35.50 > 10",
   375  				want:       true,
   376  			},
   377  			{
   378  				name:       "Ternary-else",
   379  				expression: "false ? 35.50 : 50",
   380  				want:       50.0,
   381  			},
   382  			{
   383  
   384  				name:       "Ternary-else inside clause",
   385  				expression: "(false ? 5 : 35.50) > 10",
   386  				want:       true,
   387  			},
   388  			{
   389  
   390  				name:       "Ternary-else (true-case) inside clause",
   391  				expression: "(true ? 1 : 5) < 10",
   392  				want:       true,
   393  			},
   394  			{
   395  
   396  				name:       "Ternary-else before comparator (negative case)",
   397  				expression: "true ? 1 : 5 > 10",
   398  				want:       1.0,
   399  			},
   400  			{
   401  				name:       "Nested ternaries (#32)",
   402  				expression: "(2 == 2) ? 1 : (true ? 2 : 3)",
   403  				want:       1.0,
   404  			},
   405  			{
   406  
   407  				name:       "Nested ternaries, right case (#32)",
   408  				expression: "false ? 1 : (true ? 2 : 3)",
   409  				want:       2.0,
   410  			},
   411  			{
   412  
   413  				name:       "Doubly-nested ternaries (#32)",
   414  				expression: "true ? (false ? 1 : (false ? 2 : 3)) : (false ? 4 : 5)",
   415  				want:       3.0,
   416  			},
   417  			{
   418  
   419  				name:       "String to string concat",
   420  				expression: `"foo" + "bar" == "foobar"`,
   421  				want:       true,
   422  			},
   423  			{
   424  				name:       "String to float64 concat",
   425  				expression: `"foo" + 123 == "foo123"`,
   426  				want:       true,
   427  			},
   428  			{
   429  
   430  				name:       "Float64 to string concat",
   431  				expression: `123 + "bar" == "123bar"`,
   432  				want:       true,
   433  			},
   434  			{
   435  
   436  				name:       "String to date concat",
   437  				expression: `"foo" + "02/05/1970" == "foobar"`,
   438  				want:       false,
   439  			},
   440  			{
   441  
   442  				name:       "String to bool concat",
   443  				expression: `"foo" + true == "footrue"`,
   444  				want:       true,
   445  			},
   446  			{
   447  				name:       "Bool to string concat",
   448  				expression: `true + "bar" == "truebar"`,
   449  				want:       true,
   450  			},
   451  			{
   452  
   453  				name:       "Null coalesce left",
   454  				expression: "1 ?? 2",
   455  				want:       1.0,
   456  			},
   457  			{
   458  
   459  				name:       "Array membership literals",
   460  				expression: "1 in [1, 2, 3]",
   461  				want:       true,
   462  			},
   463  			{
   464  
   465  				name:       "Array membership literal with inversion",
   466  				expression: "!(1 in [1, 2, 3])",
   467  				want:       false,
   468  			},
   469  			{
   470  				name:       "Logical operator reordering (#30)",
   471  				expression: "(true && true) || (true && false)",
   472  				want:       true,
   473  			},
   474  			{
   475  
   476  				name:       "Logical operator reordering without parens (#30)",
   477  				expression: "true && true || true && false",
   478  				want:       true,
   479  			},
   480  			{
   481  
   482  				name:       "Logical operator reordering with multiple OR (#30)",
   483  				expression: "false || true && true || false",
   484  				want:       true,
   485  			},
   486  			{
   487  				name:       "Left-side multiple consecutive (should be reordered) operators",
   488  				expression: "(10 * 10 * 10) > 10",
   489  				want:       true,
   490  			},
   491  			{
   492  
   493  				name:       "Three-part non-paren logical op reordering (#44)",
   494  				expression: "false && true || true",
   495  				want:       true,
   496  			},
   497  			{
   498  
   499  				name:       "Three-part non-paren logical op reordering (#44), second one",
   500  				expression: "true || false && true",
   501  				want:       true,
   502  			},
   503  			{
   504  				name:       "Logical operator reordering without parens (#45)",
   505  				expression: "true && true || false && false",
   506  				want:       true,
   507  			},
   508  			{
   509  				name:       "Single function",
   510  				expression: "foo()",
   511  				extension: Function("foo", func(arguments ...interface{}) (interface{}, error) {
   512  					return true, nil
   513  				}),
   514  
   515  				want: true,
   516  			},
   517  			{
   518  				name:       "Func with argument",
   519  				expression: "passthrough(1)",
   520  				extension: Function("passthrough", func(arguments ...interface{}) (interface{}, error) {
   521  					return arguments[0], nil
   522  				}),
   523  				want: 1.0,
   524  			},
   525  			{
   526  				name:       "Func with arguments",
   527  				expression: "passthrough(1, 2)",
   528  				extension: Function("passthrough", func(arguments ...interface{}) (interface{}, error) {
   529  					return arguments[0].(float64) + arguments[1].(float64), nil
   530  				}),
   531  				want: 3.0,
   532  			},
   533  			{
   534  				name:       "Nested function with operatorPrecedence",
   535  				expression: "sum(1, sum(2, 3), 2 + 2, true ? 4 : 5)",
   536  				extension: Function("sum", func(arguments ...interface{}) (interface{}, error) {
   537  					sum := 0.0
   538  					for _, v := range arguments {
   539  						sum += v.(float64)
   540  					}
   541  					return sum, nil
   542  				}),
   543  				want: 14.0,
   544  			},
   545  			{
   546  				name:       "Empty function and modifier, compared",
   547  				expression: "numeric()-1 > 0",
   548  				extension: Function("numeric", func(arguments ...interface{}) (interface{}, error) {
   549  					return 2.0, nil
   550  				}),
   551  				want: true,
   552  			},
   553  			{
   554  				name:       "Empty function comparator",
   555  				expression: "numeric() > 0",
   556  				extension: Function("numeric", func(arguments ...interface{}) (interface{}, error) {
   557  					return 2.0, nil
   558  				}),
   559  				want: true,
   560  			},
   561  			{
   562  
   563  				name:       "Empty function logical operator",
   564  				expression: "success() && !false",
   565  				extension: Function("success", func(arguments ...interface{}) (interface{}, error) {
   566  					return true, nil
   567  				}),
   568  				want: true,
   569  			},
   570  			{
   571  				name:       "Empty function ternary",
   572  				expression: "nope() ? 1 : 2.0",
   573  				extension: Function("nope", func(arguments ...interface{}) (interface{}, error) {
   574  					return false, nil
   575  				}),
   576  				want: 2.0,
   577  			},
   578  			{
   579  
   580  				name:       "Empty function null coalesce",
   581  				expression: "null() ?? 2",
   582  				extension: Function("null", func(arguments ...interface{}) (interface{}, error) {
   583  					return nil, nil
   584  				}),
   585  				want: 2.0,
   586  			},
   587  			{
   588  				name:       "Empty function with prefix",
   589  				expression: "-ten()",
   590  				extension: Function("ten", func(arguments ...interface{}) (interface{}, error) {
   591  					return 10.0, nil
   592  				}),
   593  				want: -10.0,
   594  			},
   595  			{
   596  				name:       "Empty function as part of chain",
   597  				expression: "10 - numeric() - 2",
   598  				extension: Function("numeric", func(arguments ...interface{}) (interface{}, error) {
   599  					return 5.0, nil
   600  				}),
   601  				want: 3.0,
   602  			},
   603  			{
   604  				name:       "Empty function near separator",
   605  				expression: "10 in [1, 2, 3, ten(), 8]",
   606  				extension: Function("ten", func(arguments ...interface{}) (interface{}, error) {
   607  					return 10.0, nil
   608  				}),
   609  				want: true,
   610  			},
   611  			{
   612  				name:       "Enclosed empty function with modifier and comparator (#28)",
   613  				expression: "(ten() - 1) > 3",
   614  				extension: Function("ten", func(arguments ...interface{}) (interface{}, error) {
   615  					return 10.0, nil
   616  				}),
   617  				want: true,
   618  			},
   619  			{
   620  				name:       "Array",
   621  				expression: `[(ten() - 1) > 3, (ten() - 1),"hey"]`,
   622  				extension: Function("ten", func(arguments ...interface{}) (interface{}, error) {
   623  					return 10.0, nil
   624  				}),
   625  				want: []interface{}{true, 9., "hey"},
   626  			},
   627  			{
   628  				name:       "Object",
   629  				expression: `{1: (ten() - 1) > 3, 7 + ".X" : (ten() - 1),"hello" : "hey"}`,
   630  				extension: Function("ten", func(arguments ...interface{}) (interface{}, error) {
   631  					return 10.0, nil
   632  				}),
   633  				want: map[string]interface{}{"1": true, "7.X": 9., "hello": "hey"},
   634  			},
   635  			{
   636  				name:       "Object negativ value",
   637  				expression: `{1: -1,"hello" : "hey"}`,
   638  				want:       map[string]interface{}{"1": -1., "hello": "hey"},
   639  			},
   640  			{
   641  				name:       "Empty Array",
   642  				expression: `[]`,
   643  				want:       []interface{}{},
   644  			},
   645  			{
   646  				name:       "Empty Object",
   647  				expression: `{}`,
   648  				want:       map[string]interface{}{},
   649  			},
   650  			{
   651  				name:       "Variadic",
   652  				expression: `sum(1,2,3,4)`,
   653  				extension: Function("sum", func(arguments ...float64) (interface{}, error) {
   654  					sum := 0.
   655  					for _, a := range arguments {
   656  						sum += a
   657  					}
   658  					return sum, nil
   659  				}),
   660  				want: 10.0,
   661  			},
   662  			{
   663  				name:       "Ident Operator",
   664  				expression: `1 plus 1`,
   665  				extension: InfixNumberOperator("plus", func(a, b float64) (interface{}, error) {
   666  					return a + b, nil
   667  				}),
   668  				want: 2.0,
   669  			},
   670  			{
   671  				name:       "Postfix Operator",
   672  				expression: `4§`,
   673  				extension: PostfixOperator("§", func(_ context.Context, _ *Parser, eval Evaluable) (Evaluable, error) {
   674  					return func(ctx context.Context, parameter interface{}) (interface{}, error) {
   675  						i, err := eval.EvalInt(ctx, parameter)
   676  						if err != nil {
   677  							return nil, err
   678  						}
   679  						return fmt.Sprintf("§%d", i), nil
   680  					}, nil
   681  				}),
   682  				want: "§4",
   683  			},
   684  			{
   685  				name:       "Tabs as non-whitespace",
   686  				expression: "4\t5\t6",
   687  				extension: NewLanguage(
   688  					Init(func(ctx context.Context, p *Parser) (Evaluable, error) {
   689  						p.SetWhitespace('\n', '\r', ' ')
   690  						return p.ParseExpression(ctx)
   691  					}),
   692  					InfixNumberOperator("\t", func(a, b float64) (interface{}, error) {
   693  						return a * b, nil
   694  					}),
   695  				),
   696  				want: 120.0,
   697  			},
   698  			{
   699  				name:       "Handle all other prefixes",
   700  				expression: "^foo + $bar + &baz",
   701  				extension: DefaultExtension(func(ctx context.Context, p *Parser) (Evaluable, error) {
   702  					var mul int
   703  					switch p.TokenText() {
   704  					case "^":
   705  						mul = 1
   706  					case "$":
   707  						mul = 2
   708  					case "&":
   709  						mul = 3
   710  					}
   711  
   712  					switch p.Scan() {
   713  					case scanner.Ident:
   714  						return p.Const(mul * len(p.TokenText())), nil
   715  					default:
   716  						return nil, p.Expected("length multiplier", scanner.Ident)
   717  					}
   718  				}),
   719  				want: 18.0,
   720  			},
   721  			{
   722  				name:       "Embed languages",
   723  				expression: "left { 5 + 5 } right",
   724  				extension: func() Language {
   725  					step := func(ctx context.Context, p *Parser, cur Evaluable) (Evaluable, error) {
   726  						next, err := p.ParseExpression(ctx)
   727  						if err != nil {
   728  							return nil, err
   729  						}
   730  
   731  						return func(ctx context.Context, parameter interface{}) (interface{}, error) {
   732  							us, err := cur.EvalString(ctx, parameter)
   733  							if err != nil {
   734  								return nil, err
   735  							}
   736  
   737  							them, err := next.EvalString(ctx, parameter)
   738  							if err != nil {
   739  								return nil, err
   740  							}
   741  
   742  							return us + them, nil
   743  						}, nil
   744  					}
   745  
   746  					return NewLanguage(
   747  						Init(func(ctx context.Context, p *Parser) (Evaluable, error) {
   748  							p.SetWhitespace()
   749  							p.SetMode(0)
   750  
   751  							return p.ParseExpression(ctx)
   752  						}),
   753  						DefaultExtension(func(ctx context.Context, p *Parser) (Evaluable, error) {
   754  							return step(ctx, p, p.Const(p.TokenText()))
   755  						}),
   756  						PrefixExtension(scanner.EOF, func(ctx context.Context, p *Parser) (Evaluable, error) {
   757  							return p.Const(""), nil
   758  						}),
   759  						PrefixExtension('{', func(ctx context.Context, p *Parser) (Evaluable, error) {
   760  							eval, err := p.ParseSublanguage(ctx, Full())
   761  							if err != nil {
   762  								return nil, err
   763  							}
   764  
   765  							switch p.Scan() {
   766  							case '}':
   767  							default:
   768  								return nil, p.Expected("embedded", '}')
   769  							}
   770  
   771  							return step(ctx, p, eval)
   772  						}),
   773  					)
   774  				}(),
   775  				want: "left 10 right",
   776  			},
   777  			{
   778  				name:       "Late binding",
   779  				expression: "5 * [ 10 * { 20 / [ 10 ] } ]",
   780  				extension: func() Language {
   781  					var inner, outer Language
   782  
   783  					parseCurly := func(ctx context.Context, p *Parser) (Evaluable, error) {
   784  						eval, err := p.ParseSublanguage(ctx, outer)
   785  						if err != nil {
   786  							return nil, err
   787  						}
   788  
   789  						if p.Scan() != '}' {
   790  							return nil, p.Expected("end", '}')
   791  						}
   792  
   793  						return eval, nil
   794  					}
   795  
   796  					parseSquare := func(ctx context.Context, p *Parser) (Evaluable, error) {
   797  						eval, err := p.ParseSublanguage(ctx, inner)
   798  						if err != nil {
   799  							return nil, err
   800  						}
   801  
   802  						if p.Scan() != ']' {
   803  							return nil, p.Expected("end", ']')
   804  						}
   805  
   806  						return eval, nil
   807  					}
   808  
   809  					inner = Full(PrefixExtension('{', parseCurly))
   810  					outer = Full(PrefixExtension('[', parseSquare))
   811  					return outer
   812  				}(),
   813  				want: 100.0,
   814  			},
   815  		},
   816  		t,
   817  	)
   818  }
   819  

View as plain text