@halleyassist/rule-parser 1.0.7 → 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
package/src/RuleParser.ebnf.js
CHANGED
|
@@ -45,9 +45,13 @@ 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
|
|
54
|
+
between_tod_only ||= "BETWEEN" WS+ between_tod
|
|
51
55
|
|
|
52
56
|
AND ||= (WS* "&&" WS*) | (WS+ "AND" WS+)
|
|
53
57
|
OR ||= (WS* "||" WS*) | (WS+ "OR" WS+)
|
|
@@ -70,7 +74,7 @@ number_time ::= number WS+ unit
|
|
|
70
74
|
number_tod ::= ([0-9]+) ":" ([0-9]+)
|
|
71
75
|
|
|
72
76
|
time_period_const ||= "today"
|
|
73
|
-
time_period ::= time_period_const |
|
|
77
|
+
time_period ::= time_period_const | between_tod_only | between_number_only
|
|
74
78
|
|
|
75
79
|
string ::= '"' (([#x20-#x21] | [#x23-#x5B] | [#x5D-#xFFFF]) | #x5C (#x22 | #x5C | #x2F | #x62 | #x66 | #x6E | #x72 | #x74 | #x75 HEXDIG HEXDIG HEXDIG HEXDIG))* '"'
|
|
76
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 '
|
|
70
|
-
|
|
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){
|
|
@@ -88,7 +131,7 @@ class RuleParser {
|
|
|
88
131
|
const minutes = parseInt(tokens[1])
|
|
89
132
|
const tod = hours * 100 + minutes
|
|
90
133
|
const ret = { hours, minutes, tod }
|
|
91
|
-
if (!isNaN(tod) && ret.hours >= 0 && ret.hours
|
|
134
|
+
if (!isNaN(tod) && ret.hours >= 0 && ret.hours < 24 && ret.minutes >= 0 && ret.minutes < 60) {
|
|
92
135
|
return ret
|
|
93
136
|
}
|
|
94
137
|
throw new Error(`Invalid time of day, ${child.text} -> [${tokens.join(', ')}] -> ${hours}h${minutes}m -> ${tod}`)
|
|
@@ -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":"%%
|
|
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 '
|
|
70
|
-
|
|
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){
|
|
@@ -88,7 +131,7 @@ class RuleParser {
|
|
|
88
131
|
const minutes = parseInt(tokens[1])
|
|
89
132
|
const tod = hours * 100 + minutes
|
|
90
133
|
const ret = { hours, minutes, tod }
|
|
91
|
-
if (!isNaN(tod) && ret.hours >= 0 && ret.hours
|
|
134
|
+
if (!isNaN(tod) && ret.hours >= 0 && ret.hours < 24 && ret.minutes >= 0 && ret.minutes < 60) {
|
|
92
135
|
return ret
|
|
93
136
|
}
|
|
94
137
|
throw new Error(`Invalid time of day, ${child.text} -> [${tokens.join(', ')}] -> ${hours}h${minutes}m -> ${tod}`)
|
|
@@ -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])]
|