@halleyassist/rule-parser 1.0.19 → 1.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1920,9 +1920,9 @@ exports.Grammars = require("./Grammars");
1920
1920
  module.exports = require('./RuleParser.production')
1921
1921
 
1922
1922
  },{"./RuleParser.production":12}],11:[function(require,module,exports){
1923
- module.exports=[{"name":"statement_main","bnf":[["statement","EOF"]]},{"name":"logical_operator","bnf":[["AND"],["OR"]]},{"name":"%statement[2]","bnf":[["logical_operator","expression"]],"fragment":true},{"name":"statement","bnf":[["expression","%statement[2]*"]]},{"name":"expression","bnf":[["not_expression"],["standard_expression"],["parenthesis_expression"]]},{"name":"parenthesis_expression","bnf":[["BEGIN_PARENTHESIS","WS*","statement","WS*","END_PARENTHESIS"]]},{"name":"%not_expression[2]","bnf":[["result"],["parenthesis_expression"]],"fragment":true},{"name":"not_expression","bnf":[["NOT","%not_expression[2]"]]},{"name":"%standard_expression[2][1]","bnf":[["WS*","eq_approx"]],"fragment":true},{"name":"%standard_expression[2][2]","bnf":[["WS*","basic_rhs"]],"fragment":true},{"name":"%standard_expression[2][3][1]","bnf":[["WS+","IS"]],"fragment":true},{"name":"%standard_expression[2][3]","bnf":[["%standard_expression[2][3][1]?","WS+","between"]],"fragment":true},{"name":"%standard_expression[2][4]","bnf":[["WS+","in_expr"]],"fragment":true},{"name":"%standard_expression[2]","bnf":[["%standard_expression[2][1]"],["%standard_expression[2][2]"],["%standard_expression[2][3]"],["%standard_expression[2][4]"]],"fragment":true},{"name":"standard_expression","bnf":[["result","%standard_expression[2]?"]]},{"name":"basic_rhs","bnf":[["operator","WS*","result"]]},{"name":"eq_approx","bnf":[["eq_operator","WS*","\"~\"","WS*","result"]]},{"name":"PLUS","bnf":[["\"+\""]]},{"name":"MINUS","bnf":[["\"-\""]]},{"name":"MULTIPLY","bnf":[["\"*\""]]},{"name":"DIVIDE","bnf":[["\"/\""]]},{"name":"MODULUS","bnf":[["\"%\""]]},{"name":"DEFAULT_VAL","bnf":[["\"??\""]]},{"name":"arithmetic_operator","bnf":[["PLUS"],["MINUS"],["MULTIPLY"],["DIVIDE"],["MODULUS"],["DEFAULT_VAL"]]},{"name":"arithmetic_operand","bnf":[["fcall"],["number_time"],["number"]]},{"name":"%arithmetic_result[5]","bnf":[["arithmetic_result"],["arithmetic_operand"]],"fragment":true},{"name":"arithmetic_result","bnf":[["arithmetic_operand","WS*","arithmetic_operator","WS*","%arithmetic_result[5]"]]},{"name":"simple_result","bnf":[["fcall"],["value"]]},{"name":"result","bnf":[["arithmetic_result"],["simple_result"]]},{"name":"value","bnf":[["false"],["true"],["array"],["time_period"],["number_time"],["number"],["number_tod"],["string"]]},{"name":"BEGIN_ARRAY","bnf":[["WS*",/\x5B/,"WS*"]]},{"name":"BEGIN_OBJECT","bnf":[["WS*",/\x7B/,"WS*"]]},{"name":"END_ARRAY","bnf":[["WS*",/\x5D/,"WS*"]]},{"name":"END_OBJECT","bnf":[["WS*",/\x7D/,"WS*"]]},{"name":"NAME_SEPARATOR","bnf":[["WS*",/\x3A/,"WS*"]]},{"name":"VALUE_SEPARATOR","bnf":[["WS*",/\x2C/,"WS*"]]},{"name":"WS","bnf":[[/[\x20\x09\x0A\x0D]/]]},{"name":"operator","bnf":[["GTE"],["LTE"],["GT"],["LT"],["EQ"],["NEQ"]]},{"name":"eq_operator","bnf":[["EQ"],["NEQ"]]},{"name":"BEGIN_ARGUMENT","bnf":[["\"(\""]]},{"name":"END_ARGUMENT","bnf":[["\")\""]]},{"name":"BEGIN_PARENTHESIS","bnf":[["\"(\""]]},{"name":"END_PARENTHESIS","bnf":[["\")\""]]},{"name":"BEGIN_IN","bnf":[[/[Ii]/,/[Nn]/]]},{"name":"in_expr","bnf":[["BEGIN_IN","WS*","BEGIN_PARENTHESIS","WS*","arguments","END_PARENTHESIS"]]},{"name":"argument","bnf":[["statement","WS*"]]},{"name":"%arguments[2]","bnf":[["WS*","\",\"","WS*","argument"]],"fragment":true},{"name":"arguments","bnf":[["argument","%arguments[2]*"]]},{"name":"%fname[1]","bnf":[[/[a-zA-z0-9]/]]},{"name":"fname","bnf":[["%fname[1]+"]]},{"name":"fcall","bnf":[["fname","WS*","BEGIN_ARGUMENT","WS*","arguments?","END_ARGUMENT"]]},{"name":"%between_number[1]","bnf":[["number_time"],["number"]],"fragment":true},{"name":"%between_number[2][1]","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"%between_number[2][2]","bnf":[["WS*",/\-/,"WS*"]],"fragment":true},{"name":"%between_number[2]","bnf":[["%between_number[2][1]"],["%between_number[2][2]"]],"fragment":true},{"name":"%between_number[3]","bnf":[["number_time"],["number"]],"fragment":true},{"name":"between_number","bnf":[["%between_number[1]","%between_number[2]","%between_number[3]"]]},{"name":"%between_number_time[2][1]","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"%between_number_time[2][2]","bnf":[["WS*",/\-/,"WS*"]],"fragment":true},{"name":"%between_number_time[2]","bnf":[["%between_number_time[2][1]"],["%between_number_time[2][2]"]],"fragment":true},{"name":"%between_number_time[4]","bnf":[["WS+","dow_range"]],"fragment":true},{"name":"between_number_time","bnf":[["number_time","%between_number_time[2]","number_time","%between_number_time[4]?"]]},{"name":"%between_tod[2][1]","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"%between_tod[2]","bnf":[["%between_tod[2][1]"]],"fragment":true},{"name":"%between_tod[4]","bnf":[["WS+","dow_range"]],"fragment":true},{"name":"between_tod","bnf":[["number_tod","%between_tod[2]","number_tod","%between_tod[4]?"]]},{"name":"%between[3]","bnf":[["between_number"],["between_tod"]],"fragment":true},{"name":"between","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","%between[3]"]]},{"name":"dow","bnf":[[/[Mm]/,/[Oo]/,/[Nn]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Mm]/,/[Oo]/,/[Nn]/],[/[Tt]/,/[Uu]/,/[Ee]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Tt]/,/[Uu]/,/[Ee]/],[/[Ww]/,/[Ee]/,/[Dd]/,/[Nn]/,/[Ee]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ww]/,/[Ee]/,/[Dd]/],[/[Tt]/,/[Hh]/,/[Uu]/,/[Rr]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Tt]/,/[Hh]/,/[Uu]/],[/[Tt]/,/[Hh]/,/[Uu]/,/[Rr]/],[/[Ff]/,/[Rr]/,/[Ii]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ff]/,/[Rr]/,/[Ii]/],[/[Ss]/,/[Aa]/,/[Tt]/,/[Uu]/,/[Rr]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ss]/,/[Aa]/,/[Tt]/],[/[Ss]/,/[Uu]/,/[Nn]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ss]/,/[Uu]/,/[Nn]/]]},{"name":"%dow_range[4]","bnf":[["WS+",/[Tt]/,/[Oo]/,"WS+","dow"]],"fragment":true},{"name":"dow_range","bnf":[[/[Oo]/,/[Nn]/,"WS+","dow","%dow_range[4]?"]]},{"name":"between_time_only","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","between_number_time"]]},{"name":"between_tod_only","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","between_tod"]]},{"name":"%AND[1]","bnf":[["WS*",/&/,/&/,"WS*"]],"fragment":true},{"name":"%AND[2]","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"AND","bnf":[["%AND[1]"],["%AND[2]"]]},{"name":"%OR[1]","bnf":[["WS*",/\|/,/\|/,"WS*"]],"fragment":true},{"name":"%OR[2]","bnf":[["WS+",/[Oo]/,/[Rr]/,"WS+"]],"fragment":true},{"name":"OR","bnf":[["%OR[1]"],["%OR[2]"]]},{"name":"AGO","bnf":[[/[Aa]/,/[Gg]/,/[Oo]/]]},{"name":"GT","bnf":[["\">\""]]},{"name":"LT","bnf":[["\"<\""]]},{"name":"GTE","bnf":[["\">=\""]]},{"name":"LTE","bnf":[["\"<=\""]]},{"name":"IS","bnf":[[/[Ii]/,/[Ss]/]]},{"name":"EQ","bnf":[["\"==\""],["\"=\""]]},{"name":"NEQ","bnf":[["\"!=\""]]},{"name":"%NOT[1]","bnf":[[/!/,"WS*"]],"fragment":true},{"name":"%NOT[2]","bnf":[[/[Nn]/,/[Oo]/,/[Tt]/,"WS+"]],"fragment":true},{"name":"NOT","bnf":[["%NOT[1]"],["%NOT[2]"]]},{"name":"false","bnf":[[/[Ff]/,/[Aa]/,/[Ll]/,/[Ss]/,/[Ee]/]]},{"name":"null","bnf":[[/[Nn]/,/[Uu]/,/[Ll]/,/[Ll]/]]},{"name":"true","bnf":[[/[Tt]/,/[Rr]/,/[Uu]/,/[Ee]/]]},{"name":"%array[2][2]","bnf":[["VALUE_SEPARATOR","value"]],"fragment":true},{"name":"%array[2]","bnf":[["value","%array[2][2]*"]],"fragment":true},{"name":"array","bnf":[["BEGIN_ARRAY","%array[2]?","END_ARRAY"]]},{"name":"unit","bnf":[[/[Ss]/,/[Ee]/,/[Cc]/,/[Oo]/,/[Nn]/,/[Dd]/,/[Ss]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Uu]/,/[Tt]/,/[Ee]/,/[Ss]/],[/[Hh]/,/[Oo]/,/[Uu]/,/[Rr]/,/[Ss]/],[/[Ww]/,/[Ee]/,/[Ee]/,/[Kk]/,/[Ss]/],[/[Dd]/,/[Aa]/,/[Yy]/,/[Ss]/],[/[Ss]/,/[Ee]/,/[Cc]/,/[Oo]/,/[Nn]/,/[Dd]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Uu]/,/[Tt]/,/[Ee]/],[/[Ww]/,/[Ee]/,/[Ee]/,/[Kk]/],[/[Hh]/,/[Oo]/,/[Uu]/,/[Rr]/],[/[Dd]/,/[Aa]/,/[Yy]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Ss]/],[/[Mm]/,/[Ii]/,/[Nn]/]]},{"name":"%number[2][1]","bnf":[[/[0-9]/]]},{"name":"%number[2]","bnf":[["%number[2][1]+"]],"fragment":true},{"name":"%number[3][2]","bnf":[[/[0-9]/]]},{"name":"%number[3]","bnf":[["\".\"","%number[3][2]+"]],"fragment":true},{"name":"%number[4][2]","bnf":[["\"-\""],["\"+\""]],"fragment":true},{"name":"%number[4][3][2]","bnf":[[/[0-9]/]]},{"name":"%number[4][3]","bnf":[["\"0\""],[/[1-9]/,"%number[4][3][2]*"]],"fragment":true},{"name":"%number[4]","bnf":[["\"e\"","%number[4][2]?","%number[4][3]"]],"fragment":true},{"name":"number","bnf":[["\"-\"?","%number[2]","%number[3]?","%number[4]?"]]},{"name":"number_time","bnf":[["number","WS+","unit"]]},{"name":"%number_tod[1][1]","bnf":[[/[0-9]/]]},{"name":"%number_tod[1]","bnf":[["%number_tod[1][1]+"]],"fragment":true},{"name":"%number_tod[3][1]","bnf":[[/[0-9]/]]},{"name":"%number_tod[3]","bnf":[["%number_tod[3][1]+"]],"fragment":true},{"name":"number_tod","bnf":[["%number_tod[1]","\":\"","%number_tod[3]"]]},{"name":"%time_period_ago[2]","bnf":[["WS+","number_time"]],"fragment":true},{"name":"time_period_ago","bnf":[["number_time","%time_period_ago[2]*","WS+","AGO"]]},{"name":"%time_period_ago_between[2]","bnf":[["WS+","number_time"]],"fragment":true},{"name":"time_period_ago_between","bnf":[["number_time","%time_period_ago_between[2]*","WS+","AGO","WS+","between_tod_only"]]},{"name":"time_period_const","bnf":[[/[Tt]/,/[Oo]/,/[Dd]/,/[Aa]/,/[Yy]/],["time_period_ago"]]},{"name":"time_period","bnf":[["time_period_ago_between"],["time_period_const"],["between_tod_only"],["between_time_only"]]},{"name":"%string[2][1]","bnf":[[/[\x20-\x21]/],[/[\x23-\x5B]/],[/[\x5D-\uFFFF]/]],"fragment":true},{"name":"%string[2][2]","bnf":[[/\x22/],[/\x5C/],[/\x2F/],[/\x62/],[/\x66/],[/\x6E/],[/\x72/],[/\x74/],[/\x75/,"HEXDIG","HEXDIG","HEXDIG","HEXDIG"]],"fragment":true},{"name":"%string[2]","bnf":[["%string[2][1]"],[/\x5C/,"%string[2][2]"]],"fragment":true},{"name":"string","bnf":[["'\"'","%string[2]*","'\"'"]]},{"name":"HEXDIG","bnf":[[/[a-fA-F0-9]/]]}]
1923
+ module.exports=[{"name":"statement_main","bnf":[["statement","EOF"]]},{"name":"logical_operator","bnf":[["AND"],["OR"]]},{"name":"%statement[2]","bnf":[["logical_operator","expression"]],"fragment":true},{"name":"statement","bnf":[["expression","%statement[2]*"]]},{"name":"expression","bnf":[["not_expression"],["standard_expression"],["parenthesis_expression"]]},{"name":"parenthesis_expression","bnf":[["BEGIN_PARENTHESIS","WS*","statement","WS*","END_PARENTHESIS"]]},{"name":"%not_expression[2]","bnf":[["result"],["parenthesis_expression"]],"fragment":true},{"name":"not_expression","bnf":[["NOT","%not_expression[2]"]]},{"name":"%standard_expression[2][1]","bnf":[["WS*","eq_approx"]],"fragment":true},{"name":"%standard_expression[2][2]","bnf":[["WS*","basic_rhs"]],"fragment":true},{"name":"%standard_expression[2][3][1]","bnf":[["WS+","IS"]],"fragment":true},{"name":"%standard_expression[2][3]","bnf":[["%standard_expression[2][3][1]?","WS+","between"]],"fragment":true},{"name":"%standard_expression[2][4]","bnf":[["WS+","in_expr"]],"fragment":true},{"name":"%standard_expression[2]","bnf":[["%standard_expression[2][1]"],["%standard_expression[2][2]"],["%standard_expression[2][3]"],["%standard_expression[2][4]"]],"fragment":true},{"name":"standard_expression","bnf":[["result","%standard_expression[2]?"]]},{"name":"basic_rhs","bnf":[["operator","WS*","result"]]},{"name":"eq_approx","bnf":[["eq_operator","WS*","\"~\"","WS*","result"]]},{"name":"PLUS","bnf":[["\"+\""]]},{"name":"MINUS","bnf":[["\"-\""]]},{"name":"MULTIPLY","bnf":[["\"*\""]]},{"name":"DIVIDE","bnf":[["\"/\""]]},{"name":"MODULUS","bnf":[["\"%\""]]},{"name":"DEFAULT_VAL","bnf":[["\"??\""]]},{"name":"arithmetic_operator","bnf":[["PLUS"],["MINUS"],["MULTIPLY"],["DIVIDE"],["MODULUS"],["DEFAULT_VAL"]]},{"name":"number_atom","bnf":[["number"]]},{"name":"number_time_atom","bnf":[["number_time"]]},{"name":"tod_atom","bnf":[["number_tod"]]},{"name":"dow_atom","bnf":[["dow"]]},{"name":"arithmetic_operand","bnf":[["fcall"],["number_time_atom"],["number_atom"]]},{"name":"%arithmetic_result[5]","bnf":[["arithmetic_result"],["arithmetic_operand"]],"fragment":true},{"name":"arithmetic_result","bnf":[["arithmetic_operand","WS*","arithmetic_operator","WS*","%arithmetic_result[5]"]]},{"name":"simple_result","bnf":[["fcall"],["value"]]},{"name":"result","bnf":[["arithmetic_result"],["simple_result"]]},{"name":"value_atom","bnf":[["false"],["true"],["array"],["time_period"],["number_time_atom"],["number_atom"],["tod_atom"],["string"]]},{"name":"value","bnf":[["value_atom"]]},{"name":"BEGIN_ARRAY","bnf":[["WS*",/\x5B/,"WS*"]]},{"name":"BEGIN_OBJECT","bnf":[["WS*",/\x7B/,"WS*"]]},{"name":"END_ARRAY","bnf":[["WS*",/\x5D/,"WS*"]]},{"name":"END_OBJECT","bnf":[["WS*",/\x7D/,"WS*"]]},{"name":"NAME_SEPARATOR","bnf":[["WS*",/\x3A/,"WS*"]]},{"name":"VALUE_SEPARATOR","bnf":[["WS*",/\x2C/,"WS*"]]},{"name":"WS","bnf":[[/[\x20\x09\x0A\x0D]/]]},{"name":"operator","bnf":[["GTE"],["LTE"],["GT"],["LT"],["EQ"],["NEQ"]]},{"name":"eq_operator","bnf":[["EQ"],["NEQ"]]},{"name":"BEGIN_ARGUMENT","bnf":[["\"(\""]]},{"name":"END_ARGUMENT","bnf":[["\")\""]]},{"name":"BEGIN_PARENTHESIS","bnf":[["\"(\""]]},{"name":"END_PARENTHESIS","bnf":[["\")\""]]},{"name":"BEGIN_IN","bnf":[[/[Ii]/,/[Nn]/]]},{"name":"in_expr","bnf":[["BEGIN_IN","WS*","BEGIN_PARENTHESIS","WS*","arguments","END_PARENTHESIS"]]},{"name":"argument","bnf":[["statement","WS*"]]},{"name":"%arguments[2]","bnf":[["WS*","\",\"","WS*","argument"]],"fragment":true},{"name":"arguments","bnf":[["argument","%arguments[2]*"]]},{"name":"%fname[1]","bnf":[[/[A-Za-z0-9]/]]},{"name":"fname","bnf":[["%fname[1]+"]]},{"name":"fcall","bnf":[["fname","WS*","BEGIN_ARGUMENT","WS*","arguments?","END_ARGUMENT"]]},{"name":"%between_dash_or_and[1]","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"%between_dash_or_and[2]","bnf":[["WS*",/\-/,"WS*"]],"fragment":true},{"name":"between_dash_or_and","bnf":[["%between_dash_or_and[1]"],["%between_dash_or_and[2]"]]},{"name":"between_number_inner","bnf":[["number_atom"],["number_time_atom"]]},{"name":"between_number","bnf":[["between_number_inner","between_dash_or_and","between_number_inner"]]},{"name":"between_number_time_inner","bnf":[["number_time_atom"]]},{"name":"%between_number_time[4]","bnf":[["WS+","dow_range"]],"fragment":true},{"name":"between_number_time","bnf":[["between_number_time_inner","between_dash_or_and","between_number_time_inner","%between_number_time[4]?"]]},{"name":"between_tod_inner","bnf":[["tod_atom"]]},{"name":"%between_tod[2]","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"%between_tod[4]","bnf":[["WS+","dow_range"]],"fragment":true},{"name":"between_tod","bnf":[["between_tod_inner","%between_tod[2]","between_tod_inner","%between_tod[4]?"]]},{"name":"%between[3]","bnf":[["between_number"],["between_tod"]],"fragment":true},{"name":"between","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","%between[3]"]]},{"name":"dow","bnf":[[/[Mm]/,/[Oo]/,/[Nn]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Mm]/,/[Oo]/,/[Nn]/],[/[Tt]/,/[Uu]/,/[Ee]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Tt]/,/[Uu]/,/[Ee]/],[/[Ww]/,/[Ee]/,/[Dd]/,/[Nn]/,/[Ee]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ww]/,/[Ee]/,/[Dd]/],[/[Tt]/,/[Hh]/,/[Uu]/,/[Rr]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Tt]/,/[Hh]/,/[Uu]/],[/[Tt]/,/[Hh]/,/[Uu]/,/[Rr]/],[/[Ff]/,/[Rr]/,/[Ii]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ff]/,/[Rr]/,/[Ii]/],[/[Ss]/,/[Aa]/,/[Tt]/,/[Uu]/,/[Rr]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ss]/,/[Aa]/,/[Tt]/],[/[Ss]/,/[Uu]/,/[Nn]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ss]/,/[Uu]/,/[Nn]/]]},{"name":"dow_range_inner","bnf":[["dow_atom"]]},{"name":"%dow_range[4]","bnf":[["WS+",/[Tt]/,/[Oo]/,"WS+","dow_range_inner"]],"fragment":true},{"name":"dow_range","bnf":[[/[Oo]/,/[Nn]/,"WS+","dow_range_inner","%dow_range[4]?"]]},{"name":"between_time_only","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","between_number_time"]]},{"name":"between_tod_only","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","between_tod"]]},{"name":"%AND[1]","bnf":[["WS*",/&/,/&/,"WS*"]],"fragment":true},{"name":"%AND[2]","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"AND","bnf":[["%AND[1]"],["%AND[2]"]]},{"name":"%OR[1]","bnf":[["WS*",/\|/,/\|/,"WS*"]],"fragment":true},{"name":"%OR[2]","bnf":[["WS+",/[Oo]/,/[Rr]/,"WS+"]],"fragment":true},{"name":"OR","bnf":[["%OR[1]"],["%OR[2]"]]},{"name":"AGO","bnf":[[/[Aa]/,/[Gg]/,/[Oo]/]]},{"name":"GT","bnf":[["\">\""]]},{"name":"LT","bnf":[["\"<\""]]},{"name":"GTE","bnf":[["\">=\""]]},{"name":"LTE","bnf":[["\"<=\""]]},{"name":"IS","bnf":[[/[Ii]/,/[Ss]/]]},{"name":"EQ","bnf":[["\"==\""],["\"=\""]]},{"name":"NEQ","bnf":[["\"!=\""]]},{"name":"%NOT[1]","bnf":[[/!/,"WS*"]],"fragment":true},{"name":"%NOT[2]","bnf":[[/[Nn]/,/[Oo]/,/[Tt]/,"WS+"]],"fragment":true},{"name":"NOT","bnf":[["%NOT[1]"],["%NOT[2]"]]},{"name":"false","bnf":[[/[Ff]/,/[Aa]/,/[Ll]/,/[Ss]/,/[Ee]/]]},{"name":"null","bnf":[[/[Nn]/,/[Uu]/,/[Ll]/,/[Ll]/]]},{"name":"true","bnf":[[/[Tt]/,/[Rr]/,/[Uu]/,/[Ee]/]]},{"name":"%array[2][2]","bnf":[["VALUE_SEPARATOR","value"]],"fragment":true},{"name":"%array[2]","bnf":[["value","%array[2][2]*"]],"fragment":true},{"name":"array","bnf":[["BEGIN_ARRAY","%array[2]?","END_ARRAY"]]},{"name":"unit","bnf":[[/[Ss]/,/[Ee]/,/[Cc]/,/[Oo]/,/[Nn]/,/[Dd]/,/[Ss]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Uu]/,/[Tt]/,/[Ee]/,/[Ss]/],[/[Hh]/,/[Oo]/,/[Uu]/,/[Rr]/,/[Ss]/],[/[Ww]/,/[Ee]/,/[Ee]/,/[Kk]/,/[Ss]/],[/[Dd]/,/[Aa]/,/[Yy]/,/[Ss]/],[/[Ss]/,/[Ee]/,/[Cc]/,/[Oo]/,/[Nn]/,/[Dd]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Uu]/,/[Tt]/,/[Ee]/],[/[Ww]/,/[Ee]/,/[Ee]/,/[Kk]/],[/[Hh]/,/[Oo]/,/[Uu]/,/[Rr]/],[/[Dd]/,/[Aa]/,/[Yy]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Ss]/],[/[Mm]/,/[Ii]/,/[Nn]/]]},{"name":"%number[2][1]","bnf":[[/[0-9]/]]},{"name":"%number[2]","bnf":[["%number[2][1]+"]],"fragment":true},{"name":"%number[3][2]","bnf":[[/[0-9]/]]},{"name":"%number[3]","bnf":[["\".\"","%number[3][2]+"]],"fragment":true},{"name":"%number[4][2]","bnf":[["\"-\""],["\"+\""]],"fragment":true},{"name":"%number[4][3][2]","bnf":[[/[0-9]/]]},{"name":"%number[4][3]","bnf":[["\"0\""],[/[1-9]/,"%number[4][3][2]*"]],"fragment":true},{"name":"%number[4]","bnf":[["\"e\"","%number[4][2]?","%number[4][3]"]],"fragment":true},{"name":"number","bnf":[["\"-\"?","%number[2]","%number[3]?","%number[4]?"]]},{"name":"number_time","bnf":[["number","WS+","unit"]]},{"name":"%number_tod[1][1]","bnf":[[/[0-9]/]]},{"name":"%number_tod[1]","bnf":[["%number_tod[1][1]+"]],"fragment":true},{"name":"%number_tod[3][1]","bnf":[[/[0-9]/]]},{"name":"%number_tod[3]","bnf":[["%number_tod[3][1]+"]],"fragment":true},{"name":"number_tod","bnf":[["%number_tod[1]","\":\"","%number_tod[3]"]]},{"name":"%time_period_ago[2]","bnf":[["WS+","number_time_atom"]],"fragment":true},{"name":"time_period_ago","bnf":[["number_time_atom","%time_period_ago[2]*","WS+","AGO"]]},{"name":"%time_period_ago_between[2]","bnf":[["WS+","number_time_atom"]],"fragment":true},{"name":"time_period_ago_between","bnf":[["number_time_atom","%time_period_ago_between[2]*","WS+","AGO","WS+","between_tod_only"]]},{"name":"time_period_const","bnf":[[/[Tt]/,/[Oo]/,/[Dd]/,/[Aa]/,/[Yy]/],["time_period_ago"]]},{"name":"time_period","bnf":[["time_period_ago_between"],["time_period_const"],["between_tod_only"],["between_time_only"]]},{"name":"%string[2][1]","bnf":[[/[\x20-\x21]/],[/[\x23-\x5B]/],[/[\x5D-\uFFFF]/]],"fragment":true},{"name":"%string[2][2]","bnf":[[/\x22/],[/\x5C/],[/\x2F/],[/\x62/],[/\x66/],[/\x6E/],[/\x72/],[/\x74/],[/\x75/,"HEXDIG","HEXDIG","HEXDIG","HEXDIG"]],"fragment":true},{"name":"%string[2]","bnf":[["%string[2][1]"],[/\x5C/,"%string[2][2]"]],"fragment":true},{"name":"string","bnf":[["'\"'","%string[2]*","'\"'"]]},{"name":"HEXDIG","bnf":[[/[a-fA-F0-9]/]]}]
1924
1924
  },{}],12:[function(require,module,exports){
1925
- const {Parser} = require('ebnf/dist/Parser.js'), {ParsingError} = require('ebnf');
1925
+ const {Parser} = require('ebnf/dist/Parser.js'), {ParsingError} = require('ebnf'), RuleParseError = require('./errors/RuleParseError');
1926
1926
  let ParserRules = require('./RuleParser.production.ebnf.js');
1927
1927
  let ParserCache;
1928
1928
  const {ErrorAnalyzer} = require('./errors/ErrorAnalyzer');
@@ -2015,14 +2015,17 @@ class RuleParser {
2015
2015
  }
2016
2016
  static _parseDowRange(dowRange) {
2017
2017
  if (dowRange.children.length === 1) {
2018
+ const dayText = RuleParser.__parseValue(dowRange.children[0]);
2018
2019
  return {
2019
- start: normalizeDow(dowRange.children[0].text),
2020
- end: normalizeDow(dowRange.children[0].text)
2020
+ start: dayText,
2021
+ end: dayText
2021
2022
  };
2022
2023
  } else if (dowRange.children.length === 2) {
2024
+ const startDay = RuleParser.__parseValue(dowRange.children[0]);
2025
+ const endDay = RuleParser.__parseValue(dowRange.children[1]);
2023
2026
  return {
2024
- start: normalizeDow(dowRange.children[0].text),
2025
- end: normalizeDow(dowRange.children[1].text)
2027
+ start: startDay,
2028
+ end: endDay
2026
2029
  };
2027
2030
  } else {
2028
2031
  throw new Error(`Invalid dow_range with ${ dowRange.children.length } children`);
@@ -2043,14 +2046,15 @@ class RuleParser {
2043
2046
  let totalSeconds = 0;
2044
2047
  const components = [];
2045
2048
  for (const child of timePeriodAgo.children) {
2046
- if (child.type === 'number_time') {
2047
- const number = parseFloat(child.children[0].text);
2048
- const unit = child.children[1].text.toUpperCase();
2049
+ if (child.type === 'number_time_atom') {
2050
+ const numberTime = child.children[0];
2051
+ const number = parseFloat(numberTime.children[0].text);
2052
+ const unit = numberTime.children[1].text.toUpperCase();
2049
2053
  components.push([
2050
2054
  number,
2051
2055
  unit
2052
2056
  ]);
2053
- totalSeconds += RuleParser.__parseValue(child);
2057
+ totalSeconds += RuleParser.__parseValue(numberTime);
2054
2058
  }
2055
2059
  }
2056
2060
  if (components.length === 1) {
@@ -2075,8 +2079,8 @@ class RuleParser {
2075
2079
  let totalSeconds = 0;
2076
2080
  let betweenTodOnly = null;
2077
2081
  for (let i = 0; i < tp.children.length; i++) {
2078
- if (tp.children[i].type === 'number_time') {
2079
- totalSeconds += RuleParser.__parseValue(tp.children[i]);
2082
+ if (tp.children[i].type === 'number_time_atom') {
2083
+ totalSeconds += RuleParser.__parseValue(tp.children[i].children[0]);
2080
2084
  } else if (tp.children[i].type === 'between_tod_only') {
2081
2085
  betweenTodOnly = tp.children[i];
2082
2086
  }
@@ -2123,9 +2127,9 @@ class RuleParser {
2123
2127
  case 'between_time_only': {
2124
2128
  const betweenNumberTime = tp.children[0];
2125
2129
  const startValue = RuleParser.__parseValue(betweenNumberTime.children[0]);
2126
- const endValue = RuleParser.__parseValue(betweenNumberTime.children[1]);
2127
- if (betweenNumberTime.children.length > 2 && betweenNumberTime.children[2].type === 'dow_range') {
2128
- const dow = RuleParser._parseDowRange(betweenNumberTime.children[2]);
2130
+ const endValue = RuleParser.__parseValue(betweenNumberTime.children[2]);
2131
+ if (betweenNumberTime.children.length > 3 && betweenNumberTime.children[3].type === 'dow_range') {
2132
+ const dow = RuleParser._parseDowRange(betweenNumberTime.children[3]);
2129
2133
  if (dow.start === dow.end) {
2130
2134
  return [
2131
2135
  'TimePeriodBetween',
@@ -2154,6 +2158,22 @@ class RuleParser {
2154
2158
  static __parseValue(child) {
2155
2159
  const type = child.type;
2156
2160
  switch (type) {
2161
+ case 'value': {
2162
+ return RuleParser.__parseValue(child.children[0]);
2163
+ }
2164
+ case 'value_atom': {
2165
+ return RuleParser.__parseValue(child.children[0]);
2166
+ }
2167
+ case 'number_atom':
2168
+ case 'number_time_atom':
2169
+ case 'tod_atom':
2170
+ case 'dow_atom':
2171
+ case 'between_tod_inner':
2172
+ case 'between_number_inner':
2173
+ case 'between_number_time_inner':
2174
+ case 'dow_range_inner': {
2175
+ return RuleParser.__parseValue(child.children[0]);
2176
+ }
2157
2177
  case 'string': {
2158
2178
  const str = child.text;
2159
2179
  return str.slice(1, -1);
@@ -2209,10 +2229,13 @@ class RuleParser {
2209
2229
  case 'array': {
2210
2230
  const ret = [];
2211
2231
  for (const c of child.children) {
2212
- ret.push(RuleParser.__parseValue(c.children[0]));
2232
+ ret.push(RuleParser.__parseValue(c));
2213
2233
  }
2214
2234
  return ret;
2215
2235
  }
2236
+ case 'dow': {
2237
+ return normalizeDow(child.text);
2238
+ }
2216
2239
  default:
2217
2240
  throw new Error(`Unknown value type ${ type }`);
2218
2241
  }
@@ -2221,6 +2244,17 @@ class RuleParser {
2221
2244
  const child = value.children[0];
2222
2245
  const type = child.type;
2223
2246
  switch (type) {
2247
+ case 'value_atom': {
2248
+ const atomChild = child.children[0];
2249
+ if (atomChild.type === 'time_period') {
2250
+ const tp = atomChild.children[0];
2251
+ return RuleParser._parseTimePeriod(tp);
2252
+ }
2253
+ return [
2254
+ 'Value',
2255
+ RuleParser.__parseValue(atomChild)
2256
+ ];
2257
+ }
2224
2258
  case 'time_period': {
2225
2259
  const tp = child.children[0];
2226
2260
  return RuleParser._parseTimePeriod(tp);
@@ -2249,6 +2283,13 @@ class RuleParser {
2249
2283
  switch (type) {
2250
2284
  case 'fcall':
2251
2285
  return RuleParser._parseFcall(child);
2286
+ case 'number_atom':
2287
+ case 'number_time_atom': {
2288
+ return [
2289
+ 'Value',
2290
+ RuleParser.__parseValue(child.children[0])
2291
+ ];
2292
+ }
2252
2293
  case 'number':
2253
2294
  return [
2254
2295
  'Value',
@@ -2384,7 +2425,7 @@ class RuleParser {
2384
2425
  ],
2385
2426
  [
2386
2427
  'Value',
2387
- RuleParser.__parseValue(betweenChild.children[1])
2428
+ RuleParser.__parseValue(betweenChild.children[2])
2388
2429
  ]
2389
2430
  ];
2390
2431
  }
@@ -2399,7 +2440,7 @@ class RuleParser {
2399
2440
  ],
2400
2441
  [
2401
2442
  'Value',
2402
- RuleParser.__parseValue(rhs.children[0].children[1])
2443
+ RuleParser.__parseValue(rhs.children[0].children[2])
2403
2444
  ]
2404
2445
  ];
2405
2446
  case 'basic_rhs':
@@ -2538,8 +2579,6 @@ class RuleParser {
2538
2579
  if (e.message && e.message.includes('Invalid time of day')) {
2539
2580
  const match = e.message.match(/Invalid time of day[,:]?\s*([0-9:]+)/);
2540
2581
  const badTod = match ? match[1] : 'invalid';
2541
- const {ParsingError} = require('ebnf');
2542
- const {RuleParseError} = require('./errors/RuleParseError');
2543
2582
  const lines = txt.trim().split('\n');
2544
2583
  const position = {
2545
2584
  line: lines.length,
@@ -2551,7 +2590,6 @@ class RuleParser {
2551
2590
  if (e.message && e.message.includes('Invalid day of week')) {
2552
2591
  const match = e.message.match(/Invalid day of week[,:]?\s*(\w+)/);
2553
2592
  const badDow = match ? match[1] : 'invalid';
2554
- const {RuleParseError} = require('./errors/RuleParseError');
2555
2593
  const lines = txt.trim().split('\n');
2556
2594
  const position = {
2557
2595
  line: lines.length,
@@ -2573,11 +2611,12 @@ class RuleParser {
2573
2611
  }
2574
2612
  }
2575
2613
  module.exports = RuleParser;
2576
- module.exports.ParsingError = require('ebnf').ParsingError;
2577
- module.exports.RuleParseError = require('./errors/RuleParseError').RuleParseError;
2614
+ module.exports.ParserRules = ParserRules;
2615
+ module.exports.ParsingError = ParsingError;
2616
+ module.exports.RuleParseError = RuleParseError;
2578
2617
  },{"./RuleParser.production.ebnf.js":11,"./errors/ErrorAnalyzer":13,"./errors/RuleParseError":14,"ebnf":9,"ebnf/dist/Parser.js":5}],13:[function(require,module,exports){
2579
2618
  const { ParsingError } = require('ebnf');
2580
- const { RuleParseError } = require('./RuleParseError');
2619
+ const RuleParseError = require('./RuleParseError');
2581
2620
 
2582
2621
  /**
2583
2622
  * Analyzes parsing errors and maps them to user-friendly error codes
@@ -3565,7 +3604,7 @@ class RuleParseError extends Error {
3565
3604
  }
3566
3605
  }
3567
3606
 
3568
- module.exports = { RuleParseError };
3607
+ module.exports = RuleParseError;
3569
3608
 
3570
3609
  },{}]},{},[10])(10)
3571
3610
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@halleyassist/rule-parser",
3
- "version": "1.0.19",
3
+ "version": "1.0.20",
4
4
  "description": "The grammar for HalleyAssist rules",
5
5
  "main": "src/RuleParser.production.js",
6
6
  "browser": "./dist/rule-parser.browser.js",
@@ -5,10 +5,10 @@ statement_main ::= statement EOF
5
5
  logical_operator ||= AND | OR
6
6
  statement ::= expression (logical_operator expression)*
7
7
  expression ::= not_expression | standard_expression | parenthesis_expression
8
- parenthesis_expression::= BEGIN_PARENTHESIS WS* statement WS* END_PARENTHESIS
8
+ parenthesis_expression ::= BEGIN_PARENTHESIS WS* statement WS* END_PARENTHESIS
9
9
  not_expression ||= NOT (result | parenthesis_expression)
10
10
  standard_expression ||= result ((WS* eq_approx) | (WS* basic_rhs) | ((WS+ IS)? WS+ between) | (WS+ in_expr))?
11
- basic_rhs ::= operator WS* result
11
+ basic_rhs ::= operator WS* result
12
12
  eq_approx ::= eq_operator WS* "~" WS* result
13
13
 
14
14
  PLUS ::= "+"
@@ -18,44 +18,63 @@ DIVIDE ::= "/"
18
18
  MODULUS ::= "%"
19
19
  DEFAULT_VAL ::= "??"
20
20
  arithmetic_operator ::= PLUS | MINUS | MULTIPLY | DIVIDE | MODULUS | DEFAULT_VAL
21
- arithmetic_operand ::= fcall | number_time | number
22
- arithmetic_result ::= arithmetic_operand WS* arithmetic_operator WS* ( arithmetic_result | arithmetic_operand )
21
+
22
+ number_atom ::= number
23
+ number_time_atom ::= number_time
24
+ tod_atom ::= number_tod
25
+ dow_atom ::= dow
26
+
27
+ arithmetic_operand ::= fcall | number_time_atom | number_atom
28
+ arithmetic_result ::= arithmetic_operand WS* arithmetic_operator WS* (arithmetic_result | arithmetic_operand)
23
29
 
24
30
  simple_result ::= fcall | value
25
31
  result ::= arithmetic_result | simple_result
26
- value ::= false | true | array | time_period | number_time | number | number_tod | string
27
- BEGIN_ARRAY ::= WS* #x5B WS* /* [ left square bracket */
28
- BEGIN_OBJECT ::= WS* #x7B WS* /* { left curly bracket */
29
- END_ARRAY ::= WS* #x5D WS* /* ] right square bracket */
30
- END_OBJECT ::= WS* #x7D WS* /* } right curly bracket */
31
- NAME_SEPARATOR ::= WS* #x3A WS* /* : colon */
32
- VALUE_SEPARATOR ::= WS* #x2C WS* /* , comma */
33
- WS ::= [#x20#x09#x0A#x0D] /* Space | Tab | \n | \r */
32
+
33
+ value_atom ::= false | true | array | time_period | number_time_atom | number_atom | tod_atom | string
34
+ value ::= value_atom
35
+
36
+ BEGIN_ARRAY ::= WS* #x5B WS* /* [ */
37
+ BEGIN_OBJECT ::= WS* #x7B WS* /* { */
38
+ END_ARRAY ::= WS* #x5D WS* /* ] */
39
+ END_OBJECT ::= WS* #x7D WS* /* } */
40
+ NAME_SEPARATOR ::= WS* #x3A WS* /* : */
41
+ VALUE_SEPARATOR ::= WS* #x2C WS* /* , */
42
+ WS ::= [#x20#x09#x0A#x0D]
34
43
 
35
44
  operator ::= GTE | LTE | GT | LT | EQ | NEQ
36
45
  eq_operator ::= EQ | NEQ
37
46
 
38
47
  BEGIN_ARGUMENT ::= "("
39
48
  END_ARGUMENT ::= ")"
40
-
41
49
  BEGIN_PARENTHESIS ::= "("
42
50
  END_PARENTHESIS ::= ")"
43
51
 
44
52
  BEGIN_IN ||= "IN"
45
-
46
53
  in_expr ::= BEGIN_IN WS* BEGIN_PARENTHESIS WS* arguments END_PARENTHESIS
47
54
 
48
55
  argument ::= statement WS*
49
56
  arguments ::= argument (WS* "," WS* argument)*
50
- fname ::= [a-zA-z0-9]+
57
+ fname ::= [A-Za-z0-9]+
51
58
  fcall ::= fname WS* BEGIN_ARGUMENT WS* arguments? END_ARGUMENT
52
59
 
53
- between_number ||= (number_time | number) ((WS+ "AND" WS+) | (WS* "-" WS*)) (number_time | number)
54
- between_number_time ||= number_time ((WS+ "AND" WS+) | (WS* "-" WS*)) number_time (WS+ dow_range)?
55
- between_tod ||= number_tod ((WS+ "AND" WS+)) number_tod (WS+ dow_range)?
60
+ between_dash_or_and ||= (WS+ "AND" WS+) | (WS* "-" WS*)
61
+
62
+ between_number_inner ::= number_atom | number_time_atom
63
+ between_number ||= between_number_inner between_dash_or_and between_number_inner
64
+
65
+ between_number_time_inner ::= number_time_atom
66
+ between_number_time ||= between_number_time_inner between_dash_or_and between_number_time_inner (WS+ dow_range)?
67
+
68
+ between_tod_inner ::= tod_atom
69
+ between_tod ||= between_tod_inner (WS+ "AND" WS+) between_tod_inner (WS+ dow_range)?
70
+
56
71
  between ||= "BETWEEN" WS+ (between_number | between_tod)
72
+
57
73
  dow ||= "MONDAY" | "MON" | "TUESDAY" | "TUE" | "WEDNESDAY" | "WED" | "THURSDAY" | "THU" | "THUR" | "FRIDAY" | "FRI" | "SATURDAY" | "SAT" | "SUNDAY" | "SUN"
58
- dow_range ||= "ON" WS+ dow (WS+ "TO" WS+ dow)?
74
+
75
+ dow_range_inner ::= dow_atom
76
+ dow_range ||= "ON" WS+ dow_range_inner (WS+ "TO" WS+ dow_range_inner)?
77
+
59
78
  between_time_only ||= "BETWEEN" WS+ between_number_time
60
79
  between_tod_only ||= "BETWEEN" WS+ between_tod
61
80
 
@@ -70,18 +89,21 @@ IS ||= "is"
70
89
  EQ ::= "==" | "="
71
90
  NEQ ::= "!="
72
91
  NOT ||= ("!" WS*) | ("not" WS+)
92
+
73
93
  false ||= "FALSE"
74
94
  null ||= "null"
75
95
  true ||= "TRUE"
96
+
76
97
  array ::= BEGIN_ARRAY (value (VALUE_SEPARATOR value)*)? END_ARRAY
77
98
 
78
99
  unit ||= "seconds" | "minutes" | "hours" | "weeks" | "days" | "second" | "minute" | "week" | "hour" | "day" | "mins" | "min"
79
- number ::= "-"? ([0-9]+) ("." [0-9]+)? ("e" ( "-" | "+" )? ("0" | [1-9] [0-9]*))?
100
+
101
+ number ::= "-"? ([0-9]+) ("." [0-9]+)? ("e" ("-" | "+")? ("0" | [1-9] [0-9]*))?
80
102
  number_time ::= number WS+ unit
81
103
  number_tod ::= ([0-9]+) ":" ([0-9]+)
82
104
 
83
- time_period_ago ||= number_time (WS+ number_time)* WS+ AGO
84
- time_period_ago_between ||= number_time (WS+ number_time)* WS+ AGO WS+ between_tod_only
105
+ time_period_ago ||= number_time_atom (WS+ number_time_atom)* WS+ AGO
106
+ time_period_ago_between ||= number_time_atom (WS+ number_time_atom)* WS+ AGO WS+ between_tod_only
85
107
  time_period_const ||= "today" | time_period_ago
86
108
  time_period ::= time_period_ago_between | time_period_const | between_tod_only | between_time_only
87
109
 
package/src/RuleParser.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const {Parser} = require('ebnf/dist/Parser.js'),
2
2
  {ParsingError} = require('ebnf'),
3
- assert = require('assert')
3
+ assert = require('assert'),
4
+ RuleParseError = require('./errors/RuleParseError')
4
5
 
5
6
  let ParserRules = require('./RuleParser.ebnf.js')
6
7
  let ParserCache;
@@ -108,10 +109,14 @@ class RuleParser {
108
109
  // dow_range can have 1 or 2 children (single day or range)
109
110
  if (dowRange.children.length === 1) {
110
111
  // Single day: ON MONDAY - return just the day string
111
- return { start: normalizeDow(dowRange.children[0].text), end: normalizeDow(dowRange.children[0].text) };
112
+ // New structure: dow_range -> dow_range_inner -> dow_atom -> dow
113
+ const dayText = RuleParser.__parseValue(dowRange.children[0])
114
+ return { start: dayText, end: dayText };
112
115
  } else if (dowRange.children.length === 2) {
113
116
  // Range: ON MONDAY TO FRIDAY - return both start and end days
114
- return { start: normalizeDow(dowRange.children[0].text), end: normalizeDow(dowRange.children[1].text) };
117
+ const startDay = RuleParser.__parseValue(dowRange.children[0])
118
+ const endDay = RuleParser.__parseValue(dowRange.children[1])
119
+ return { start: startDay, end: endDay };
115
120
  } else {
116
121
  throw new Error(`Invalid dow_range with ${dowRange.children.length} children`);
117
122
  }
@@ -133,12 +138,14 @@ class RuleParser {
133
138
  let totalSeconds = 0
134
139
  const components = []
135
140
  for (const child of timePeriodAgo.children) {
136
- if (child.type === 'number_time') {
137
- const number = parseFloat(child.children[0].text)
138
- const unit = child.children[1].text.toUpperCase()
141
+ if (child.type === 'number_time_atom') {
142
+ // New structure: number_time_atom -> number_time -> number, unit
143
+ const numberTime = child.children[0]
144
+ const number = parseFloat(numberTime.children[0].text)
145
+ const unit = numberTime.children[1].text.toUpperCase()
139
146
  components.push([number, unit])
140
147
  // Parse the value to get seconds
141
- totalSeconds += RuleParser.__parseValue(child)
148
+ totalSeconds += RuleParser.__parseValue(numberTime)
142
149
  }
143
150
  }
144
151
  // If there's only one component, use its number and unit
@@ -151,15 +158,16 @@ class RuleParser {
151
158
  }
152
159
  return ["TimePeriodConst", tp.text]
153
160
  case 'time_period_ago_between': {
154
- // time_period_ago_between has: number_time (WS+ number_time)* WS+ AGO WS+ between_tod_only
161
+ // time_period_ago_between has: number_time_atom (WS+ number_time_atom)* WS+ AGO WS+ between_tod_only
155
162
  // We need to extract all number_time children and sum them up, then return TimePeriodBetweenAgo
156
163
  let totalSeconds = 0
157
164
  let betweenTodOnly = null
158
165
 
159
- // Find all number_time children and the between_tod_only child
166
+ // Find all number_time_atom children and the between_tod_only child
160
167
  for (let i = 0; i < tp.children.length; i++) {
161
- if (tp.children[i].type === 'number_time') {
162
- totalSeconds += RuleParser.__parseValue(tp.children[i])
168
+ if (tp.children[i].type === 'number_time_atom') {
169
+ // New structure: number_time_atom -> number_time
170
+ totalSeconds += RuleParser.__parseValue(tp.children[i].children[0])
163
171
  } else if (tp.children[i].type === 'between_tod_only') {
164
172
  betweenTodOnly = tp.children[i]
165
173
  }
@@ -171,6 +179,7 @@ class RuleParser {
171
179
  }
172
180
 
173
181
  const betweenTod = betweenTodOnly.children[0]
182
+ // between_tod has inline separator, so: children[0] = first tod_inner, children[1] = second tod_inner, children[2] = optional dow_range
174
183
  let startTod = RuleParser.__parseValue(betweenTod.children[0])
175
184
  let endTod = RuleParser.__parseValue(betweenTod.children[1])
176
185
 
@@ -185,6 +194,7 @@ class RuleParser {
185
194
  case 'between_tod_only': {
186
195
  // between_tod_only has children[0] = between_tod node
187
196
  const betweenTod = tp.children[0]
197
+ // between_tod has inline separator, so: children[0] = first tod_inner, children[1] = second tod_inner, children[2] = optional dow_range
188
198
  let startTod = RuleParser.__parseValue(betweenTod.children[0])
189
199
  let endTod = RuleParser.__parseValue(betweenTod.children[1])
190
200
 
@@ -200,13 +210,14 @@ class RuleParser {
200
210
  case 'between_time_only': {
201
211
  // between_time_only has children[0] = between_number_time node
202
212
  const betweenNumberTime = tp.children[0]
213
+ // between_number_time has: children[0] = first time_inner, children[1] = separator, children[2] = second time_inner, children[3] = optional dow_range
203
214
  const startValue = RuleParser.__parseValue(betweenNumberTime.children[0])
204
- const endValue = RuleParser.__parseValue(betweenNumberTime.children[1])
215
+ const endValue = RuleParser.__parseValue(betweenNumberTime.children[2])
205
216
 
206
- // Check if there's a dow_range at betweenNumberTime.children[2]
217
+ // Check if there's a dow_range at betweenNumberTime.children[3]
207
218
  // If DOW filters are provided, append them as additional parameters
208
- if (betweenNumberTime.children.length > 2 && betweenNumberTime.children[2].type === 'dow_range') {
209
- const dow = RuleParser._parseDowRange(betweenNumberTime.children[2])
219
+ if (betweenNumberTime.children.length > 3 && betweenNumberTime.children[3].type === 'dow_range') {
220
+ const dow = RuleParser._parseDowRange(betweenNumberTime.children[3])
210
221
  if (dow.start === dow.end) {
211
222
  // Single day: ["TimePeriodBetween", start, end, "MONDAY"]
212
223
  return ["TimePeriodBetween", startValue, endValue, dow.start]
@@ -223,6 +234,25 @@ class RuleParser {
223
234
  static __parseValue(child){
224
235
  const type = child.type
225
236
  switch(type){
237
+ case 'value': {
238
+ // Arrays have value nodes as children - unwrap to get value_atom
239
+ return RuleParser.__parseValue(child.children[0])
240
+ }
241
+ case 'value_atom': {
242
+ // New layer: unwrap value_atom to get the actual atomic type
243
+ return RuleParser.__parseValue(child.children[0])
244
+ }
245
+ case 'number_atom':
246
+ case 'number_time_atom':
247
+ case 'tod_atom':
248
+ case 'dow_atom':
249
+ case 'between_tod_inner':
250
+ case 'between_number_inner':
251
+ case 'between_number_time_inner':
252
+ case 'dow_range_inner': {
253
+ // New layer: unwrap atom wrappers to get the actual leaf nodes
254
+ return RuleParser.__parseValue(child.children[0])
255
+ }
226
256
  case 'string': {
227
257
  const str = child.text
228
258
  return str.slice(1, -1)
@@ -274,10 +304,13 @@ class RuleParser {
274
304
  case 'array': {
275
305
  const ret = []
276
306
  for(const c of child.children){
277
- ret.push(RuleParser.__parseValue(c.children[0]))
307
+ ret.push(RuleParser.__parseValue(c))
278
308
  }
279
309
  return ret;
280
310
  }
311
+ case 'dow': {
312
+ return normalizeDow(child.text)
313
+ }
281
314
  default:
282
315
  throw new Error(`Unknown value type ${type}`)
283
316
  }
@@ -287,7 +320,17 @@ class RuleParser {
287
320
 
288
321
  const type = child.type
289
322
  switch(type){
323
+ case 'value_atom': {
324
+ // New layer: unwrap value_atom to get the actual atomic type
325
+ const atomChild = child.children[0]
326
+ if (atomChild.type === 'time_period') {
327
+ const tp = atomChild.children[0]
328
+ return RuleParser._parseTimePeriod(tp)
329
+ }
330
+ return ['Value', RuleParser.__parseValue(atomChild)]
331
+ }
290
332
  case 'time_period': {
333
+ // Old structure (shouldn't happen with new EBNF)
291
334
  const tp = child.children[0]
292
335
  return RuleParser._parseTimePeriod(tp)
293
336
  }
@@ -314,6 +357,11 @@ class RuleParser {
314
357
  switch(type){
315
358
  case 'fcall':
316
359
  return RuleParser._parseFcall(child)
360
+ case 'number_atom':
361
+ case 'number_time_atom': {
362
+ // New layer: unwrap atom wrappers to get the actual leaf nodes
363
+ return ['Value', RuleParser.__parseValue(child.children[0])]
364
+ }
317
365
  case 'number':
318
366
  return ['Value', parseFloat(child.text)]
319
367
  case 'number_time':
@@ -406,7 +454,7 @@ class RuleParser {
406
454
  switch(rhs.type){
407
455
  case 'between_tod': {
408
456
  // Direct between_tod (without wrapping between node)
409
- // between_tod has: children[0] = first tod, children[1] = second tod, children[2] = optional dow_range
457
+ // between_tod has inline separator, so: children[0] = first tod_inner, children[1] = second tod_inner, children[2] = optional dow_range
410
458
  const startTod = RuleParser.__parseValue(rhs.children[0])
411
459
  const endTod = RuleParser.__parseValue(rhs.children[1])
412
460
 
@@ -421,7 +469,7 @@ class RuleParser {
421
469
  // between wraps either between_number or between_tod
422
470
  const betweenChild = rhs.children[0]
423
471
  if (betweenChild.type === 'between_tod') {
424
- // between_tod has: children[0] = first tod, children[1] = second tod, children[2] = optional dow_range
472
+ // between_tod has inline separator, so: children[0] = first tod_inner, children[1] = second tod_inner, children[2] = optional dow_range
425
473
  const startTod = RuleParser.__parseValue(betweenChild.children[0])
426
474
  const endTod = RuleParser.__parseValue(betweenChild.children[1])
427
475
 
@@ -432,12 +480,13 @@ class RuleParser {
432
480
 
433
481
  return ['Between', RuleParser._parseResult(expr.children[0]), ['Value', startTod], ['Value', endTod]]
434
482
  } else {
435
- // between_number - no dow support
436
- return ['Between', RuleParser._parseResult(expr.children[0]), ['Value', RuleParser.__parseValue(betweenChild.children[0])], ['Value', RuleParser.__parseValue(betweenChild.children[1])]]
483
+ // between_number has: children[0] = first number_inner, children[1] = separator, children[2] = second number_inner
484
+ return ['Between', RuleParser._parseResult(expr.children[0]), ['Value', RuleParser.__parseValue(betweenChild.children[0])], ['Value', RuleParser.__parseValue(betweenChild.children[2])]]
437
485
  }
438
486
  }
439
487
  case 'between_number':
440
- return ['Between', RuleParser._parseResult(expr.children[0]), ['Value', RuleParser.__parseValue(rhs.children[0].children[0])], ['Value', RuleParser.__parseValue(rhs.children[0].children[1])]]
488
+ // between_number has: children[0] = first number_inner, children[1] = separator, children[2] = second number_inner
489
+ return ['Between', RuleParser._parseResult(expr.children[0]), ['Value', RuleParser.__parseValue(rhs.children[0].children[0])], ['Value', RuleParser.__parseValue(rhs.children[0].children[2])]]
441
490
  case 'basic_rhs':
442
491
  return [OperatorFn[rhs.children[0].text], RuleParser._parseResult(expr.children[0]), RuleParser._parseResult(rhs.children[1])]
443
492
  case 'eq_approx': {
@@ -559,8 +608,6 @@ class RuleParser {
559
608
  // Extract the invalid time from the error message
560
609
  const match = e.message.match(/Invalid time of day[,:]?\s*([0-9:]+)/);
561
610
  const badTod = match ? match[1] : 'invalid';
562
- const { ParsingError } = require('ebnf');
563
- const { RuleParseError } = require('./errors/RuleParseError');
564
611
 
565
612
  // Calculate position (simplified - at end of input)
566
613
  const lines = txt.trim().split('\n');
@@ -585,7 +632,6 @@ class RuleParser {
585
632
  if (e.message && e.message.includes('Invalid day of week')) {
586
633
  const match = e.message.match(/Invalid day of week[,:]?\s*(\w+)/);
587
634
  const badDow = match ? match[1] : 'invalid';
588
- const { RuleParseError } = require('./errors/RuleParseError');
589
635
 
590
636
  const lines = txt.trim().split('\n');
591
637
  const position = {
@@ -611,5 +657,6 @@ class RuleParser {
611
657
  }
612
658
  }
613
659
  module.exports = RuleParser
614
- module.exports.ParsingError = require('ebnf').ParsingError
615
- module.exports.RuleParseError = require('./errors/RuleParseError').RuleParseError
660
+ module.exports.ParserRules = ParserRules
661
+ module.exports.ParsingError = ParsingError
662
+ module.exports.RuleParseError = RuleParseError
@@ -1 +1 @@
1
- module.exports=[{"name":"statement_main","bnf":[["statement","EOF"]]},{"name":"logical_operator","bnf":[["AND"],["OR"]]},{"name":"%statement[2]","bnf":[["logical_operator","expression"]],"fragment":true},{"name":"statement","bnf":[["expression","%statement[2]*"]]},{"name":"expression","bnf":[["not_expression"],["standard_expression"],["parenthesis_expression"]]},{"name":"parenthesis_expression","bnf":[["BEGIN_PARENTHESIS","WS*","statement","WS*","END_PARENTHESIS"]]},{"name":"%not_expression[2]","bnf":[["result"],["parenthesis_expression"]],"fragment":true},{"name":"not_expression","bnf":[["NOT","%not_expression[2]"]]},{"name":"%standard_expression[2][1]","bnf":[["WS*","eq_approx"]],"fragment":true},{"name":"%standard_expression[2][2]","bnf":[["WS*","basic_rhs"]],"fragment":true},{"name":"%standard_expression[2][3][1]","bnf":[["WS+","IS"]],"fragment":true},{"name":"%standard_expression[2][3]","bnf":[["%standard_expression[2][3][1]?","WS+","between"]],"fragment":true},{"name":"%standard_expression[2][4]","bnf":[["WS+","in_expr"]],"fragment":true},{"name":"%standard_expression[2]","bnf":[["%standard_expression[2][1]"],["%standard_expression[2][2]"],["%standard_expression[2][3]"],["%standard_expression[2][4]"]],"fragment":true},{"name":"standard_expression","bnf":[["result","%standard_expression[2]?"]]},{"name":"basic_rhs","bnf":[["operator","WS*","result"]]},{"name":"eq_approx","bnf":[["eq_operator","WS*","\"~\"","WS*","result"]]},{"name":"PLUS","bnf":[["\"+\""]]},{"name":"MINUS","bnf":[["\"-\""]]},{"name":"MULTIPLY","bnf":[["\"*\""]]},{"name":"DIVIDE","bnf":[["\"/\""]]},{"name":"MODULUS","bnf":[["\"%\""]]},{"name":"DEFAULT_VAL","bnf":[["\"??\""]]},{"name":"arithmetic_operator","bnf":[["PLUS"],["MINUS"],["MULTIPLY"],["DIVIDE"],["MODULUS"],["DEFAULT_VAL"]]},{"name":"arithmetic_operand","bnf":[["fcall"],["number_time"],["number"]]},{"name":"%arithmetic_result[5]","bnf":[["arithmetic_result"],["arithmetic_operand"]],"fragment":true},{"name":"arithmetic_result","bnf":[["arithmetic_operand","WS*","arithmetic_operator","WS*","%arithmetic_result[5]"]]},{"name":"simple_result","bnf":[["fcall"],["value"]]},{"name":"result","bnf":[["arithmetic_result"],["simple_result"]]},{"name":"value","bnf":[["false"],["true"],["array"],["time_period"],["number_time"],["number"],["number_tod"],["string"]]},{"name":"BEGIN_ARRAY","bnf":[["WS*",/\x5B/,"WS*"]]},{"name":"BEGIN_OBJECT","bnf":[["WS*",/\x7B/,"WS*"]]},{"name":"END_ARRAY","bnf":[["WS*",/\x5D/,"WS*"]]},{"name":"END_OBJECT","bnf":[["WS*",/\x7D/,"WS*"]]},{"name":"NAME_SEPARATOR","bnf":[["WS*",/\x3A/,"WS*"]]},{"name":"VALUE_SEPARATOR","bnf":[["WS*",/\x2C/,"WS*"]]},{"name":"WS","bnf":[[/[\x20\x09\x0A\x0D]/]]},{"name":"operator","bnf":[["GTE"],["LTE"],["GT"],["LT"],["EQ"],["NEQ"]]},{"name":"eq_operator","bnf":[["EQ"],["NEQ"]]},{"name":"BEGIN_ARGUMENT","bnf":[["\"(\""]]},{"name":"END_ARGUMENT","bnf":[["\")\""]]},{"name":"BEGIN_PARENTHESIS","bnf":[["\"(\""]]},{"name":"END_PARENTHESIS","bnf":[["\")\""]]},{"name":"BEGIN_IN","bnf":[[/[Ii]/,/[Nn]/]]},{"name":"in_expr","bnf":[["BEGIN_IN","WS*","BEGIN_PARENTHESIS","WS*","arguments","END_PARENTHESIS"]]},{"name":"argument","bnf":[["statement","WS*"]]},{"name":"%arguments[2]","bnf":[["WS*","\",\"","WS*","argument"]],"fragment":true},{"name":"arguments","bnf":[["argument","%arguments[2]*"]]},{"name":"%fname[1]","bnf":[[/[a-zA-z0-9]/]]},{"name":"fname","bnf":[["%fname[1]+"]]},{"name":"fcall","bnf":[["fname","WS*","BEGIN_ARGUMENT","WS*","arguments?","END_ARGUMENT"]]},{"name":"%between_number[1]","bnf":[["number_time"],["number"]],"fragment":true},{"name":"%between_number[2][1]","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"%between_number[2][2]","bnf":[["WS*",/\-/,"WS*"]],"fragment":true},{"name":"%between_number[2]","bnf":[["%between_number[2][1]"],["%between_number[2][2]"]],"fragment":true},{"name":"%between_number[3]","bnf":[["number_time"],["number"]],"fragment":true},{"name":"between_number","bnf":[["%between_number[1]","%between_number[2]","%between_number[3]"]]},{"name":"%between_number_time[2][1]","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"%between_number_time[2][2]","bnf":[["WS*",/\-/,"WS*"]],"fragment":true},{"name":"%between_number_time[2]","bnf":[["%between_number_time[2][1]"],["%between_number_time[2][2]"]],"fragment":true},{"name":"%between_number_time[4]","bnf":[["WS+","dow_range"]],"fragment":true},{"name":"between_number_time","bnf":[["number_time","%between_number_time[2]","number_time","%between_number_time[4]?"]]},{"name":"%between_tod[2][1]","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"%between_tod[2]","bnf":[["%between_tod[2][1]"]],"fragment":true},{"name":"%between_tod[4]","bnf":[["WS+","dow_range"]],"fragment":true},{"name":"between_tod","bnf":[["number_tod","%between_tod[2]","number_tod","%between_tod[4]?"]]},{"name":"%between[3]","bnf":[["between_number"],["between_tod"]],"fragment":true},{"name":"between","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","%between[3]"]]},{"name":"dow","bnf":[[/[Mm]/,/[Oo]/,/[Nn]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Mm]/,/[Oo]/,/[Nn]/],[/[Tt]/,/[Uu]/,/[Ee]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Tt]/,/[Uu]/,/[Ee]/],[/[Ww]/,/[Ee]/,/[Dd]/,/[Nn]/,/[Ee]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ww]/,/[Ee]/,/[Dd]/],[/[Tt]/,/[Hh]/,/[Uu]/,/[Rr]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Tt]/,/[Hh]/,/[Uu]/],[/[Tt]/,/[Hh]/,/[Uu]/,/[Rr]/],[/[Ff]/,/[Rr]/,/[Ii]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ff]/,/[Rr]/,/[Ii]/],[/[Ss]/,/[Aa]/,/[Tt]/,/[Uu]/,/[Rr]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ss]/,/[Aa]/,/[Tt]/],[/[Ss]/,/[Uu]/,/[Nn]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ss]/,/[Uu]/,/[Nn]/]]},{"name":"%dow_range[4]","bnf":[["WS+",/[Tt]/,/[Oo]/,"WS+","dow"]],"fragment":true},{"name":"dow_range","bnf":[[/[Oo]/,/[Nn]/,"WS+","dow","%dow_range[4]?"]]},{"name":"between_time_only","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","between_number_time"]]},{"name":"between_tod_only","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","between_tod"]]},{"name":"%AND[1]","bnf":[["WS*",/&/,/&/,"WS*"]],"fragment":true},{"name":"%AND[2]","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"AND","bnf":[["%AND[1]"],["%AND[2]"]]},{"name":"%OR[1]","bnf":[["WS*",/\|/,/\|/,"WS*"]],"fragment":true},{"name":"%OR[2]","bnf":[["WS+",/[Oo]/,/[Rr]/,"WS+"]],"fragment":true},{"name":"OR","bnf":[["%OR[1]"],["%OR[2]"]]},{"name":"AGO","bnf":[[/[Aa]/,/[Gg]/,/[Oo]/]]},{"name":"GT","bnf":[["\">\""]]},{"name":"LT","bnf":[["\"<\""]]},{"name":"GTE","bnf":[["\">=\""]]},{"name":"LTE","bnf":[["\"<=\""]]},{"name":"IS","bnf":[[/[Ii]/,/[Ss]/]]},{"name":"EQ","bnf":[["\"==\""],["\"=\""]]},{"name":"NEQ","bnf":[["\"!=\""]]},{"name":"%NOT[1]","bnf":[[/!/,"WS*"]],"fragment":true},{"name":"%NOT[2]","bnf":[[/[Nn]/,/[Oo]/,/[Tt]/,"WS+"]],"fragment":true},{"name":"NOT","bnf":[["%NOT[1]"],["%NOT[2]"]]},{"name":"false","bnf":[[/[Ff]/,/[Aa]/,/[Ll]/,/[Ss]/,/[Ee]/]]},{"name":"null","bnf":[[/[Nn]/,/[Uu]/,/[Ll]/,/[Ll]/]]},{"name":"true","bnf":[[/[Tt]/,/[Rr]/,/[Uu]/,/[Ee]/]]},{"name":"%array[2][2]","bnf":[["VALUE_SEPARATOR","value"]],"fragment":true},{"name":"%array[2]","bnf":[["value","%array[2][2]*"]],"fragment":true},{"name":"array","bnf":[["BEGIN_ARRAY","%array[2]?","END_ARRAY"]]},{"name":"unit","bnf":[[/[Ss]/,/[Ee]/,/[Cc]/,/[Oo]/,/[Nn]/,/[Dd]/,/[Ss]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Uu]/,/[Tt]/,/[Ee]/,/[Ss]/],[/[Hh]/,/[Oo]/,/[Uu]/,/[Rr]/,/[Ss]/],[/[Ww]/,/[Ee]/,/[Ee]/,/[Kk]/,/[Ss]/],[/[Dd]/,/[Aa]/,/[Yy]/,/[Ss]/],[/[Ss]/,/[Ee]/,/[Cc]/,/[Oo]/,/[Nn]/,/[Dd]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Uu]/,/[Tt]/,/[Ee]/],[/[Ww]/,/[Ee]/,/[Ee]/,/[Kk]/],[/[Hh]/,/[Oo]/,/[Uu]/,/[Rr]/],[/[Dd]/,/[Aa]/,/[Yy]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Ss]/],[/[Mm]/,/[Ii]/,/[Nn]/]]},{"name":"%number[2][1]","bnf":[[/[0-9]/]]},{"name":"%number[2]","bnf":[["%number[2][1]+"]],"fragment":true},{"name":"%number[3][2]","bnf":[[/[0-9]/]]},{"name":"%number[3]","bnf":[["\".\"","%number[3][2]+"]],"fragment":true},{"name":"%number[4][2]","bnf":[["\"-\""],["\"+\""]],"fragment":true},{"name":"%number[4][3][2]","bnf":[[/[0-9]/]]},{"name":"%number[4][3]","bnf":[["\"0\""],[/[1-9]/,"%number[4][3][2]*"]],"fragment":true},{"name":"%number[4]","bnf":[["\"e\"","%number[4][2]?","%number[4][3]"]],"fragment":true},{"name":"number","bnf":[["\"-\"?","%number[2]","%number[3]?","%number[4]?"]]},{"name":"number_time","bnf":[["number","WS+","unit"]]},{"name":"%number_tod[1][1]","bnf":[[/[0-9]/]]},{"name":"%number_tod[1]","bnf":[["%number_tod[1][1]+"]],"fragment":true},{"name":"%number_tod[3][1]","bnf":[[/[0-9]/]]},{"name":"%number_tod[3]","bnf":[["%number_tod[3][1]+"]],"fragment":true},{"name":"number_tod","bnf":[["%number_tod[1]","\":\"","%number_tod[3]"]]},{"name":"%time_period_ago[2]","bnf":[["WS+","number_time"]],"fragment":true},{"name":"time_period_ago","bnf":[["number_time","%time_period_ago[2]*","WS+","AGO"]]},{"name":"%time_period_ago_between[2]","bnf":[["WS+","number_time"]],"fragment":true},{"name":"time_period_ago_between","bnf":[["number_time","%time_period_ago_between[2]*","WS+","AGO","WS+","between_tod_only"]]},{"name":"time_period_const","bnf":[[/[Tt]/,/[Oo]/,/[Dd]/,/[Aa]/,/[Yy]/],["time_period_ago"]]},{"name":"time_period","bnf":[["time_period_ago_between"],["time_period_const"],["between_tod_only"],["between_time_only"]]},{"name":"%string[2][1]","bnf":[[/[\x20-\x21]/],[/[\x23-\x5B]/],[/[\x5D-\uFFFF]/]],"fragment":true},{"name":"%string[2][2]","bnf":[[/\x22/],[/\x5C/],[/\x2F/],[/\x62/],[/\x66/],[/\x6E/],[/\x72/],[/\x74/],[/\x75/,"HEXDIG","HEXDIG","HEXDIG","HEXDIG"]],"fragment":true},{"name":"%string[2]","bnf":[["%string[2][1]"],[/\x5C/,"%string[2][2]"]],"fragment":true},{"name":"string","bnf":[["'\"'","%string[2]*","'\"'"]]},{"name":"HEXDIG","bnf":[[/[a-fA-F0-9]/]]}]
1
+ module.exports=[{"name":"statement_main","bnf":[["statement","EOF"]]},{"name":"logical_operator","bnf":[["AND"],["OR"]]},{"name":"%statement[2]","bnf":[["logical_operator","expression"]],"fragment":true},{"name":"statement","bnf":[["expression","%statement[2]*"]]},{"name":"expression","bnf":[["not_expression"],["standard_expression"],["parenthesis_expression"]]},{"name":"parenthesis_expression","bnf":[["BEGIN_PARENTHESIS","WS*","statement","WS*","END_PARENTHESIS"]]},{"name":"%not_expression[2]","bnf":[["result"],["parenthesis_expression"]],"fragment":true},{"name":"not_expression","bnf":[["NOT","%not_expression[2]"]]},{"name":"%standard_expression[2][1]","bnf":[["WS*","eq_approx"]],"fragment":true},{"name":"%standard_expression[2][2]","bnf":[["WS*","basic_rhs"]],"fragment":true},{"name":"%standard_expression[2][3][1]","bnf":[["WS+","IS"]],"fragment":true},{"name":"%standard_expression[2][3]","bnf":[["%standard_expression[2][3][1]?","WS+","between"]],"fragment":true},{"name":"%standard_expression[2][4]","bnf":[["WS+","in_expr"]],"fragment":true},{"name":"%standard_expression[2]","bnf":[["%standard_expression[2][1]"],["%standard_expression[2][2]"],["%standard_expression[2][3]"],["%standard_expression[2][4]"]],"fragment":true},{"name":"standard_expression","bnf":[["result","%standard_expression[2]?"]]},{"name":"basic_rhs","bnf":[["operator","WS*","result"]]},{"name":"eq_approx","bnf":[["eq_operator","WS*","\"~\"","WS*","result"]]},{"name":"PLUS","bnf":[["\"+\""]]},{"name":"MINUS","bnf":[["\"-\""]]},{"name":"MULTIPLY","bnf":[["\"*\""]]},{"name":"DIVIDE","bnf":[["\"/\""]]},{"name":"MODULUS","bnf":[["\"%\""]]},{"name":"DEFAULT_VAL","bnf":[["\"??\""]]},{"name":"arithmetic_operator","bnf":[["PLUS"],["MINUS"],["MULTIPLY"],["DIVIDE"],["MODULUS"],["DEFAULT_VAL"]]},{"name":"number_atom","bnf":[["number"]]},{"name":"number_time_atom","bnf":[["number_time"]]},{"name":"tod_atom","bnf":[["number_tod"]]},{"name":"dow_atom","bnf":[["dow"]]},{"name":"arithmetic_operand","bnf":[["fcall"],["number_time_atom"],["number_atom"]]},{"name":"%arithmetic_result[5]","bnf":[["arithmetic_result"],["arithmetic_operand"]],"fragment":true},{"name":"arithmetic_result","bnf":[["arithmetic_operand","WS*","arithmetic_operator","WS*","%arithmetic_result[5]"]]},{"name":"simple_result","bnf":[["fcall"],["value"]]},{"name":"result","bnf":[["arithmetic_result"],["simple_result"]]},{"name":"value_atom","bnf":[["false"],["true"],["array"],["time_period"],["number_time_atom"],["number_atom"],["tod_atom"],["string"]]},{"name":"value","bnf":[["value_atom"]]},{"name":"BEGIN_ARRAY","bnf":[["WS*",/\x5B/,"WS*"]]},{"name":"BEGIN_OBJECT","bnf":[["WS*",/\x7B/,"WS*"]]},{"name":"END_ARRAY","bnf":[["WS*",/\x5D/,"WS*"]]},{"name":"END_OBJECT","bnf":[["WS*",/\x7D/,"WS*"]]},{"name":"NAME_SEPARATOR","bnf":[["WS*",/\x3A/,"WS*"]]},{"name":"VALUE_SEPARATOR","bnf":[["WS*",/\x2C/,"WS*"]]},{"name":"WS","bnf":[[/[\x20\x09\x0A\x0D]/]]},{"name":"operator","bnf":[["GTE"],["LTE"],["GT"],["LT"],["EQ"],["NEQ"]]},{"name":"eq_operator","bnf":[["EQ"],["NEQ"]]},{"name":"BEGIN_ARGUMENT","bnf":[["\"(\""]]},{"name":"END_ARGUMENT","bnf":[["\")\""]]},{"name":"BEGIN_PARENTHESIS","bnf":[["\"(\""]]},{"name":"END_PARENTHESIS","bnf":[["\")\""]]},{"name":"BEGIN_IN","bnf":[[/[Ii]/,/[Nn]/]]},{"name":"in_expr","bnf":[["BEGIN_IN","WS*","BEGIN_PARENTHESIS","WS*","arguments","END_PARENTHESIS"]]},{"name":"argument","bnf":[["statement","WS*"]]},{"name":"%arguments[2]","bnf":[["WS*","\",\"","WS*","argument"]],"fragment":true},{"name":"arguments","bnf":[["argument","%arguments[2]*"]]},{"name":"%fname[1]","bnf":[[/[A-Za-z0-9]/]]},{"name":"fname","bnf":[["%fname[1]+"]]},{"name":"fcall","bnf":[["fname","WS*","BEGIN_ARGUMENT","WS*","arguments?","END_ARGUMENT"]]},{"name":"%between_dash_or_and[1]","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"%between_dash_or_and[2]","bnf":[["WS*",/\-/,"WS*"]],"fragment":true},{"name":"between_dash_or_and","bnf":[["%between_dash_or_and[1]"],["%between_dash_or_and[2]"]]},{"name":"between_number_inner","bnf":[["number_atom"],["number_time_atom"]]},{"name":"between_number","bnf":[["between_number_inner","between_dash_or_and","between_number_inner"]]},{"name":"between_number_time_inner","bnf":[["number_time_atom"]]},{"name":"%between_number_time[4]","bnf":[["WS+","dow_range"]],"fragment":true},{"name":"between_number_time","bnf":[["between_number_time_inner","between_dash_or_and","between_number_time_inner","%between_number_time[4]?"]]},{"name":"between_tod_inner","bnf":[["tod_atom"]]},{"name":"%between_tod[2]","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"%between_tod[4]","bnf":[["WS+","dow_range"]],"fragment":true},{"name":"between_tod","bnf":[["between_tod_inner","%between_tod[2]","between_tod_inner","%between_tod[4]?"]]},{"name":"%between[3]","bnf":[["between_number"],["between_tod"]],"fragment":true},{"name":"between","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","%between[3]"]]},{"name":"dow","bnf":[[/[Mm]/,/[Oo]/,/[Nn]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Mm]/,/[Oo]/,/[Nn]/],[/[Tt]/,/[Uu]/,/[Ee]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Tt]/,/[Uu]/,/[Ee]/],[/[Ww]/,/[Ee]/,/[Dd]/,/[Nn]/,/[Ee]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ww]/,/[Ee]/,/[Dd]/],[/[Tt]/,/[Hh]/,/[Uu]/,/[Rr]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Tt]/,/[Hh]/,/[Uu]/],[/[Tt]/,/[Hh]/,/[Uu]/,/[Rr]/],[/[Ff]/,/[Rr]/,/[Ii]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ff]/,/[Rr]/,/[Ii]/],[/[Ss]/,/[Aa]/,/[Tt]/,/[Uu]/,/[Rr]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ss]/,/[Aa]/,/[Tt]/],[/[Ss]/,/[Uu]/,/[Nn]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ss]/,/[Uu]/,/[Nn]/]]},{"name":"dow_range_inner","bnf":[["dow_atom"]]},{"name":"%dow_range[4]","bnf":[["WS+",/[Tt]/,/[Oo]/,"WS+","dow_range_inner"]],"fragment":true},{"name":"dow_range","bnf":[[/[Oo]/,/[Nn]/,"WS+","dow_range_inner","%dow_range[4]?"]]},{"name":"between_time_only","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","between_number_time"]]},{"name":"between_tod_only","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","between_tod"]]},{"name":"%AND[1]","bnf":[["WS*",/&/,/&/,"WS*"]],"fragment":true},{"name":"%AND[2]","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"AND","bnf":[["%AND[1]"],["%AND[2]"]]},{"name":"%OR[1]","bnf":[["WS*",/\|/,/\|/,"WS*"]],"fragment":true},{"name":"%OR[2]","bnf":[["WS+",/[Oo]/,/[Rr]/,"WS+"]],"fragment":true},{"name":"OR","bnf":[["%OR[1]"],["%OR[2]"]]},{"name":"AGO","bnf":[[/[Aa]/,/[Gg]/,/[Oo]/]]},{"name":"GT","bnf":[["\">\""]]},{"name":"LT","bnf":[["\"<\""]]},{"name":"GTE","bnf":[["\">=\""]]},{"name":"LTE","bnf":[["\"<=\""]]},{"name":"IS","bnf":[[/[Ii]/,/[Ss]/]]},{"name":"EQ","bnf":[["\"==\""],["\"=\""]]},{"name":"NEQ","bnf":[["\"!=\""]]},{"name":"%NOT[1]","bnf":[[/!/,"WS*"]],"fragment":true},{"name":"%NOT[2]","bnf":[[/[Nn]/,/[Oo]/,/[Tt]/,"WS+"]],"fragment":true},{"name":"NOT","bnf":[["%NOT[1]"],["%NOT[2]"]]},{"name":"false","bnf":[[/[Ff]/,/[Aa]/,/[Ll]/,/[Ss]/,/[Ee]/]]},{"name":"null","bnf":[[/[Nn]/,/[Uu]/,/[Ll]/,/[Ll]/]]},{"name":"true","bnf":[[/[Tt]/,/[Rr]/,/[Uu]/,/[Ee]/]]},{"name":"%array[2][2]","bnf":[["VALUE_SEPARATOR","value"]],"fragment":true},{"name":"%array[2]","bnf":[["value","%array[2][2]*"]],"fragment":true},{"name":"array","bnf":[["BEGIN_ARRAY","%array[2]?","END_ARRAY"]]},{"name":"unit","bnf":[[/[Ss]/,/[Ee]/,/[Cc]/,/[Oo]/,/[Nn]/,/[Dd]/,/[Ss]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Uu]/,/[Tt]/,/[Ee]/,/[Ss]/],[/[Hh]/,/[Oo]/,/[Uu]/,/[Rr]/,/[Ss]/],[/[Ww]/,/[Ee]/,/[Ee]/,/[Kk]/,/[Ss]/],[/[Dd]/,/[Aa]/,/[Yy]/,/[Ss]/],[/[Ss]/,/[Ee]/,/[Cc]/,/[Oo]/,/[Nn]/,/[Dd]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Uu]/,/[Tt]/,/[Ee]/],[/[Ww]/,/[Ee]/,/[Ee]/,/[Kk]/],[/[Hh]/,/[Oo]/,/[Uu]/,/[Rr]/],[/[Dd]/,/[Aa]/,/[Yy]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Ss]/],[/[Mm]/,/[Ii]/,/[Nn]/]]},{"name":"%number[2][1]","bnf":[[/[0-9]/]]},{"name":"%number[2]","bnf":[["%number[2][1]+"]],"fragment":true},{"name":"%number[3][2]","bnf":[[/[0-9]/]]},{"name":"%number[3]","bnf":[["\".\"","%number[3][2]+"]],"fragment":true},{"name":"%number[4][2]","bnf":[["\"-\""],["\"+\""]],"fragment":true},{"name":"%number[4][3][2]","bnf":[[/[0-9]/]]},{"name":"%number[4][3]","bnf":[["\"0\""],[/[1-9]/,"%number[4][3][2]*"]],"fragment":true},{"name":"%number[4]","bnf":[["\"e\"","%number[4][2]?","%number[4][3]"]],"fragment":true},{"name":"number","bnf":[["\"-\"?","%number[2]","%number[3]?","%number[4]?"]]},{"name":"number_time","bnf":[["number","WS+","unit"]]},{"name":"%number_tod[1][1]","bnf":[[/[0-9]/]]},{"name":"%number_tod[1]","bnf":[["%number_tod[1][1]+"]],"fragment":true},{"name":"%number_tod[3][1]","bnf":[[/[0-9]/]]},{"name":"%number_tod[3]","bnf":[["%number_tod[3][1]+"]],"fragment":true},{"name":"number_tod","bnf":[["%number_tod[1]","\":\"","%number_tod[3]"]]},{"name":"%time_period_ago[2]","bnf":[["WS+","number_time_atom"]],"fragment":true},{"name":"time_period_ago","bnf":[["number_time_atom","%time_period_ago[2]*","WS+","AGO"]]},{"name":"%time_period_ago_between[2]","bnf":[["WS+","number_time_atom"]],"fragment":true},{"name":"time_period_ago_between","bnf":[["number_time_atom","%time_period_ago_between[2]*","WS+","AGO","WS+","between_tod_only"]]},{"name":"time_period_const","bnf":[[/[Tt]/,/[Oo]/,/[Dd]/,/[Aa]/,/[Yy]/],["time_period_ago"]]},{"name":"time_period","bnf":[["time_period_ago_between"],["time_period_const"],["between_tod_only"],["between_time_only"]]},{"name":"%string[2][1]","bnf":[[/[\x20-\x21]/],[/[\x23-\x5B]/],[/[\x5D-\uFFFF]/]],"fragment":true},{"name":"%string[2][2]","bnf":[[/\x22/],[/\x5C/],[/\x2F/],[/\x62/],[/\x66/],[/\x6E/],[/\x72/],[/\x74/],[/\x75/,"HEXDIG","HEXDIG","HEXDIG","HEXDIG"]],"fragment":true},{"name":"%string[2]","bnf":[["%string[2][1]"],[/\x5C/,"%string[2][2]"]],"fragment":true},{"name":"string","bnf":[["'\"'","%string[2]*","'\"'"]]},{"name":"HEXDIG","bnf":[[/[a-fA-F0-9]/]]}]
@@ -1,6 +1,7 @@
1
1
  const {Parser} = require('ebnf/dist/Parser.js'),
2
2
  {ParsingError} = require('ebnf'),
3
- assert = require('assert')
3
+ assert = require('assert'),
4
+ RuleParseError = require('./errors/RuleParseError')
4
5
 
5
6
  let ParserRules = require('./RuleParser.production.ebnf.js')
6
7
  let ParserCache;
@@ -108,10 +109,14 @@ class RuleParser {
108
109
  // dow_range can have 1 or 2 children (single day or range)
109
110
  if (dowRange.children.length === 1) {
110
111
  // Single day: ON MONDAY - return just the day string
111
- return { start: normalizeDow(dowRange.children[0].text), end: normalizeDow(dowRange.children[0].text) };
112
+ // New structure: dow_range -> dow_range_inner -> dow_atom -> dow
113
+ const dayText = RuleParser.__parseValue(dowRange.children[0])
114
+ return { start: dayText, end: dayText };
112
115
  } else if (dowRange.children.length === 2) {
113
116
  // Range: ON MONDAY TO FRIDAY - return both start and end days
114
- return { start: normalizeDow(dowRange.children[0].text), end: normalizeDow(dowRange.children[1].text) };
117
+ const startDay = RuleParser.__parseValue(dowRange.children[0])
118
+ const endDay = RuleParser.__parseValue(dowRange.children[1])
119
+ return { start: startDay, end: endDay };
115
120
  } else {
116
121
  throw new Error(`Invalid dow_range with ${dowRange.children.length} children`);
117
122
  }
@@ -133,12 +138,14 @@ class RuleParser {
133
138
  let totalSeconds = 0
134
139
  const components = []
135
140
  for (const child of timePeriodAgo.children) {
136
- if (child.type === 'number_time') {
137
- const number = parseFloat(child.children[0].text)
138
- const unit = child.children[1].text.toUpperCase()
141
+ if (child.type === 'number_time_atom') {
142
+ // New structure: number_time_atom -> number_time -> number, unit
143
+ const numberTime = child.children[0]
144
+ const number = parseFloat(numberTime.children[0].text)
145
+ const unit = numberTime.children[1].text.toUpperCase()
139
146
  components.push([number, unit])
140
147
  // Parse the value to get seconds
141
- totalSeconds += RuleParser.__parseValue(child)
148
+ totalSeconds += RuleParser.__parseValue(numberTime)
142
149
  }
143
150
  }
144
151
  // If there's only one component, use its number and unit
@@ -151,15 +158,16 @@ class RuleParser {
151
158
  }
152
159
  return ["TimePeriodConst", tp.text]
153
160
  case 'time_period_ago_between': {
154
- // time_period_ago_between has: number_time (WS+ number_time)* WS+ AGO WS+ between_tod_only
161
+ // time_period_ago_between has: number_time_atom (WS+ number_time_atom)* WS+ AGO WS+ between_tod_only
155
162
  // We need to extract all number_time children and sum them up, then return TimePeriodBetweenAgo
156
163
  let totalSeconds = 0
157
164
  let betweenTodOnly = null
158
165
 
159
- // Find all number_time children and the between_tod_only child
166
+ // Find all number_time_atom children and the between_tod_only child
160
167
  for (let i = 0; i < tp.children.length; i++) {
161
- if (tp.children[i].type === 'number_time') {
162
- totalSeconds += RuleParser.__parseValue(tp.children[i])
168
+ if (tp.children[i].type === 'number_time_atom') {
169
+ // New structure: number_time_atom -> number_time
170
+ totalSeconds += RuleParser.__parseValue(tp.children[i].children[0])
163
171
  } else if (tp.children[i].type === 'between_tod_only') {
164
172
  betweenTodOnly = tp.children[i]
165
173
  }
@@ -171,6 +179,7 @@ class RuleParser {
171
179
  }
172
180
 
173
181
  const betweenTod = betweenTodOnly.children[0]
182
+ // between_tod has inline separator, so: children[0] = first tod_inner, children[1] = second tod_inner, children[2] = optional dow_range
174
183
  let startTod = RuleParser.__parseValue(betweenTod.children[0])
175
184
  let endTod = RuleParser.__parseValue(betweenTod.children[1])
176
185
 
@@ -185,6 +194,7 @@ class RuleParser {
185
194
  case 'between_tod_only': {
186
195
  // between_tod_only has children[0] = between_tod node
187
196
  const betweenTod = tp.children[0]
197
+ // between_tod has inline separator, so: children[0] = first tod_inner, children[1] = second tod_inner, children[2] = optional dow_range
188
198
  let startTod = RuleParser.__parseValue(betweenTod.children[0])
189
199
  let endTod = RuleParser.__parseValue(betweenTod.children[1])
190
200
 
@@ -200,13 +210,14 @@ class RuleParser {
200
210
  case 'between_time_only': {
201
211
  // between_time_only has children[0] = between_number_time node
202
212
  const betweenNumberTime = tp.children[0]
213
+ // between_number_time has: children[0] = first time_inner, children[1] = separator, children[2] = second time_inner, children[3] = optional dow_range
203
214
  const startValue = RuleParser.__parseValue(betweenNumberTime.children[0])
204
- const endValue = RuleParser.__parseValue(betweenNumberTime.children[1])
215
+ const endValue = RuleParser.__parseValue(betweenNumberTime.children[2])
205
216
 
206
- // Check if there's a dow_range at betweenNumberTime.children[2]
217
+ // Check if there's a dow_range at betweenNumberTime.children[3]
207
218
  // If DOW filters are provided, append them as additional parameters
208
- if (betweenNumberTime.children.length > 2 && betweenNumberTime.children[2].type === 'dow_range') {
209
- const dow = RuleParser._parseDowRange(betweenNumberTime.children[2])
219
+ if (betweenNumberTime.children.length > 3 && betweenNumberTime.children[3].type === 'dow_range') {
220
+ const dow = RuleParser._parseDowRange(betweenNumberTime.children[3])
210
221
  if (dow.start === dow.end) {
211
222
  // Single day: ["TimePeriodBetween", start, end, "MONDAY"]
212
223
  return ["TimePeriodBetween", startValue, endValue, dow.start]
@@ -223,6 +234,25 @@ class RuleParser {
223
234
  static __parseValue(child){
224
235
  const type = child.type
225
236
  switch(type){
237
+ case 'value': {
238
+ // Arrays have value nodes as children - unwrap to get value_atom
239
+ return RuleParser.__parseValue(child.children[0])
240
+ }
241
+ case 'value_atom': {
242
+ // New layer: unwrap value_atom to get the actual atomic type
243
+ return RuleParser.__parseValue(child.children[0])
244
+ }
245
+ case 'number_atom':
246
+ case 'number_time_atom':
247
+ case 'tod_atom':
248
+ case 'dow_atom':
249
+ case 'between_tod_inner':
250
+ case 'between_number_inner':
251
+ case 'between_number_time_inner':
252
+ case 'dow_range_inner': {
253
+ // New layer: unwrap atom wrappers to get the actual leaf nodes
254
+ return RuleParser.__parseValue(child.children[0])
255
+ }
226
256
  case 'string': {
227
257
  const str = child.text
228
258
  return str.slice(1, -1)
@@ -274,10 +304,13 @@ class RuleParser {
274
304
  case 'array': {
275
305
  const ret = []
276
306
  for(const c of child.children){
277
- ret.push(RuleParser.__parseValue(c.children[0]))
307
+ ret.push(RuleParser.__parseValue(c))
278
308
  }
279
309
  return ret;
280
310
  }
311
+ case 'dow': {
312
+ return normalizeDow(child.text)
313
+ }
281
314
  default:
282
315
  throw new Error(`Unknown value type ${type}`)
283
316
  }
@@ -287,7 +320,17 @@ class RuleParser {
287
320
 
288
321
  const type = child.type
289
322
  switch(type){
323
+ case 'value_atom': {
324
+ // New layer: unwrap value_atom to get the actual atomic type
325
+ const atomChild = child.children[0]
326
+ if (atomChild.type === 'time_period') {
327
+ const tp = atomChild.children[0]
328
+ return RuleParser._parseTimePeriod(tp)
329
+ }
330
+ return ['Value', RuleParser.__parseValue(atomChild)]
331
+ }
290
332
  case 'time_period': {
333
+ // Old structure (shouldn't happen with new EBNF)
291
334
  const tp = child.children[0]
292
335
  return RuleParser._parseTimePeriod(tp)
293
336
  }
@@ -314,6 +357,11 @@ class RuleParser {
314
357
  switch(type){
315
358
  case 'fcall':
316
359
  return RuleParser._parseFcall(child)
360
+ case 'number_atom':
361
+ case 'number_time_atom': {
362
+ // New layer: unwrap atom wrappers to get the actual leaf nodes
363
+ return ['Value', RuleParser.__parseValue(child.children[0])]
364
+ }
317
365
  case 'number':
318
366
  return ['Value', parseFloat(child.text)]
319
367
  case 'number_time':
@@ -406,7 +454,7 @@ class RuleParser {
406
454
  switch(rhs.type){
407
455
  case 'between_tod': {
408
456
  // Direct between_tod (without wrapping between node)
409
- // between_tod has: children[0] = first tod, children[1] = second tod, children[2] = optional dow_range
457
+ // between_tod has inline separator, so: children[0] = first tod_inner, children[1] = second tod_inner, children[2] = optional dow_range
410
458
  const startTod = RuleParser.__parseValue(rhs.children[0])
411
459
  const endTod = RuleParser.__parseValue(rhs.children[1])
412
460
 
@@ -421,7 +469,7 @@ class RuleParser {
421
469
  // between wraps either between_number or between_tod
422
470
  const betweenChild = rhs.children[0]
423
471
  if (betweenChild.type === 'between_tod') {
424
- // between_tod has: children[0] = first tod, children[1] = second tod, children[2] = optional dow_range
472
+ // between_tod has inline separator, so: children[0] = first tod_inner, children[1] = second tod_inner, children[2] = optional dow_range
425
473
  const startTod = RuleParser.__parseValue(betweenChild.children[0])
426
474
  const endTod = RuleParser.__parseValue(betweenChild.children[1])
427
475
 
@@ -432,12 +480,13 @@ class RuleParser {
432
480
 
433
481
  return ['Between', RuleParser._parseResult(expr.children[0]), ['Value', startTod], ['Value', endTod]]
434
482
  } else {
435
- // between_number - no dow support
436
- return ['Between', RuleParser._parseResult(expr.children[0]), ['Value', RuleParser.__parseValue(betweenChild.children[0])], ['Value', RuleParser.__parseValue(betweenChild.children[1])]]
483
+ // between_number has: children[0] = first number_inner, children[1] = separator, children[2] = second number_inner
484
+ return ['Between', RuleParser._parseResult(expr.children[0]), ['Value', RuleParser.__parseValue(betweenChild.children[0])], ['Value', RuleParser.__parseValue(betweenChild.children[2])]]
437
485
  }
438
486
  }
439
487
  case 'between_number':
440
- return ['Between', RuleParser._parseResult(expr.children[0]), ['Value', RuleParser.__parseValue(rhs.children[0].children[0])], ['Value', RuleParser.__parseValue(rhs.children[0].children[1])]]
488
+ // between_number has: children[0] = first number_inner, children[1] = separator, children[2] = second number_inner
489
+ return ['Between', RuleParser._parseResult(expr.children[0]), ['Value', RuleParser.__parseValue(rhs.children[0].children[0])], ['Value', RuleParser.__parseValue(rhs.children[0].children[2])]]
441
490
  case 'basic_rhs':
442
491
  return [OperatorFn[rhs.children[0].text], RuleParser._parseResult(expr.children[0]), RuleParser._parseResult(rhs.children[1])]
443
492
  case 'eq_approx': {
@@ -559,8 +608,6 @@ class RuleParser {
559
608
  // Extract the invalid time from the error message
560
609
  const match = e.message.match(/Invalid time of day[,:]?\s*([0-9:]+)/);
561
610
  const badTod = match ? match[1] : 'invalid';
562
- const { ParsingError } = require('ebnf');
563
- const { RuleParseError } = require('./errors/RuleParseError');
564
611
 
565
612
  // Calculate position (simplified - at end of input)
566
613
  const lines = txt.trim().split('\n');
@@ -585,7 +632,6 @@ class RuleParser {
585
632
  if (e.message && e.message.includes('Invalid day of week')) {
586
633
  const match = e.message.match(/Invalid day of week[,:]?\s*(\w+)/);
587
634
  const badDow = match ? match[1] : 'invalid';
588
- const { RuleParseError } = require('./errors/RuleParseError');
589
635
 
590
636
  const lines = txt.trim().split('\n');
591
637
  const position = {
@@ -611,5 +657,6 @@ class RuleParser {
611
657
  }
612
658
  }
613
659
  module.exports = RuleParser
614
- module.exports.ParsingError = require('ebnf').ParsingError
615
- module.exports.RuleParseError = require('./errors/RuleParseError').RuleParseError
660
+ module.exports.ParserRules = ParserRules
661
+ module.exports.ParsingError = ParsingError
662
+ module.exports.RuleParseError = RuleParseError
@@ -1,5 +1,5 @@
1
1
  const { ParsingError } = require('ebnf');
2
- const { RuleParseError } = require('./RuleParseError');
2
+ const RuleParseError = require('./RuleParseError');
3
3
 
4
4
  /**
5
5
  * Analyzes parsing errors and maps them to user-friendly error codes
@@ -61,4 +61,4 @@ class RuleParseError extends Error {
61
61
  }
62
62
  }
63
63
 
64
- module.exports = { RuleParseError };
64
+ module.exports = RuleParseError;