@halleyassist/rule-parser 1.0.8 → 1.0.9

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@halleyassist/rule-parser",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "The grammar for HalleyAssist rules",
5
5
  "main": "src/RuleParser.production.js",
6
6
  "scripts": {
@@ -45,9 +45,12 @@ arguments ::= argument*
45
45
  fname ::= [a-zA-z0-9]+
46
46
  fcall ::= fname WS* BEGIN_ARGUMENT WS* arguments? END_ARGUMENT
47
47
 
48
- between_number ||= number ((WS+ "AND" WS+) | (WS* "-" WS*)) number
49
- between_tod ||= number_tod ((WS+ "AND" WS+)) number_tod
48
+ between_number ||= (number_time | number) ((WS+ "AND" WS+) | (WS* "-" WS*)) (number_time | number)
49
+ between_tod ||= number_tod ((WS+ "AND" WS+)) number_tod (WS+ dow_range)?
50
50
  between ||= "BETWEEN" WS+ (between_number | between_tod)
51
+ dow ||= "MONDAY" | "TUESDAY" | "WEDNESDAY" | "THURSDAY" | "FRIDAY" | "SATURDAY" | "SUNDAY"
52
+ dow_range ||= "ON" WS+ dow (WS+ "TO" WS+ dow)?
53
+ between_number_only ||= "BETWEEN" WS+ between_number
51
54
  between_tod_only ||= "BETWEEN" WS+ between_tod
52
55
 
53
56
  AND ||= (WS* "&&" WS*) | (WS+ "AND" WS+)
@@ -71,7 +74,7 @@ number_time ::= number WS+ unit
71
74
  number_tod ::= ([0-9]+) ":" ([0-9]+)
72
75
 
73
76
  time_period_const ||= "today"
74
- time_period ::= time_period_const | between_tod_only
77
+ time_period ::= time_period_const | between_tod_only | between_number_only
75
78
 
76
79
  string ::= '"' (([#x20-#x21] | [#x23-#x5B] | [#x5D-#xFFFF]) | #x5C (#x22 | #x5C | #x2F | #x62 | #x66 | #x6E | #x72 | #x74 | #x75 HEXDIG HEXDIG HEXDIG HEXDIG))* '"'
77
80
  HEXDIG ::= [a-fA-F0-9]
package/src/RuleParser.js CHANGED
@@ -62,12 +62,55 @@ class RuleParser {
62
62
  }
63
63
  return ret
64
64
  }
65
+ static _parseDowRange(dowRange) {
66
+ const dow = []
67
+
68
+ // dow_range can have 1 or 2 children (single day or range)
69
+ if (dowRange.children.length === 1) {
70
+ // Single day: ON MONDAY
71
+ dow.push(dowRange.children[0].text.toLowerCase())
72
+ } else if (dowRange.children.length === 2) {
73
+ // Range: ON MONDAY TO WEDNESDAY
74
+ dow.push(dowRange.children[0].text.toLowerCase())
75
+ dow.push(dowRange.children[1].text.toLowerCase())
76
+ } else {
77
+ throw new Error(`Invalid dow_range with ${dowRange.children.length} children`)
78
+ }
79
+
80
+ return dow
81
+ }
82
+ static _addDowToTods(startTod, endTod, dowRange) {
83
+ if (dowRange && dowRange.type === 'dow_range') {
84
+ const dow = RuleParser._parseDowRange(dowRange)
85
+ startTod.dow = dow
86
+ endTod.dow = dow
87
+ }
88
+ }
65
89
  static _parseTimePeriod(tp){
66
90
  switch(tp.type){
67
91
  case 'time_period_const':
68
92
  return ["TimePeriodConst", tp.text]
69
- case 'between_tod_only':
70
- return ["TimePeriodBetween", RuleParser.__parseValue(tp.children[0]?.children[0]), RuleParser.__parseValue(tp.children[0]?.children[1])]
93
+ case 'between_tod_only': {
94
+ // between_tod_only has children[0] = between_tod node
95
+ const betweenTod = tp.children[0]
96
+ const startTod = RuleParser.__parseValue(betweenTod.children[0])
97
+ const endTod = RuleParser.__parseValue(betweenTod.children[1])
98
+
99
+ // Check if there's a dow_range at betweenTod.children[2]
100
+ if (betweenTod.children.length > 2) {
101
+ RuleParser._addDowToTods(startTod, endTod, betweenTod.children[2])
102
+ }
103
+
104
+ return ["TimePeriodBetween", startTod, endTod]
105
+ }
106
+ case 'between_number_only': {
107
+ // between_number_only has children[0] = between_number node
108
+ const betweenNumber = tp.children[0]
109
+ const startValue = RuleParser.__parseValue(betweenNumber.children[0])
110
+ const endValue = RuleParser.__parseValue(betweenNumber.children[1])
111
+
112
+ return ["TimePeriodBetween", startValue, endValue]
113
+ }
71
114
  }
72
115
  }
73
116
  static __parseValue(child){
@@ -191,9 +234,39 @@ class RuleParser {
191
234
  case 2: {
192
235
  const rhs = expr.children[1]
193
236
  switch(rhs.type){
194
- case 'between_tod':
237
+ case 'between_tod': {
238
+ // Direct between_tod (without wrapping between node)
239
+ // between_tod has: children[0] = first tod, children[1] = second tod, children[2] = optional dow_range
240
+ const startTod = RuleParser.__parseValue(rhs.children[0])
241
+ const endTod = RuleParser.__parseValue(rhs.children[1])
242
+
243
+ // Check if there's a dow_range (children[2])
244
+ if (rhs.children.length > 2) {
245
+ RuleParser._addDowToTods(startTod, endTod, rhs.children[2])
246
+ }
247
+
248
+ return ['Between', RuleParser._parseResult(expr.children[0]), ['Value', startTod], ['Value', endTod]]
249
+ }
250
+ case 'between': {
251
+ // between wraps either between_number or between_tod
252
+ const betweenChild = rhs.children[0]
253
+ if (betweenChild.type === 'between_tod') {
254
+ // between_tod has: children[0] = first tod, children[1] = second tod, children[2] = optional dow_range
255
+ const startTod = RuleParser.__parseValue(betweenChild.children[0])
256
+ const endTod = RuleParser.__parseValue(betweenChild.children[1])
257
+
258
+ // Check if there's a dow_range (children[2])
259
+ if (betweenChild.children.length > 2) {
260
+ RuleParser._addDowToTods(startTod, endTod, betweenChild.children[2])
261
+ }
262
+
263
+ return ['Between', RuleParser._parseResult(expr.children[0]), ['Value', startTod], ['Value', endTod]]
264
+ } else {
265
+ // between_number - no dow support
266
+ return ['Between', RuleParser._parseResult(expr.children[0]), ['Value', RuleParser.__parseValue(betweenChild.children[0])], ['Value', RuleParser.__parseValue(betweenChild.children[1])]]
267
+ }
268
+ }
195
269
  case 'between_number':
196
- case 'between':
197
270
  return ['Between', RuleParser._parseResult(expr.children[0]), ['Value', RuleParser.__parseValue(rhs.children[0].children[0])], ['Value', RuleParser.__parseValue(rhs.children[0].children[1])]]
198
271
  case 'basic_rhs':
199
272
  return [OperatorFn[rhs.children[0].text], RuleParser._parseResult(expr.children[0]), RuleParser._parseResult(rhs.children[1])]
@@ -1 +1 @@
1
- module.exports=[{"name":"statement_main","bnf":[["statement","EOF"]]},{"name":"logical_operator","bnf":[["AND"],["OR"]]},{"name":"%statement0","bnf":[["logical_operator","expression"]],"fragment":true},{"name":"statement","bnf":[["expression","%statement0*"]]},{"name":"expression","bnf":[["not_expression"],["standard_expression"],["parenthesis_expression"]]},{"name":"parenthesis_expression","bnf":[["BEGIN_PARENTHESIS","WS*","statement","WS*","END_PARENTHESIS"]]},{"name":"%not_expression1","bnf":[["result"],["parenthesis_expression"]],"fragment":true},{"name":"not_expression","bnf":[["NOT","%not_expression1"]]},{"name":"%%standard_expression23","bnf":[["WS*","eq_approx"]],"fragment":true},{"name":"%%standard_expression24","bnf":[["WS*","basic_rhs"]],"fragment":true},{"name":"%%%standard_expression256","bnf":[["WS+","IS"]],"fragment":true},{"name":"%%standard_expression25","bnf":[["%%%standard_expression256?","WS+","between"]],"fragment":true},{"name":"%standard_expression2","bnf":[["%%standard_expression23"],["%%standard_expression24"],["%%standard_expression25"]],"fragment":true},{"name":"standard_expression","bnf":[["result","%standard_expression2?"]]},{"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_result7","bnf":[["arithmetic_result"],["simple_result"]],"fragment":true},{"name":"arithmetic_result","bnf":[["simple_result","WS*","arithmetic_operator","WS*","%arithmetic_result7"]]},{"name":"simple_result","bnf":[["fcall"],["value"]]},{"name":"result","bnf":[["arithmetic_result"],["simple_result"]]},{"name":"value","bnf":[["false"],["true"],["array"],["number_time"],["number"],["number_tod"],["time_period"],["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":"%WS8","bnf":[[/[\x20\x09\x0A\x0D]/]]},{"name":"WS","bnf":[["%WS8+"]]},{"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":"%argument9","bnf":[["\",\"","WS*"]],"fragment":true},{"name":"argument","bnf":[["statement","WS*","%argument9?"]]},{"name":"arguments","bnf":[["argument*"]]},{"name":"%fname10","bnf":[[/[a-zA-z0-9]/]]},{"name":"fname","bnf":[["%fname10+"]]},{"name":"fcall","bnf":[["fname","WS*","BEGIN_ARGUMENT","WS*","arguments?","END_ARGUMENT"]]},{"name":"%%between_number1112","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"%%between_number1113","bnf":[["WS*",/\-/,"WS*"]],"fragment":true},{"name":"%between_number11","bnf":[["%%between_number1112"],["%%between_number1113"]],"fragment":true},{"name":"between_number","bnf":[["number","%between_number11","number"]]},{"name":"%%between_tod1415","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"%between_tod14","bnf":[["%%between_tod1415"]],"fragment":true},{"name":"between_tod","bnf":[["number_tod","%between_tod14","number_tod"]]},{"name":"%between16","bnf":[["between_number"],["between_tod"]],"fragment":true},{"name":"between","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","%between16"]]},{"name":"between_tod_only","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","between_tod"]]},{"name":"%AND17","bnf":[["WS*",/&/,/&/,"WS*"]],"fragment":true},{"name":"%AND18","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"AND","bnf":[["%AND17"],["%AND18"]]},{"name":"%OR19","bnf":[["WS*",/\|/,/\|/,"WS*"]],"fragment":true},{"name":"%OR20","bnf":[["WS+",/[Oo]/,/[Rr]/,"WS+"]],"fragment":true},{"name":"OR","bnf":[["%OR19"],["%OR20"]]},{"name":"GT","bnf":[["\">\""]]},{"name":"LT","bnf":[["\"<\""]]},{"name":"GTE","bnf":[["\">=\""]]},{"name":"LTE","bnf":[["\"<=\""]]},{"name":"IS","bnf":[[/[Ii]/,/[Ss]/]]},{"name":"EQ","bnf":[["\"==\""],["\"=\""]]},{"name":"NEQ","bnf":[["\"!=\""]]},{"name":"%NOT21","bnf":[[/!/,"WS*"]],"fragment":true},{"name":"%NOT22","bnf":[[/[Nn]/,/[Oo]/,/[Tt]/,"WS+"]],"fragment":true},{"name":"NOT","bnf":[["%NOT21"],["%NOT22"]]},{"name":"false","bnf":[[/[Ff]/,/[Aa]/,/[Ll]/,/[Ss]/,/[Ee]/]]},{"name":"null","bnf":[[/[Nn]/,/[Uu]/,/[Ll]/,/[Ll]/]]},{"name":"true","bnf":[[/[Tt]/,/[Rr]/,/[Uu]/,/[Ee]/]]},{"name":"%%array2324","bnf":[["VALUE_SEPARATOR","value"]],"fragment":true},{"name":"%array23","bnf":[["value","%%array2324*"]],"fragment":true},{"name":"array","bnf":[["BEGIN_ARRAY","%array23?","END_ARRAY"]]},{"name":"unit","bnf":[[/[Ss]/,/[Ee]/,/[Cc]/,/[Oo]/,/[Nn]/,/[Dd]/,/[Ss]/],[/[Ss]/,/[Ee]/,/[Cc]/,/[Oo]/,/[Nn]/,/[Dd]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Uu]/,/[Tt]/,/[Ee]/,/[Ss]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Uu]/,/[Tt]/,/[Ee]/],[/[Mm]/,/[Ii]/,/[Nn]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Ss]/],[/[Mm]/,/[Ii]/,/[Nn]/],[/[Hh]/,/[Oo]/,/[Uu]/,/[Rr]/,/[Ss]/],[/[Hh]/,/[Oo]/,/[Uu]/,/[Rr]/],[/[Dd]/,/[Aa]/,/[Yy]/,/[Ss]/],[/[Dd]/,/[Aa]/,/[Yy]/],[/[Ww]/,/[Ee]/,/[Ee]/,/[Kk]/,/[Ss]/],[/[Ww]/,/[Ee]/,/[Ee]/,/[Kk]/]]},{"name":"%%number2526","bnf":[[/[0-9]/]]},{"name":"%number25","bnf":[["%%number2526+"]],"fragment":true},{"name":"%%number2728","bnf":[[/[0-9]/]]},{"name":"%number27","bnf":[["\".\"","%%number2728+"]],"fragment":true},{"name":"%%number2930","bnf":[["\"-\""],["\"+\""]],"fragment":true},{"name":"%%%number293132","bnf":[[/[0-9]/]]},{"name":"%%number2931","bnf":[["\"0\""],[/[1-9]/,"%%%number293132*"]],"fragment":true},{"name":"%number29","bnf":[["\"e\"","%%number2930?","%%number2931"]],"fragment":true},{"name":"number","bnf":[["\"-\"?","%number25","%number27?","%number29?"]]},{"name":"number_time","bnf":[["number","WS+","unit"]]},{"name":"%%number_tod3334","bnf":[[/[0-9]/]]},{"name":"%number_tod33","bnf":[["%%number_tod3334+"]],"fragment":true},{"name":"%%number_tod3536","bnf":[[/[0-9]/]]},{"name":"%number_tod35","bnf":[["%%number_tod3536+"]],"fragment":true},{"name":"number_tod","bnf":[["%number_tod33","\":\"","%number_tod35"]]},{"name":"time_period_const","bnf":[[/[Tt]/,/[Oo]/,/[Dd]/,/[Aa]/,/[Yy]/]]},{"name":"time_period","bnf":[["time_period_const"],["between_tod_only"]]},{"name":"%%string3738","bnf":[[/[\x20-\x21]/],[/[\x23-\x5B]/],[/[\x5D-\uFFFF]/]],"fragment":true},{"name":"%%string3739","bnf":[[/\x22/],[/\x5C/],[/\x2F/],[/\x62/],[/\x66/],[/\x6E/],[/\x72/],[/\x74/],[/\x75/,"HEXDIG","HEXDIG","HEXDIG","HEXDIG"]],"fragment":true},{"name":"%string37","bnf":[["%%string3738"],[/\x5C/,"%%string3739"]],"fragment":true},{"name":"string","bnf":[["'\"'","%string37*","'\"'"]]},{"name":"HEXDIG","bnf":[[/[a-fA-F0-9]/]]}]
1
+ module.exports=[{"name":"statement_main","bnf":[["statement","EOF"]]},{"name":"logical_operator","bnf":[["AND"],["OR"]]},{"name":"%statement0","bnf":[["logical_operator","expression"]],"fragment":true},{"name":"statement","bnf":[["expression","%statement0*"]]},{"name":"expression","bnf":[["not_expression"],["standard_expression"],["parenthesis_expression"]]},{"name":"parenthesis_expression","bnf":[["BEGIN_PARENTHESIS","WS*","statement","WS*","END_PARENTHESIS"]]},{"name":"%not_expression1","bnf":[["result"],["parenthesis_expression"]],"fragment":true},{"name":"not_expression","bnf":[["NOT","%not_expression1"]]},{"name":"%%standard_expression23","bnf":[["WS*","eq_approx"]],"fragment":true},{"name":"%%standard_expression24","bnf":[["WS*","basic_rhs"]],"fragment":true},{"name":"%%%standard_expression256","bnf":[["WS+","IS"]],"fragment":true},{"name":"%%standard_expression25","bnf":[["%%%standard_expression256?","WS+","between"]],"fragment":true},{"name":"%standard_expression2","bnf":[["%%standard_expression23"],["%%standard_expression24"],["%%standard_expression25"]],"fragment":true},{"name":"standard_expression","bnf":[["result","%standard_expression2?"]]},{"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_result7","bnf":[["arithmetic_result"],["simple_result"]],"fragment":true},{"name":"arithmetic_result","bnf":[["simple_result","WS*","arithmetic_operator","WS*","%arithmetic_result7"]]},{"name":"simple_result","bnf":[["fcall"],["value"]]},{"name":"result","bnf":[["arithmetic_result"],["simple_result"]]},{"name":"value","bnf":[["false"],["true"],["array"],["number_time"],["number"],["number_tod"],["time_period"],["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":"%WS8","bnf":[[/[\x20\x09\x0A\x0D]/]]},{"name":"WS","bnf":[["%WS8+"]]},{"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":"%argument9","bnf":[["\",\"","WS*"]],"fragment":true},{"name":"argument","bnf":[["statement","WS*","%argument9?"]]},{"name":"arguments","bnf":[["argument*"]]},{"name":"%fname10","bnf":[[/[a-zA-z0-9]/]]},{"name":"fname","bnf":[["%fname10+"]]},{"name":"fcall","bnf":[["fname","WS*","BEGIN_ARGUMENT","WS*","arguments?","END_ARGUMENT"]]},{"name":"%between_number11","bnf":[["number_time"],["number"]],"fragment":true},{"name":"%%between_number1213","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"%%between_number1214","bnf":[["WS*",/\-/,"WS*"]],"fragment":true},{"name":"%between_number12","bnf":[["%%between_number1213"],["%%between_number1214"]],"fragment":true},{"name":"%between_number15","bnf":[["number_time"],["number"]],"fragment":true},{"name":"between_number","bnf":[["%between_number11","%between_number12","%between_number15"]]},{"name":"%%between_tod1617","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"%between_tod16","bnf":[["%%between_tod1617"]],"fragment":true},{"name":"%between_tod18","bnf":[["WS+","dow_range"]],"fragment":true},{"name":"between_tod","bnf":[["number_tod","%between_tod16","number_tod","%between_tod18?"]]},{"name":"%between19","bnf":[["between_number"],["between_tod"]],"fragment":true},{"name":"between","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","%between19"]]},{"name":"dow","bnf":[[/[Mm]/,/[Oo]/,/[Nn]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Tt]/,/[Uu]/,/[Ee]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ww]/,/[Ee]/,/[Dd]/,/[Nn]/,/[Ee]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Tt]/,/[Hh]/,/[Uu]/,/[Rr]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ff]/,/[Rr]/,/[Ii]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ss]/,/[Aa]/,/[Tt]/,/[Uu]/,/[Rr]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ss]/,/[Uu]/,/[Nn]/,/[Dd]/,/[Aa]/,/[Yy]/]]},{"name":"%dow_range20","bnf":[["WS+",/[Tt]/,/[Oo]/,"WS+","dow"]],"fragment":true},{"name":"dow_range","bnf":[[/[Oo]/,/[Nn]/,"WS+","dow","%dow_range20?"]]},{"name":"between_number_only","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","between_number"]]},{"name":"between_tod_only","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","between_tod"]]},{"name":"%AND21","bnf":[["WS*",/&/,/&/,"WS*"]],"fragment":true},{"name":"%AND22","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"AND","bnf":[["%AND21"],["%AND22"]]},{"name":"%OR23","bnf":[["WS*",/\|/,/\|/,"WS*"]],"fragment":true},{"name":"%OR24","bnf":[["WS+",/[Oo]/,/[Rr]/,"WS+"]],"fragment":true},{"name":"OR","bnf":[["%OR23"],["%OR24"]]},{"name":"GT","bnf":[["\">\""]]},{"name":"LT","bnf":[["\"<\""]]},{"name":"GTE","bnf":[["\">=\""]]},{"name":"LTE","bnf":[["\"<=\""]]},{"name":"IS","bnf":[[/[Ii]/,/[Ss]/]]},{"name":"EQ","bnf":[["\"==\""],["\"=\""]]},{"name":"NEQ","bnf":[["\"!=\""]]},{"name":"%NOT25","bnf":[[/!/,"WS*"]],"fragment":true},{"name":"%NOT26","bnf":[[/[Nn]/,/[Oo]/,/[Tt]/,"WS+"]],"fragment":true},{"name":"NOT","bnf":[["%NOT25"],["%NOT26"]]},{"name":"false","bnf":[[/[Ff]/,/[Aa]/,/[Ll]/,/[Ss]/,/[Ee]/]]},{"name":"null","bnf":[[/[Nn]/,/[Uu]/,/[Ll]/,/[Ll]/]]},{"name":"true","bnf":[[/[Tt]/,/[Rr]/,/[Uu]/,/[Ee]/]]},{"name":"%%array2728","bnf":[["VALUE_SEPARATOR","value"]],"fragment":true},{"name":"%array27","bnf":[["value","%%array2728*"]],"fragment":true},{"name":"array","bnf":[["BEGIN_ARRAY","%array27?","END_ARRAY"]]},{"name":"unit","bnf":[[/[Ss]/,/[Ee]/,/[Cc]/,/[Oo]/,/[Nn]/,/[Dd]/,/[Ss]/],[/[Ss]/,/[Ee]/,/[Cc]/,/[Oo]/,/[Nn]/,/[Dd]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Uu]/,/[Tt]/,/[Ee]/,/[Ss]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Uu]/,/[Tt]/,/[Ee]/],[/[Mm]/,/[Ii]/,/[Nn]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Ss]/],[/[Mm]/,/[Ii]/,/[Nn]/],[/[Hh]/,/[Oo]/,/[Uu]/,/[Rr]/,/[Ss]/],[/[Hh]/,/[Oo]/,/[Uu]/,/[Rr]/],[/[Dd]/,/[Aa]/,/[Yy]/,/[Ss]/],[/[Dd]/,/[Aa]/,/[Yy]/],[/[Ww]/,/[Ee]/,/[Ee]/,/[Kk]/,/[Ss]/],[/[Ww]/,/[Ee]/,/[Ee]/,/[Kk]/]]},{"name":"%%number2930","bnf":[[/[0-9]/]]},{"name":"%number29","bnf":[["%%number2930+"]],"fragment":true},{"name":"%%number3132","bnf":[[/[0-9]/]]},{"name":"%number31","bnf":[["\".\"","%%number3132+"]],"fragment":true},{"name":"%%number3334","bnf":[["\"-\""],["\"+\""]],"fragment":true},{"name":"%%%number333536","bnf":[[/[0-9]/]]},{"name":"%%number3335","bnf":[["\"0\""],[/[1-9]/,"%%%number333536*"]],"fragment":true},{"name":"%number33","bnf":[["\"e\"","%%number3334?","%%number3335"]],"fragment":true},{"name":"number","bnf":[["\"-\"?","%number29","%number31?","%number33?"]]},{"name":"number_time","bnf":[["number","WS+","unit"]]},{"name":"%%number_tod3738","bnf":[[/[0-9]/]]},{"name":"%number_tod37","bnf":[["%%number_tod3738+"]],"fragment":true},{"name":"%%number_tod3940","bnf":[[/[0-9]/]]},{"name":"%number_tod39","bnf":[["%%number_tod3940+"]],"fragment":true},{"name":"number_tod","bnf":[["%number_tod37","\":\"","%number_tod39"]]},{"name":"time_period_const","bnf":[[/[Tt]/,/[Oo]/,/[Dd]/,/[Aa]/,/[Yy]/]]},{"name":"time_period","bnf":[["time_period_const"],["between_tod_only"],["between_number_only"]]},{"name":"%%string4142","bnf":[[/[\x20-\x21]/],[/[\x23-\x5B]/],[/[\x5D-\uFFFF]/]],"fragment":true},{"name":"%%string4143","bnf":[[/\x22/],[/\x5C/],[/\x2F/],[/\x62/],[/\x66/],[/\x6E/],[/\x72/],[/\x74/],[/\x75/,"HEXDIG","HEXDIG","HEXDIG","HEXDIG"]],"fragment":true},{"name":"%string41","bnf":[["%%string4142"],[/\x5C/,"%%string4143"]],"fragment":true},{"name":"string","bnf":[["'\"'","%string41*","'\"'"]]},{"name":"HEXDIG","bnf":[[/[a-fA-F0-9]/]]}]
@@ -62,12 +62,55 @@ class RuleParser {
62
62
  }
