{
  "generatedFrom": "src/formulas.yaml",
  "today": "2026-03-15",
  "vars": {
    "n": 12,
    "zero": 0,
    "empty": null,
    "name": "Anne",
    "date": "2024-02-29",
    "tags": [
      "a",
      "b"
    ]
  },
  "cases": [
    {
      "formula": "1 + 2 * 3",
      "ast": {
        "fn": "ADD",
        "args": [
          {
            "lit": 1
          },
          {
            "fn": "MUL",
            "args": [
              {
                "lit": 2
              },
              {
                "lit": 3
              }
            ]
          }
        ]
      },
      "expect": 7
    },
    {
      "formula": "(1 + 2) * 3",
      "ast": {
        "fn": "MUL",
        "args": [
          {
            "fn": "ADD",
            "args": [
              {
                "lit": 1
              },
              {
                "lit": 2
              }
            ]
          },
          {
            "lit": 3
          }
        ]
      },
      "expect": 9
    },
    {
      "formula": "10 - 4 - 3",
      "ast": {
        "fn": "SUB",
        "args": [
          {
            "fn": "SUB",
            "args": [
              {
                "lit": 10
              },
              {
                "lit": 4
              }
            ]
          },
          {
            "lit": 3
          }
        ]
      },
      "expect": 3
    },
    {
      "formula": "-n + 2",
      "ast": {
        "fn": "ADD",
        "args": [
          {
            "fn": "NEG",
            "args": [
              {
                "var": "n"
              }
            ]
          },
          {
            "lit": 2
          }
        ]
      },
      "expect": -10
    },
    {
      "formula": "n / 4",
      "ast": {
        "fn": "DIV",
        "args": [
          {
            "var": "n"
          },
          {
            "lit": 4
          }
        ]
      },
      "expect": 3
    },
    {
      "formula": "empty * 12",
      "ast": {
        "fn": "MUL",
        "args": [
          {
            "var": "empty"
          },
          {
            "lit": 12
          }
        ]
      },
      "expect": null,
      "note": "blank propagates through arithmetic"
    },
    {
      "formula": "-empty",
      "ast": {
        "fn": "NEG",
        "args": [
          {
            "var": "empty"
          }
        ]
      },
      "expect": null
    },
    {
      "formula": "n / zero",
      "ast": {
        "fn": "DIV",
        "args": [
          {
            "var": "n"
          },
          {
            "var": "zero"
          }
        ]
      },
      "expect": null,
      "note": "division by zero is an error"
    },
    {
      "formula": "\"a\" * 2",
      "ast": {
        "fn": "MUL",
        "args": [
          {
            "lit": "a"
          },
          {
            "lit": 2
          }
        ]
      },
      "expect": null,
      "note": "wrong type is an error"
    },
    {
      "formula": "0.1 + 0.2",
      "ast": {
        "fn": "ADD",
        "args": [
          {
            "lit": 0.1
          },
          {
            "lit": 0.2
          }
        ]
      },
      "expect": 0.30000000000000004,
      "note": "plain IEEE doubles"
    },
    {
      "formula": "POWER(2, 10)",
      "ast": {
        "fn": "POWER",
        "args": [
          {
            "lit": 2
          },
          {
            "lit": 10
          }
        ]
      },
      "expect": 1024
    },
    {
      "formula": "ABS(-3.5)",
      "ast": {
        "fn": "ABS",
        "args": [
          {
            "lit": -3.5
          }
        ]
      },
      "expect": 3.5
    },
    {
      "formula": "n >= 12",
      "ast": {
        "fn": "GE",
        "args": [
          {
            "var": "n"
          },
          {
            "lit": 12
          }
        ]
      },
      "expect": true
    },
    {
      "formula": "n > 12",
      "ast": {
        "fn": "GT",
        "args": [
          {
            "var": "n"
          },
          {
            "lit": 12
          }
        ]
      },
      "expect": false
    },
    {
      "formula": "empty > 1",
      "ast": {
        "fn": "GT",
        "args": [
          {
            "var": "empty"
          },
          {
            "lit": 1
          }
        ]
      },
      "expect": false,
      "note": "ordering with blank is FALSE"
    },
    {
      "formula": "empty < 1",
      "ast": {
        "fn": "LT",
        "args": [
          {
            "var": "empty"
          },
          {
            "lit": 1
          }
        ]
      },
      "expect": false
    },
    {
      "formula": "empty = \"\"",
      "ast": {
        "fn": "EQ",
        "args": [
          {
            "var": "empty"
          },
          {
            "lit": ""
          }
        ]
      },
      "expect": true,
      "note": "\"\" is blank"
    },
    {
      "formula": "empty = 0",
      "ast": {
        "fn": "EQ",
        "args": [
          {
            "var": "empty"
          },
          {
            "lit": 0
          }
        ]
      },
      "expect": false,
      "note": "blank is not zero"
    },
    {
      "formula": "name = \"anne\"",
      "ast": {
        "fn": "EQ",
        "args": [
          {
            "var": "name"
          },
          {
            "lit": "anne"
          }
        ]
      },
      "expect": false,
      "note": "text equality is case-sensitive"
    },
    {
      "formula": "name <> \"Anne\"",
      "ast": {
        "fn": "NE",
        "args": [
          {
            "var": "name"
          },
          {
            "lit": "Anne"
          }
        ]
      },
      "expect": false
    },
    {
      "formula": "n = \"12\"",
      "ast": {
        "fn": "EQ",
        "args": [
          {
            "var": "n"
          },
          {
            "lit": "12"
          }
        ]
      },
      "expect": false,
      "note": "different types are unequal"
    },
    {
      "formula": "n < \"a\"",
      "ast": {
        "fn": "LT",
        "args": [
          {
            "var": "n"
          },
          {
            "lit": "a"
          }
        ]
      },
      "expect": null,
      "note": "ordering mixed types is an error"
    },
    {
      "formula": "date < \"2024-03-01\"",
      "ast": {
        "fn": "LT",
        "args": [
          {
            "var": "date"
          },
          {
            "lit": "2024-03-01"
          }
        ]
      },
      "expect": true,
      "note": "ISO dates order as text"
    },
    {
      "formula": "\"b\" > \"B\"",
      "ast": {
        "fn": "GT",
        "args": [
          {
            "lit": "b"
          },
          {
            "lit": "B"
          }
        ]
      },
      "expect": true,
      "note": "ordinal comparison"
    },
    {
      "formula": "AND(TRUE, n > 1)",
      "ast": {
        "fn": "AND",
        "args": [
          {
            "lit": true
          },
          {
            "fn": "GT",
            "args": [
              {
                "var": "n"
              },
              {
                "lit": 1
              }
            ]
          }
        ]
      },
      "expect": true
    },
    {
      "formula": "AND(FALSE, n / zero)",
      "ast": {
        "fn": "AND",
        "args": [
          {
            "lit": false
          },
          {
            "fn": "DIV",
            "args": [
              {
                "var": "n"
              },
              {
                "var": "zero"
              }
            ]
          }
        ]
      },
      "expect": false,
      "note": "AND stops at the first FALSE"
    },
    {
      "formula": "OR(TRUE, n / zero)",
      "ast": {
        "fn": "OR",
        "args": [
          {
            "lit": true
          },
          {
            "fn": "DIV",
            "args": [
              {
                "var": "n"
              },
              {
                "var": "zero"
              }
            ]
          }
        ]
      },
      "expect": true
    },
    {
      "formula": "OR(empty, FALSE)",
      "ast": {
        "fn": "OR",
        "args": [
          {
            "var": "empty"
          },
          {
            "lit": false
          }
        ]
      },
      "expect": false,
      "note": "blank is FALSE"
    },
    {
      "formula": "NOT(zero)",
      "ast": {
        "fn": "NOT",
        "args": [
          {
            "var": "zero"
          }
        ]
      },
      "expect": true
    },
    {
      "formula": "AND(name)",
      "ast": {
        "fn": "AND",
        "args": [
          {
            "var": "name"
          }
        ]
      },
      "expect": null,
      "note": "text is not TRUE/FALSE"
    },
    {
      "formula": "IF(n > 10, \"big\", \"small\")",
      "ast": {
        "fn": "IF",
        "args": [
          {
            "fn": "GT",
            "args": [
              {
                "var": "n"
              },
              {
                "lit": 10
              }
            ]
          },
          {
            "lit": "big"
          },
          {
            "lit": "small"
          }
        ]
      },
      "expect": "big"
    },
    {
      "formula": "IF(FALSE, 1)",
      "ast": {
        "fn": "IF",
        "args": [
          {
            "lit": false
          },
          {
            "lit": 1
          }
        ]
      },
      "expect": null
    },
    {
      "formula": "IF(TRUE, 1, n / zero)",
      "ast": {
        "fn": "IF",
        "args": [
          {
            "lit": true
          },
          {
            "lit": 1
          },
          {
            "fn": "DIV",
            "args": [
              {
                "var": "n"
              },
              {
                "var": "zero"
              }
            ]
          }
        ]
      },
      "expect": 1,
      "note": "IF only evaluates the branch it needs"
    },
    {
      "formula": "ISBLANK(empty)",
      "ast": {
        "fn": "ISBLANK",
        "args": [
          {
            "var": "empty"
          }
        ]
      },
      "expect": true
    },
    {
      "formula": "ISBLANK(\"\")",
      "ast": {
        "fn": "ISBLANK",
        "args": [
          {
            "lit": ""
          }
        ]
      },
      "expect": true
    },
    {
      "formula": "ISBLANK(zero)",
      "ast": {
        "fn": "ISBLANK",
        "args": [
          {
            "var": "zero"
          }
        ]
      },
      "expect": false
    },
    {
      "formula": "IFBLANK(empty, 5)",
      "ast": {
        "fn": "IFBLANK",
        "args": [
          {
            "var": "empty"
          },
          {
            "lit": 5
          }
        ]
      },
      "expect": 5
    },
    {
      "formula": "IFBLANK(zero, 5)",
      "ast": {
        "fn": "IFBLANK",
        "args": [
          {
            "var": "zero"
          },
          {
            "lit": 5
          }
        ]
      },
      "expect": 0
    },
    {
      "formula": "name & \" is \" & n",
      "ast": {
        "fn": "CONCAT",
        "args": [
          {
            "var": "name"
          },
          {
            "lit": " is "
          },
          {
            "var": "n"
          }
        ]
      },
      "expect": "Anne is 12"
    },
    {
      "formula": "\"x\" & empty & TRUE & 1.5",
      "ast": {
        "fn": "CONCAT",
        "args": [
          {
            "lit": "x"
          },
          {
            "var": "empty"
          },
          {
            "lit": true
          },
          {
            "lit": 1.5
          }
        ]
      },
      "expect": "xTRUE1.5"
    },
    {
      "formula": "LEN(name)",
      "ast": {
        "fn": "LEN",
        "args": [
          {
            "var": "name"
          }
        ]
      },
      "expect": 4
    },
    {
      "formula": "LEN(empty)",
      "ast": {
        "fn": "LEN",
        "args": [
          {
            "var": "empty"
          }
        ]
      },
      "expect": 0
    },
    {
      "formula": "LEN(n)",
      "ast": {
        "fn": "LEN",
        "args": [
          {
            "var": "n"
          }
        ]
      },
      "expect": null,
      "note": "LEN takes text"
    },
    {
      "formula": "LEN(\"æøå\")",
      "ast": {
        "fn": "LEN",
        "args": [
          {
            "lit": "æøå"
          }
        ]
      },
      "expect": 3
    },
    {
      "formula": "UPPER(\"æble å\")",
      "ast": {
        "fn": "UPPER",
        "args": [
          {
            "lit": "æble å"
          }
        ]
      },
      "expect": "ÆBLE Å"
    },
    {
      "formula": "LOWER(\"ÆBLE\")",
      "ast": {
        "fn": "LOWER",
        "args": [
          {
            "lit": "ÆBLE"
          }
        ]
      },
      "expect": "æble"
    },
    {
      "formula": "TRIM(\"  a   b  \")",
      "ast": {
        "fn": "TRIM",
        "args": [
          {
            "lit": "  a   b  "
          }
        ]
      },
      "expect": "a b"
    },
    {
      "formula": "LEFT(\"12345678\", 2)",
      "ast": {
        "fn": "LEFT",
        "args": [
          {
            "lit": "12345678"
          },
          {
            "lit": 2
          }
        ]
      },
      "expect": "12"
    },
    {
      "formula": "RIGHT(\"12345678\", 3)",
      "ast": {
        "fn": "RIGHT",
        "args": [
          {
            "lit": "12345678"
          },
          {
            "lit": 3
          }
        ]
      },
      "expect": "678"
    },
    {
      "formula": "LEFT(name)",
      "ast": {
        "fn": "LEFT",
        "args": [
          {
            "var": "name"
          }
        ]
      },
      "expect": "A"
    },
    {
      "formula": "CONTAINS(name, \"nn\")",
      "ast": {
        "fn": "CONTAINS",
        "args": [
          {
            "var": "name"
          },
          {
            "lit": "nn"
          }
        ]
      },
      "expect": true
    },
    {
      "formula": "CONTAINS(name, \"NN\")",
      "ast": {
        "fn": "CONTAINS",
        "args": [
          {
            "var": "name"
          },
          {
            "lit": "NN"
          }
        ]
      },
      "expect": false
    },
    {
      "formula": "CONTAINS(tags, \"b\")",
      "ast": {
        "fn": "CONTAINS",
        "args": [
          {
            "var": "tags"
          },
          {
            "lit": "b"
          }
        ]
      },
      "expect": true
    },
    {
      "formula": "CONTAINS(tags, \"c\")",
      "ast": {
        "fn": "CONTAINS",
        "args": [
          {
            "var": "tags"
          },
          {
            "lit": "c"
          }
        ]
      },
      "expect": false
    },
    {
      "formula": "CONTAINS(empty, \"c\")",
      "ast": {
        "fn": "CONTAINS",
        "args": [
          {
            "var": "empty"
          },
          {
            "lit": "c"
          }
        ]
      },
      "expect": false
    },
    {
      "formula": "MATCHES(\"12345678\", \"^[0-9]{8}$\")",
      "ast": {
        "fn": "MATCHES",
        "args": [
          {
            "lit": "12345678"
          },
          {
            "lit": "^[0-9]{8}$"
          }
        ]
      },
      "expect": true
    },
    {
      "formula": "MATCHES(\"1234567\", \"^[0-9]{8}$\")",
      "ast": {
        "fn": "MATCHES",
        "args": [
          {
            "lit": "1234567"
          },
          {
            "lit": "^[0-9]{8}$"
          }
        ]
      },
      "expect": false
    },
    {
      "formula": "MATCHES(\"abc123\", \"[0-9]\")",
      "ast": {
        "fn": "MATCHES",
        "args": [
          {
            "lit": "abc123"
          },
          {
            "lit": "[0-9]"
          }
        ]
      },
      "expect": true,
      "note": "MATCHES searches"
    },
    {
      "formula": "MATCHES(empty, \".*\")",
      "ast": {
        "fn": "MATCHES",
        "args": [
          {
            "var": "empty"
          },
          {
            "lit": ".*"
          }
        ]
      },
      "expect": false
    },
    {
      "formula": "MATCHES(\"say \"\"hi\"\"\", \"\"\"hi\"\"\")",
      "ast": {
        "fn": "MATCHES",
        "args": [
          {
            "lit": "say \"hi\""
          },
          {
            "lit": "\"hi\""
          }
        ]
      },
      "expect": true,
      "note": "doubled quotes inside text"
    },
    {
      "formula": "ROUND(2.5)",
      "ast": {
        "fn": "ROUND",
        "args": [
          {
            "lit": 2.5
          }
        ]
      },
      "expect": 3
    },
    {
      "formula": "ROUND(-2.5)",
      "ast": {
        "fn": "ROUND",
        "args": [
          {
            "lit": -2.5
          }
        ]
      },
      "expect": -3,
      "note": "half away from zero"
    },
    {
      "formula": "ROUND(1234.5678, 2)",
      "ast": {
        "fn": "ROUND",
        "args": [
          {
            "lit": 1234.5678
          },
          {
            "lit": 2
          }
        ]
      },
      "expect": 1234.57
    },
    {
      "formula": "ROUND(1234.5678, -2)",
      "ast": {
        "fn": "ROUND",
        "args": [
          {
            "lit": 1234.5678
          },
          {
            "lit": -2
          }
        ]
      },
      "expect": 1200
    },
    {
      "formula": "ROUND(1.005, 2)",
      "ast": {
        "fn": "ROUND",
        "args": [
          {
            "lit": 1.005
          },
          {
            "lit": 2
          }
        ]
      },
      "expect": 1,
      "note": "1.005 is 1.00499999... as a double"
    },
    {
      "formula": "ROUND(empty, 2)",
      "ast": {
        "fn": "ROUND",
        "args": [
          {
            "var": "empty"
          },
          {
            "lit": 2
          }
        ]
      },
      "expect": null
    },
    {
      "formula": "ROUND(1.5, 0.5)",
      "ast": {
        "fn": "ROUND",
        "args": [
          {
            "lit": 1.5
          },
          {
            "lit": 0.5
          }
        ]
      },
      "expect": null,
      "note": "digits must be whole"
    },
    {
      "formula": "MIN(3, tags)",
      "ast": {
        "fn": "MIN",
        "args": [
          {
            "lit": 3
          },
          {
            "var": "tags"
          }
        ]
      },
      "expect": null,
      "note": "text in MIN is an error"
    },
    {
      "formula": "MIN(3, empty, 1)",
      "ast": {
        "fn": "MIN",
        "args": [
          {
            "lit": 3
          },
          {
            "var": "empty"
          },
          {
            "lit": 1
          }
        ]
      },
      "expect": 1
    },
    {
      "formula": "MAX(empty)",
      "ast": {
        "fn": "MAX",
        "args": [
          {
            "var": "empty"
          }
        ]
      },
      "expect": null
    },
    {
      "formula": "SUM(1, 2, empty)",
      "ast": {
        "fn": "SUM",
        "args": [
          {
            "lit": 1
          },
          {
            "lit": 2
          },
          {
            "var": "empty"
          }
        ]
      },
      "expect": 3
    },
    {
      "formula": "SUM(empty)",
      "ast": {
        "fn": "SUM",
        "args": [
          {
            "var": "empty"
          }
        ]
      },
      "expect": 0
    },
    {
      "formula": "COUNT(tags, empty, n)",
      "ast": {
        "fn": "COUNT",
        "args": [
          {
            "var": "tags"
          },
          {
            "var": "empty"
          },
          {
            "var": "n"
          }
        ]
      },
      "expect": 3
    },
    {
      "formula": "TODAY()",
      "ast": {
        "fn": "TODAY",
        "args": []
      },
      "expect": "2026-03-15"
    },
    {
      "formula": "DATE(2024, 2, 29)",
      "ast": {
        "fn": "DATE",
        "args": [
          {
            "lit": 2024
          },
          {
            "lit": 2
          },
          {
            "lit": 29
          }
        ]
      },
      "expect": "2024-02-29"
    },
    {
      "formula": "DATE(2024, 13, 1)",
      "ast": {
        "fn": "DATE",
        "args": [
          {
            "lit": 2024
          },
          {
            "lit": 13
          },
          {
            "lit": 1
          }
        ]
      },
      "expect": "2025-01-01",
      "note": "months overflow"
    },
    {
      "formula": "DATE(2024, 3, 0)",
      "ast": {
        "fn": "DATE",
        "args": [
          {
            "lit": 2024
          },
          {
            "lit": 3
          },
          {
            "lit": 0
          }
        ]
      },
      "expect": "2024-02-29",
      "note": "day 0 is the last day of the previous month"
    },
    {
      "formula": "DATE(2023, 2, 29)",
      "ast": {
        "fn": "DATE",
        "args": [
          {
            "lit": 2023
          },
          {
            "lit": 2
          },
          {
            "lit": 29
          }
        ]
      },
      "expect": "2023-03-01"
    },
    {
      "formula": "YEAR(date)",
      "ast": {
        "fn": "YEAR",
        "args": [
          {
            "var": "date"
          }
        ]
      },
      "expect": 2024
    },
    {
      "formula": "MONTH(date)",
      "ast": {
        "fn": "MONTH",
        "args": [
          {
            "var": "date"
          }
        ]
      },
      "expect": 2
    },
    {
      "formula": "DAY(date)",
      "ast": {
        "fn": "DAY",
        "args": [
          {
            "var": "date"
          }
        ]
      },
      "expect": 29
    },
    {
      "formula": "YEAR(\"2024-02-30\")",
      "ast": {
        "fn": "YEAR",
        "args": [
          {
            "lit": "2024-02-30"
          }
        ]
      },
      "expect": null,
      "note": "not a real date"
    },
    {
      "formula": "DAYS(\"2024-03-01\", date)",
      "ast": {
        "fn": "DAYS",
        "args": [
          {
            "lit": "2024-03-01"
          },
          {
            "var": "date"
          }
        ]
      },
      "expect": 1
    },
    {
      "formula": "DAYS(\"2023-01-01\", \"2024-01-01\")",
      "ast": {
        "fn": "DAYS",
        "args": [
          {
            "lit": "2023-01-01"
          },
          {
            "lit": "2024-01-01"
          }
        ]
      },
      "expect": -365
    },
    {
      "formula": "EDATE(\"2024-01-31\", 1)",
      "ast": {
        "fn": "EDATE",
        "args": [
          {
            "lit": "2024-01-31"
          },
          {
            "lit": 1
          }
        ]
      },
      "expect": "2024-02-29"
    },
    {
      "formula": "EDATE(\"2024-03-31\", -1)",
      "ast": {
        "fn": "EDATE",
        "args": [
          {
            "lit": "2024-03-31"
          },
          {
            "lit": -1
          }
        ]
      },
      "expect": "2024-02-29"
    },
    {
      "formula": "EDATE(date, 12)",
      "ast": {
        "fn": "EDATE",
        "args": [
          {
            "var": "date"
          },
          {
            "lit": 12
          }
        ]
      },
      "expect": "2025-02-28"
    },
    {
      "formula": "ADDDAYS(date, 1)",
      "ast": {
        "fn": "ADDDAYS",
        "args": [
          {
            "var": "date"
          },
          {
            "lit": 1
          }
        ]
      },
      "expect": "2024-03-01"
    },
    {
      "formula": "ADDDAYS(\"2024-01-01\", -1)",
      "ast": {
        "fn": "ADDDAYS",
        "args": [
          {
            "lit": "2024-01-01"
          },
          {
            "lit": -1
          }
        ]
      },
      "expect": "2023-12-31"
    },
    {
      "formula": "AGE(\"2008-03-15\")",
      "ast": {
        "fn": "AGE",
        "args": [
          {
            "lit": "2008-03-15"
          }
        ]
      },
      "expect": 18
    },
    {
      "formula": "AGE(\"2008-03-16\")",
      "ast": {
        "fn": "AGE",
        "args": [
          {
            "lit": "2008-03-16"
          }
        ]
      },
      "expect": 17
    },
    {
      "formula": "AGE(date, \"2025-02-28\")",
      "ast": {
        "fn": "AGE",
        "args": [
          {
            "var": "date"
          },
          {
            "lit": "2025-02-28"
          }
        ]
      },
      "expect": 0,
      "note": "29 Feb birthday counts from 1 March"
    },
    {
      "formula": "AGE(date, \"2025-03-01\")",
      "ast": {
        "fn": "AGE",
        "args": [
          {
            "var": "date"
          },
          {
            "lit": "2025-03-01"
          }
        ]
      },
      "expect": 1
    },
    {
      "formula": "AGE(empty)",
      "ast": {
        "fn": "AGE",
        "args": [
          {
            "var": "empty"
          }
        ]
      },
      "expect": null
    }
  ]
}