63
63
  return ret
64
64
  }
65
+ static _parseDowRange(dowRange) {
66
+ const dow = []
67
+
68
+ // dow_range can have 1 or 2 children (single day or range)
69
+ if (dowRange.children.length === 1) {
70
+ // Single day: ON MONDAY
71
+ dow.push(dowRange.children[0].text.toLowerCase())
72
+ } else if (dowRange.children.length === 2) {
73
+ // Range: ON MONDAY TO WEDNESDAY
74
+ dow.push(dowRange.children[0].text.toLowerCase())
75
+ dow.push(dowRange.children[1].text.toLowerCase())
76
+ } else {
77
+ throw new Error(`Invalid dow_range with ${dowRange.children.length} children`)
78
+ }
79
+
80
+ return dow
81
+ }
82
+ static _addDowToTods(startTod, endTod, dowRange) {
83
+ if (dowRange && dowRange.type === 'dow_range') {
84
+ const dow = RuleParser._parseDowRange(dowRange)
85
+ startTod.dow = dow
86
+ endTod.dow = dow
87
+ }
88
+ }
65
89
  static _parseTimePeriod(tp){
66
90
  switch(tp.type){
67
91
  case 'time_period_const':
68
92
  return ["TimePeriodConst", tp.text]
69
- case 'between_tod_only':
70
- return ["TimePeriodBetween", RuleParser.__parseValue(tp.children[0]?.children[0]), RuleParser.__parseValue(tp.children[0]?.children[1])]
93
+ case 'between_tod_only': {
94
+ // between_tod_only has children[0] = between_tod node
95
+ const betweenTod = tp.children[0]
96
+ const startTod = RuleParser.__parseValue(betweenTod.children[0])
97
+ const endTod = RuleParser.__parseValue(betweenTod.children[1])
98
+
99
+ // Check if there's a dow_range at betweenTod.children[2]
100
+ if (betweenTod.children.length > 2) {
101
+ RuleParser._addDowToTods(startTod, endTod, betweenTod.children[2])
102
+ }
103
+
104
+ return ["TimePeriodBetween", startTod, endTod]
105
+ }
106
+ case 'between_number_only': {
107
+ // between_number_only has children[0] = between_number node
108
+ const betweenNumber = tp.children[0]
109
+ const startValue = RuleParser.__parseValue(betweenNumber.children[0])
110
+ const endValue = RuleParser.__parseValue(betweenNumber.children[1])
111
+
112
+ return ["TimePeriodBetween", startValue, endValue]
113
+ }
71
114
  }
72
115
  }
73
116
  static __parseValue(child){
@@ -191,9 +234,39 @@ class RuleParser {
191
234
  case 2: {
192
235
  const rhs = expr.children[1]
193
236
  switch(rhs.type){
194
- case 'between_tod':
237
+ case 'between_tod': {
238
+ // Direct between_tod (without wrapping between node)
239
+ // between_tod has: children[0] = first tod, children[1] = second tod, children[2] = optional dow_range
240
+ const startTod = RuleParser.__parseValue(rhs.children[0])
241
+ const endTod = RuleParser.__parseValue(rhs.children[1])
242
+
243
+ // Check if there's a dow_range (children[2])
244
+ if (rhs.children.length > 2) {
245
+ RuleParser._addDowToTods(startTod, endTod, rhs.children[2])
246
+ }
247
+
248
+ return ['Between', RuleParser._parseResult(expr.children[0]), ['Value', startTod], ['Value', endTod]]
249
+ }
250
+ case 'between': {
251
+ // between wraps either between_number or between_tod
252
+ const betweenChild = rhs.children[0]
253
+ if (betweenChild.type === 'between_tod') {
254
+ // between_tod has: children[0] = first tod, children[1] = second tod, children[2] = optional dow_range
255
+ const startTod = RuleParser.__parseValue(betweenChild.children[0])
256
+ const endTod = RuleParser.__parseValue(betweenChild.children[1])
257
+
258
+ // Check if there's a dow_range (children[2])
259
+ if (betweenChild.children.length > 2) {
260
+ RuleParser._addDowToTods(startTod, endTod, betweenChild.children[2])
261
+ }
262
+
263
+ return ['Between', RuleParser._parseResult(expr.children[0]), ['Value', startTod], ['Value', endTod]]
264
+ } else {
265
+ // between_number - no dow support
266
+ return ['Between', RuleParser._parseResult(expr.children[0]), ['Value', RuleParser.__parseValue(betweenChild.children[0])], ['Value', RuleParser.__parseValue(betweenChild.children[1])]]
267
+ }
268
+ }
195
269
  case 'between_number':
196
- case 'between':
197
270
  return ['Between', RuleParser._parseResult(expr.children[0]), ['Value', RuleParser.__parseValue(rhs.children[0].children[0])], ['Value', RuleParser.__parseValue(rhs.children[0].children[1])]]
198
271
  case 'basic_rhs':
199
272
  return [OperatorFn[rhs.children[0].text], RuleParser._parseResult(expr.children[0]), RuleParser._parseResult(rhs.children[1])]