Berry refactor rule matcher (#18138)

This commit is contained in:
s-hadinger 2023-03-09 09:48:41 +02:00 committed by GitHub
parent 7167884f06
commit ba1475f8cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 823 additions and 426 deletions

View File

@ -58,6 +58,7 @@ extern int l_getswitch(bvm *vm);
extern int l_i2cenabled(bvm *vm);
extern int tasm_find_op(bvm *vm);
extern int tasm_apply_str_op(bvm *vm);
#include "solidify/solidified_tasmota_class.h"
#include "solidify/solidified_rule_matcher.h"
@ -138,6 +139,7 @@ class be_class_tasmota (scope: global, name: Tasmota) {
remove_fast_loop, closure(Tasmota_remove_fast_loop_closure)
cmd, closure(Tasmota_cmd_closure)
_find_op, func(tasm_find_op) // new C version for finding a rule operator
_apply_str_op, func(tasm_apply_str_op)
find_key_i, closure(Tasmota_find_key_i_closure)
find_op, closure(Tasmota_find_op_closure)
add_rule, closure(Tasmota_add_rule_closure)

View File

@ -61,13 +61,13 @@ m = tasmota.Rule_Matcher.parse("AA#BB")
assert(m.match({'aa':1}) == nil)
assert(m.match({'aa':{'bb':1}}) == 1)
m = tasmota.Rule_Matcher.parse("AA#BB#CC=2")
m = tasmota.Rule_Matcher.parse("AA#BB#CC==2")
assert(m.match({'aa':1}) == nil)
assert(m.match({'aa':{'bb':1}}) == nil)
assert(m.match({'aa':{'bb':{'cc':1}}}) == nil)
assert(m.match({'aa':{'bb':{'cc':2}}}) == 2)
m = tasmota.Rule_Matcher.parse("AA#?#CC=2")
m = tasmota.Rule_Matcher.parse("AA#?#CC==2")
assert(m.match({'aa':1}) == nil)
assert(m.match({'aa':{'bb':{'cc':2}}}) == 2)
@ -193,12 +193,69 @@ class Rule_Matcher
var op_str # name of the operator like '>'
var op_value # value to compare agains
def init(op_func, op_value, op_str)
self.op_func = op_func
self.op_value = op_value
self.op_str = op_str
def init(op_str, op_value)
self.op_parse(op_str, op_value)
end
###########################################################################################
# Functions to compare two values
###########################################################################################
def op_parse(op, op_value)
self.op_str = op
def op_eq_str(a,b) return tasmota._apply_str_op(1, str(a), b) end
def op_neq_str(a,b) return tasmota._apply_str_op(2, str(a), b) end
def op_start_str(a,b) return tasmota._apply_str_op(3, str(a), b) end
def op_end_str(a,b) return tasmota._apply_str_op(4, str(a), b) end
def op_sub_str(a,b) return tasmota._apply_str_op(5, str(a), b) end
def op_notsub_str(a,b) return tasmota._apply_str_op(6, str(a), b) end
def op_eq(a,b) return number(a) == b end
def op_neq(a,b) return number(a) != b end
def op_gt(a,b) return number(a) > b end
def op_gte(a,b) return number(a) >= b end
def op_lt(a,b) return number(a) < b end
def op_lte(a,b) return number(a) <= b end
def op_mod(a,b) return (int(a) % b) == 0 end
var numerical = false
var f
if op=='=' f = op_eq_str
elif op=='!==' f = op_neq_str
elif op=='$!' f = op_neq_str
elif op=='$<' f = op_start_str
elif op=='$>' f = op_end_str
elif op=='$|' f = op_sub_str
elif op=='$^' f = op_notsub_str
else
numerical = true
if op=='==' f = op_eq
elif op=='!=' f = op_neq
elif op=='>' f = op_gt
elif op=='>=' f = op_gte
elif op=='<' f = op_lt
elif op=='<=' f = op_lte
elif op=='|' f = op_mod
end
end
self.op_func = f
if numerical # if numerical comparator, make sure that the value passed is a number
# to check if a number is correct, the safest method is to use a json decoder
import json
var val_num = json.load(op_value)
if type(val_num) != 'int' && type(val_num) != 'real'
raise "value_error", "value needs to be a number"
else
self.op_value = val_num
end
else
self.op_value = str(op)
end
end
def match(val)
var t = type(val)
if t != 'int' && t != 'real' && t != 'string' return nil end # must be a simple type
@ -206,7 +263,11 @@ class Rule_Matcher
end
def tostring()
return "<Matcher op '" + self.op_str + "' val='" + str(self.op_value) + "'>"
if type(self.op_value) == 'string'
return "<Matcher op '" + self.op_str + "' val='" + str(self.op_value) + "'>"
else
return "<Matcher op '" + self.op_str + "' val=" + str(self.op_value) + ">"
end
end
end
@ -279,10 +340,7 @@ class Rule_Matcher
# if an operator was found, add the operator matcher
if op_str != nil && op_value != nil # we have an operator
var op_func = _class.op_parse(op_str)
if op_func
matchers.push(_class.Rule_Matcher_Operator(op_func, op_value, op_str))
end
matchers.push(_class.Rule_Matcher_Operator(op_str, op_value))
end
return _class(pattern, value_str, matchers) # `_class` is a reference to the Rule_Matcher class
@ -307,28 +365,4 @@ class Rule_Matcher
return str(self.matchers)
end
###########################################################################################
# Functions to compare two values
###########################################################################################
static def op_parse(op)
def op_eq_str(a,b) return str(a) == str(b) end
def op_neq_str(a,b) return str(a) != str(b) end
def op_eq(a,b) return real(a) == real(b) end
def op_neq(a,b) return real(a) != real(b) end
def op_gt(a,b) return real(a) > real(b) end
def op_gte(a,b) return real(a) >= real(b) end
def op_lt(a,b) return real(a) < real(b) end
def op_lte(a,b) return real(a) <= real(b) end
if op=='==' return op_eq_str
elif op=='!==' return op_neq_str
elif op=='=' return op_eq
elif op=='!=' return op_neq
elif op=='>' return op_gt
elif op=='>=' return op_gte
elif op=='<' return op_lt
elif op=='<=' return op_lte
end
end
end

View File

@ -77,7 +77,7 @@ class Tasmota
var idx_start = idx_composite & 0x7FFF
var idx_end = idx_composite >> 16
return [ item[0 .. idx_start-1], item[idx_start .. idx_end], item[idx_end+1 ..]]
return [ item[0 .. idx_start-1], item[idx_start .. idx_end - 1], item[idx_end ..]]
end
return [item, nil, nil]
end

View File

@ -347,30 +347,452 @@ be_local_closure(Rule_Matcher_Operator_match, /* name */
/********************************************************************
** Solidified function: init
** Solidified function: op_parse
********************************************************************/
be_local_closure(Rule_Matcher_Operator_init, /* name */
be_local_closure(Rule_Matcher_Operator_op_parse, /* name */
be_nested_proto(
4, /* nstack */
4, /* argc */
22, /* nstack */
3, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 3]) { /* constants */
/* K0 */ be_nested_str(op_func),
/* K1 */ be_nested_str(op_value),
/* K2 */ be_nested_str(op_str),
1, /* has sup protos */
( &(const struct bproto*[13]) {
be_nested_proto(
7, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 3]) { /* constants */
/* K0 */ be_nested_str(tasmota),
/* K1 */ be_nested_str(_apply_str_op),
/* K2 */ be_const_int(1),
}),
&be_const_str_op_eq_str,
&be_const_str_solidified,
( &(const binstruction[ 9]) { /* code */
0xB80A0000, // 0000 GETNGBL R2 K0
0x8C080501, // 0001 GETMET R2 R2 K1
0x58100002, // 0002 LDCONST R4 K2
0x60140008, // 0003 GETGBL R5 G8
0x5C180000, // 0004 MOVE R6 R0
0x7C140200, // 0005 CALL R5 1
0x5C180200, // 0006 MOVE R6 R1
0x7C080800, // 0007 CALL R2 4
0x80040400, // 0008 RET 1 R2
})
),
be_nested_proto(
7, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 3]) { /* constants */
/* K0 */ be_nested_str(tasmota),
/* K1 */ be_nested_str(_apply_str_op),
/* K2 */ be_const_int(2),
}),
&be_const_str_op_neq_str,
&be_const_str_solidified,
( &(const binstruction[ 9]) { /* code */
0xB80A0000, // 0000 GETNGBL R2 K0
0x8C080501, // 0001 GETMET R2 R2 K1
0x58100002, // 0002 LDCONST R4 K2
0x60140008, // 0003 GETGBL R5 G8
0x5C180000, // 0004 MOVE R6 R0
0x7C140200, // 0005 CALL R5 1
0x5C180200, // 0006 MOVE R6 R1
0x7C080800, // 0007 CALL R2 4
0x80040400, // 0008 RET 1 R2
})
),
be_nested_proto(
7, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 3]) { /* constants */
/* K0 */ be_nested_str(tasmota),
/* K1 */ be_nested_str(_apply_str_op),
/* K2 */ be_const_int(3),
}),
&be_const_str_op_start_str,
&be_const_str_solidified,
( &(const binstruction[ 9]) { /* code */
0xB80A0000, // 0000 GETNGBL R2 K0
0x8C080501, // 0001 GETMET R2 R2 K1
0x58100002, // 0002 LDCONST R4 K2
0x60140008, // 0003 GETGBL R5 G8
0x5C180000, // 0004 MOVE R6 R0
0x7C140200, // 0005 CALL R5 1
0x5C180200, // 0006 MOVE R6 R1
0x7C080800, // 0007 CALL R2 4
0x80040400, // 0008 RET 1 R2
})
),
be_nested_proto(
7, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 2]) { /* constants */
/* K0 */ be_nested_str(tasmota),
/* K1 */ be_nested_str(_apply_str_op),
}),
&be_const_str_op_end_str,
&be_const_str_solidified,
( &(const binstruction[ 9]) { /* code */
0xB80A0000, // 0000 GETNGBL R2 K0
0x8C080501, // 0001 GETMET R2 R2 K1
0x54120003, // 0002 LDINT R4 4
0x60140008, // 0003 GETGBL R5 G8
0x5C180000, // 0004 MOVE R6 R0
0x7C140200, // 0005 CALL R5 1
0x5C180200, // 0006 MOVE R6 R1
0x7C080800, // 0007 CALL R2 4
0x80040400, // 0008 RET 1 R2
})
),
be_nested_proto(
7, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 2]) { /* constants */
/* K0 */ be_nested_str(tasmota),
/* K1 */ be_nested_str(_apply_str_op),
}),
&be_const_str_op_sub_str,
&be_const_str_solidified,
( &(const binstruction[ 9]) { /* code */
0xB80A0000, // 0000 GETNGBL R2 K0
0x8C080501, // 0001 GETMET R2 R2 K1
0x54120004, // 0002 LDINT R4 5
0x60140008, // 0003 GETGBL R5 G8
0x5C180000, // 0004 MOVE R6 R0
0x7C140200, // 0005 CALL R5 1
0x5C180200, // 0006 MOVE R6 R1
0x7C080800, // 0007 CALL R2 4
0x80040400, // 0008 RET 1 R2
})
),
be_nested_proto(
7, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 2]) { /* constants */
/* K0 */ be_nested_str(tasmota),
/* K1 */ be_nested_str(_apply_str_op),
}),
&be_const_str_op_notsub_str,
&be_const_str_solidified,
( &(const binstruction[ 9]) { /* code */
0xB80A0000, // 0000 GETNGBL R2 K0
0x8C080501, // 0001 GETMET R2 R2 K1
0x54120005, // 0002 LDINT R4 6
0x60140008, // 0003 GETGBL R5 G8
0x5C180000, // 0004 MOVE R6 R0
0x7C140200, // 0005 CALL R5 1
0x5C180200, // 0006 MOVE R6 R1
0x7C080800, // 0007 CALL R2 4
0x80040400, // 0008 RET 1 R2
})
),
be_nested_proto(
4, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
0, /* has constants */
NULL, /* no const */
&be_const_str_op_eq,
&be_const_str_solidified,
( &(const binstruction[ 5]) { /* code */
0x60080007, // 0000 GETGBL R2 G7
0x5C0C0000, // 0001 MOVE R3 R0
0x7C080200, // 0002 CALL R2 1
0x1C080401, // 0003 EQ R2 R2 R1
0x80040400, // 0004 RET 1 R2
})
),
be_nested_proto(
4, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
0, /* has constants */
NULL, /* no const */
&be_const_str_op_neq,
&be_const_str_solidified,
( &(const binstruction[ 5]) { /* code */
0x60080007, // 0000 GETGBL R2 G7
0x5C0C0000, // 0001 MOVE R3 R0
0x7C080200, // 0002 CALL R2 1
0x20080401, // 0003 NE R2 R2 R1
0x80040400, // 0004 RET 1 R2
})
),
be_nested_proto(
4, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
0, /* has constants */
NULL, /* no const */
&be_const_str_op_gt,
&be_const_str_solidified,
( &(const binstruction[ 5]) { /* code */
0x60080007, // 0000 GETGBL R2 G7
0x5C0C0000, // 0001 MOVE R3 R0
0x7C080200, // 0002 CALL R2 1
0x24080401, // 0003 GT R2 R2 R1
0x80040400, // 0004 RET 1 R2
})
),
be_nested_proto(
4, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
0, /* has constants */
NULL, /* no const */
&be_const_str_op_gte,
&be_const_str_solidified,
( &(const binstruction[ 5]) { /* code */
0x60080007, // 0000 GETGBL R2 G7
0x5C0C0000, // 0001 MOVE R3 R0
0x7C080200, // 0002 CALL R2 1
0x28080401, // 0003 GE R2 R2 R1
0x80040400, // 0004 RET 1 R2
})
),
be_nested_proto(
4, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
0, /* has constants */
NULL, /* no const */
&be_const_str_op_lt,
&be_const_str_solidified,
( &(const binstruction[ 5]) { /* code */
0x60080007, // 0000 GETGBL R2 G7
0x5C0C0000, // 0001 MOVE R3 R0
0x7C080200, // 0002 CALL R2 1
0x14080401, // 0003 LT R2 R2 R1
0x80040400, // 0004 RET 1 R2
})
),
be_nested_proto(
4, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
0, /* has constants */
NULL, /* no const */
&be_const_str_op_lte,
&be_const_str_solidified,
( &(const binstruction[ 5]) { /* code */
0x60080007, // 0000 GETGBL R2 G7
0x5C0C0000, // 0001 MOVE R3 R0
0x7C080200, // 0002 CALL R2 1
0x18080401, // 0003 LE R2 R2 R1
0x80040400, // 0004 RET 1 R2
})
),
be_nested_proto(
4, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 1]) { /* constants */
/* K0 */ be_const_int(0),
}),
&be_const_str_op_mod,
&be_const_str_solidified,
( &(const binstruction[ 6]) { /* code */
0x60080009, // 0000 GETGBL R2 G9
0x5C0C0000, // 0001 MOVE R3 R0
0x7C080200, // 0002 CALL R2 1
0x10080401, // 0003 MOD R2 R2 R1
0x1C080500, // 0004 EQ R2 R2 K0
0x80040400, // 0005 RET 1 R2
})
),
}),
&be_const_str_init,
1, /* has constants */
( &(const bvalue[23]) { /* constants */
/* K0 */ be_nested_str(op_str),
/* K1 */ be_nested_str(_X3D),
/* K2 */ be_nested_str(_X21_X3D_X3D),
/* K3 */ be_nested_str(_X24_X21),
/* K4 */ be_nested_str(_X24_X3C),
/* K5 */ be_nested_str(_X24_X3E),
/* K6 */ be_nested_str(_X24_X7C),
/* K7 */ be_nested_str(_X24_X5E),
/* K8 */ be_nested_str(_X3D_X3D),
/* K9 */ be_nested_str(_X21_X3D),
/* K10 */ be_nested_str(_X3E),
/* K11 */ be_nested_str(_X3E_X3D),
/* K12 */ be_nested_str(_X3C),
/* K13 */ be_nested_str(_X3C_X3D),
/* K14 */ be_nested_str(_X7C),
/* K15 */ be_nested_str(op_func),
/* K16 */ be_nested_str(json),
/* K17 */ be_nested_str(load),
/* K18 */ be_nested_str(int),
/* K19 */ be_nested_str(real),
/* K20 */ be_nested_str(value_error),
/* K21 */ be_nested_str(value_X20needs_X20to_X20be_X20a_X20number),
/* K22 */ be_nested_str(op_value),
}),
&be_const_str_op_parse,
&be_const_str_solidified,
( &(const binstruction[ 4]) { /* code */
( &(const binstruction[97]) { /* code */
0x90020001, // 0000 SETMBR R0 K0 R1
0x90020202, // 0001 SETMBR R0 K1 R2
0x90020403, // 0002 SETMBR R0 K2 R3
0x80000000, // 0003 RET 0
0x840C0000, // 0001 CLOSURE R3 P0
0x84100001, // 0002 CLOSURE R4 P1
0x84140002, // 0003 CLOSURE R5 P2
0x84180003, // 0004 CLOSURE R6 P3
0x841C0004, // 0005 CLOSURE R7 P4
0x84200005, // 0006 CLOSURE R8 P5
0x84240006, // 0007 CLOSURE R9 P6
0x84280007, // 0008 CLOSURE R10 P7
0x842C0008, // 0009 CLOSURE R11 P8
0x84300009, // 000A CLOSURE R12 P9
0x8434000A, // 000B CLOSURE R13 P10
0x8438000B, // 000C CLOSURE R14 P11
0x843C000C, // 000D CLOSURE R15 P12
0x50400000, // 000E LDBOOL R16 0 0
0x4C440000, // 000F LDNIL R17
0x1C480301, // 0010 EQ R18 R1 K1
0x784A0001, // 0011 JMPF R18 #0014
0x5C440600, // 0012 MOVE R17 R3
0x70020033, // 0013 JMP #0048
0x1C480302, // 0014 EQ R18 R1 K2
0x784A0001, // 0015 JMPF R18 #0018
0x5C440800, // 0016 MOVE R17 R4
0x7002002F, // 0017 JMP #0048
0x1C480303, // 0018 EQ R18 R1 K3
0x784A0001, // 0019 JMPF R18 #001C
0x5C440800, // 001A MOVE R17 R4
0x7002002B, // 001B JMP #0048
0x1C480304, // 001C EQ R18 R1 K4
0x784A0001, // 001D JMPF R18 #0020
0x5C440A00, // 001E MOVE R17 R5
0x70020027, // 001F JMP #0048
0x1C480305, // 0020 EQ R18 R1 K5
0x784A0001, // 0021 JMPF R18 #0024
0x5C440C00, // 0022 MOVE R17 R6
0x70020023, // 0023 JMP #0048
0x1C480306, // 0024 EQ R18 R1 K6
0x784A0001, // 0025 JMPF R18 #0028
0x5C440E00, // 0026 MOVE R17 R7
0x7002001F, // 0027 JMP #0048
0x1C480307, // 0028 EQ R18 R1 K7
0x784A0001, // 0029 JMPF R18 #002C
0x5C441000, // 002A MOVE R17 R8
0x7002001B, // 002B JMP #0048
0x50400200, // 002C LDBOOL R16 1 0
0x1C480308, // 002D EQ R18 R1 K8
0x784A0001, // 002E JMPF R18 #0031
0x5C441200, // 002F MOVE R17 R9
0x70020016, // 0030 JMP #0048
0x1C480309, // 0031 EQ R18 R1 K9
0x784A0001, // 0032 JMPF R18 #0035
0x5C441400, // 0033 MOVE R17 R10
0x70020012, // 0034 JMP #0048
0x1C48030A, // 0035 EQ R18 R1 K10
0x784A0001, // 0036 JMPF R18 #0039
0x5C441600, // 0037 MOVE R17 R11
0x7002000E, // 0038 JMP #0048
0x1C48030B, // 0039 EQ R18 R1 K11
0x784A0001, // 003A JMPF R18 #003D
0x5C441800, // 003B MOVE R17 R12
0x7002000A, // 003C JMP #0048
0x1C48030C, // 003D EQ R18 R1 K12
0x784A0001, // 003E JMPF R18 #0041
0x5C441A00, // 003F MOVE R17 R13
0x70020006, // 0040 JMP #0048
0x1C48030D, // 0041 EQ R18 R1 K13
0x784A0001, // 0042 JMPF R18 #0045
0x5C441C00, // 0043 MOVE R17 R14
0x70020002, // 0044 JMP #0048
0x1C48030E, // 0045 EQ R18 R1 K14
0x784A0000, // 0046 JMPF R18 #0048
0x5C441E00, // 0047 MOVE R17 R15
0x90021E11, // 0048 SETMBR R0 K15 R17
0x78420011, // 0049 JMPF R16 #005C
0xA44A2000, // 004A IMPORT R18 K16
0x8C4C2511, // 004B GETMET R19 R18 K17
0x5C540400, // 004C MOVE R21 R2
0x7C4C0400, // 004D CALL R19 2
0x60500004, // 004E GETGBL R20 G4
0x5C542600, // 004F MOVE R21 R19
0x7C500200, // 0050 CALL R20 1
0x20502912, // 0051 NE R20 R20 K18
0x78520006, // 0052 JMPF R20 #005A
0x60500004, // 0053 GETGBL R20 G4
0x5C542600, // 0054 MOVE R21 R19
0x7C500200, // 0055 CALL R20 1
0x20502913, // 0056 NE R20 R20 K19
0x78520001, // 0057 JMPF R20 #005A
0xB0062915, // 0058 RAISE 1 K20 K21
0x70020000, // 0059 JMP #005B
0x90022C13, // 005A SETMBR R0 K22 R19
0x70020003, // 005B JMP #0060
0x60480008, // 005C GETGBL R18 G8
0x5C4C0200, // 005D MOVE R19 R1
0x7C480200, // 005E CALL R18 1
0x90022C12, // 005F SETMBR R0 K22 R18
0x80000000, // 0060 RET 0
})
)
);
@ -390,25 +812,74 @@ be_local_closure(Rule_Matcher_Operator_tostring, /* name */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 5]) { /* constants */
/* K0 */ be_nested_str(_X3CMatcher_X20op_X20_X27),
/* K1 */ be_nested_str(op_str),
/* K2 */ be_nested_str(_X27_X20val_X3D_X27),
/* K3 */ be_nested_str(op_value),
/* K4 */ be_nested_str(_X27_X3E),
( &(const bvalue[ 8]) { /* constants */
/* K0 */ be_nested_str(op_value),
/* K1 */ be_nested_str(string),
/* K2 */ be_nested_str(_X3CMatcher_X20op_X20_X27),
/* K3 */ be_nested_str(op_str),
/* K4 */ be_nested_str(_X27_X20val_X3D_X27),
/* K5 */ be_nested_str(_X27_X3E),
/* K6 */ be_nested_str(_X27_X20val_X3D),
/* K7 */ be_nested_str(_X3E),
}),
&be_const_str_tostring,
&be_const_str_solidified,
( &(const binstruction[ 9]) { /* code */
0x88040101, // 0000 GETMBR R1 R0 K1
0x00060001, // 0001 ADD R1 K0 R1
0x00040302, // 0002 ADD R1 R1 K2
0x60080008, // 0003 GETGBL R2 G8
0x880C0103, // 0004 GETMBR R3 R0 K3
0x7C080200, // 0005 CALL R2 1
0x00040202, // 0006 ADD R1 R1 R2
( &(const binstruction[25]) { /* code */
0x60040004, // 0000 GETGBL R1 G4
0x88080100, // 0001 GETMBR R2 R0 K0
0x7C040200, // 0002 CALL R1 1
0x1C040301, // 0003 EQ R1 R1 K1
0x78060009, // 0004 JMPF R1 #000F
0x88040103, // 0005 GETMBR R1 R0 K3
0x00060401, // 0006 ADD R1 K2 R1
0x00040304, // 0007 ADD R1 R1 K4
0x80040200, // 0008 RET 1 R1
0x60080008, // 0008 GETGBL R2 G8
0x880C0100, // 0009 GETMBR R3 R0 K0
0x7C080200, // 000A CALL R2 1
0x00040202, // 000B ADD R1 R1 R2
0x00040305, // 000C ADD R1 R1 K5
0x80040200, // 000D RET 1 R1
0x70020008, // 000E JMP #0018
0x88040103, // 000F GETMBR R1 R0 K3
0x00060401, // 0010 ADD R1 K2 R1
0x00040306, // 0011 ADD R1 R1 K6
0x60080008, // 0012 GETGBL R2 G8
0x880C0100, // 0013 GETMBR R3 R0 K0
0x7C080200, // 0014 CALL R2 1
0x00040202, // 0015 ADD R1 R1 R2
0x00040307, // 0016 ADD R1 R1 K7
0x80040200, // 0017 RET 1 R1
0x80000000, // 0018 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: init
********************************************************************/
be_local_closure(Rule_Matcher_Operator_init, /* name */
be_nested_proto(
7, /* nstack */
3, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 1]) { /* constants */
/* K0 */ be_nested_str(op_parse),
}),
&be_const_str_init,
&be_const_str_solidified,
( &(const binstruction[ 5]) { /* code */
0x8C0C0100, // 0000 GETMET R3 R0 K0
0x5C140200, // 0001 MOVE R5 R1
0x5C180400, // 0002 MOVE R6 R2
0x7C0C0600, // 0003 CALL R3 3
0x80000000, // 0004 RET 0
})
)
);
@ -421,14 +892,15 @@ be_local_closure(Rule_Matcher_Operator_tostring, /* name */
be_local_class(Rule_Matcher_Operator,
3,
NULL,
be_nested_map(6,
be_nested_map(7,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key(op_value, -1), be_const_var(2) },
{ be_const_key(op_func, 2), be_const_var(0) },
{ be_const_key(op_value, 6), be_const_var(2) },
{ be_const_key(tostring, -1), be_const_closure(Rule_Matcher_Operator_tostring_closure) },
{ be_const_key(init, -1), be_const_closure(Rule_Matcher_Operator_init_closure) },
{ be_const_key(match, 5), be_const_closure(Rule_Matcher_Operator_match_closure) },
{ be_const_key(op_func, 0), be_const_var(0) },
{ be_const_key(match, 1), be_const_closure(Rule_Matcher_Operator_match_closure) },
{ be_const_key(op_str, -1), be_const_var(1) },
{ be_const_key(init, -1), be_const_closure(Rule_Matcher_Operator_init_closure) },
{ be_const_key(op_parse, -1), be_const_closure(Rule_Matcher_Operator_op_parse_closure) },
})),
(bstring*) &be_const_str_Rule_Matcher_Operator
);
@ -611,296 +1083,6 @@ be_local_closure(Rule_Matcher_tostring, /* name */
/*******************************************************************/
/********************************************************************
** Solidified function: op_parse
********************************************************************/
be_local_closure(Rule_Matcher_op_parse, /* name */
be_nested_proto(
11, /* nstack */
1, /* argc */
4, /* varg */
0, /* has upvals */
NULL, /* no upvals */
1, /* has sup protos */
( &(const struct bproto*[ 8]) {
be_nested_proto(
5, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
0, /* has constants */
NULL, /* no const */
&be_const_str_op_eq_str,
&be_const_str_solidified,
( &(const binstruction[ 8]) { /* code */
0x60080008, // 0000 GETGBL R2 G8
0x5C0C0000, // 0001 MOVE R3 R0
0x7C080200, // 0002 CALL R2 1
0x600C0008, // 0003 GETGBL R3 G8
0x5C100200, // 0004 MOVE R4 R1
0x7C0C0200, // 0005 CALL R3 1
0x1C080403, // 0006 EQ R2 R2 R3
0x80040400, // 0007 RET 1 R2
})
),
be_nested_proto(
5, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
0, /* has constants */
NULL, /* no const */
&be_const_str_op_neq_str,
&be_const_str_solidified,
( &(const binstruction[ 8]) { /* code */
0x60080008, // 0000 GETGBL R2 G8
0x5C0C0000, // 0001 MOVE R3 R0
0x7C080200, // 0002 CALL R2 1
0x600C0008, // 0003 GETGBL R3 G8
0x5C100200, // 0004 MOVE R4 R1
0x7C0C0200, // 0005 CALL R3 1
0x20080403, // 0006 NE R2 R2 R3
0x80040400, // 0007 RET 1 R2
})
),
be_nested_proto(
5, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
0, /* has constants */
NULL, /* no const */
&be_const_str_op_eq,
&be_const_str_solidified,
( &(const binstruction[ 8]) { /* code */
0x6008000A, // 0000 GETGBL R2 G10
0x5C0C0000, // 0001 MOVE R3 R0
0x7C080200, // 0002 CALL R2 1
0x600C000A, // 0003 GETGBL R3 G10
0x5C100200, // 0004 MOVE R4 R1
0x7C0C0200, // 0005 CALL R3 1
0x1C080403, // 0006 EQ R2 R2 R3
0x80040400, // 0007 RET 1 R2
})
),
be_nested_proto(
5, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
0, /* has constants */
NULL, /* no const */
&be_const_str_op_neq,
&be_const_str_solidified,
( &(const binstruction[ 8]) { /* code */
0x6008000A, // 0000 GETGBL R2 G10
0x5C0C0000, // 0001 MOVE R3 R0
0x7C080200, // 0002 CALL R2 1
0x600C000A, // 0003 GETGBL R3 G10
0x5C100200, // 0004 MOVE R4 R1
0x7C0C0200, // 0005 CALL R3 1
0x20080403, // 0006 NE R2 R2 R3
0x80040400, // 0007 RET 1 R2
})
),
be_nested_proto(
5, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
0, /* has constants */
NULL, /* no const */
&be_const_str_op_gt,
&be_const_str_solidified,
( &(const binstruction[ 8]) { /* code */
0x6008000A, // 0000 GETGBL R2 G10
0x5C0C0000, // 0001 MOVE R3 R0
0x7C080200, // 0002 CALL R2 1
0x600C000A, // 0003 GETGBL R3 G10
0x5C100200, // 0004 MOVE R4 R1
0x7C0C0200, // 0005 CALL R3 1
0x24080403, // 0006 GT R2 R2 R3
0x80040400, // 0007 RET 1 R2
})
),
be_nested_proto(
5, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
0, /* has constants */
NULL, /* no const */
&be_const_str_op_gte,
&be_const_str_solidified,
( &(const binstruction[ 8]) { /* code */
0x6008000A, // 0000 GETGBL R2 G10
0x5C0C0000, // 0001 MOVE R3 R0
0x7C080200, // 0002 CALL R2 1
0x600C000A, // 0003 GETGBL R3 G10
0x5C100200, // 0004 MOVE R4 R1
0x7C0C0200, // 0005 CALL R3 1
0x28080403, // 0006 GE R2 R2 R3
0x80040400, // 0007 RET 1 R2
})
),
be_nested_proto(
5, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
0, /* has constants */
NULL, /* no const */
&be_const_str_op_lt,
&be_const_str_solidified,
( &(const binstruction[ 8]) { /* code */
0x6008000A, // 0000 GETGBL R2 G10
0x5C0C0000, // 0001 MOVE R3 R0
0x7C080200, // 0002 CALL R2 1
0x600C000A, // 0003 GETGBL R3 G10
0x5C100200, // 0004 MOVE R4 R1
0x7C0C0200, // 0005 CALL R3 1
0x14080403, // 0006 LT R2 R2 R3
0x80040400, // 0007 RET 1 R2
})
),
be_nested_proto(
5, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
0, /* has constants */
NULL, /* no const */
&be_const_str_op_lte,
&be_const_str_solidified,
( &(const binstruction[ 8]) { /* code */
0x6008000A, // 0000 GETGBL R2 G10
0x5C0C0000, // 0001 MOVE R3 R0
0x7C080200, // 0002 CALL R2 1
0x600C000A, // 0003 GETGBL R3 G10
0x5C100200, // 0004 MOVE R4 R1
0x7C0C0200, // 0005 CALL R3 1
0x18080403, // 0006 LE R2 R2 R3
0x80040400, // 0007 RET 1 R2
})
),
}),
1, /* has constants */
( &(const bvalue[ 9]) { /* constants */
/* K0 */ be_const_class(be_class_Rule_Matcher),
/* K1 */ be_nested_str(_X3D_X3D),
/* K2 */ be_nested_str(_X21_X3D_X3D),
/* K3 */ be_nested_str(_X3D),
/* K4 */ be_nested_str(_X21_X3D),
/* K5 */ be_nested_str(_X3E),
/* K6 */ be_nested_str(_X3E_X3D),
/* K7 */ be_nested_str(_X3C),
/* K8 */ be_nested_str(_X3C_X3D),
}),
&be_const_str_op_parse,
&be_const_str_solidified,
( &(const binstruction[41]) { /* code */
0x58040000, // 0000 LDCONST R1 K0
0x84080000, // 0001 CLOSURE R2 P0
0x840C0001, // 0002 CLOSURE R3 P1
0x84100002, // 0003 CLOSURE R4 P2
0x84140003, // 0004 CLOSURE R5 P3
0x84180004, // 0005 CLOSURE R6 P4
0x841C0005, // 0006 CLOSURE R7 P5
0x84200006, // 0007 CLOSURE R8 P6
0x84240007, // 0008 CLOSURE R9 P7
0x1C280101, // 0009 EQ R10 R0 K1
0x782A0001, // 000A JMPF R10 #000D
0x80040400, // 000B RET 1 R2
0x7002001A, // 000C JMP #0028
0x1C280102, // 000D EQ R10 R0 K2
0x782A0001, // 000E JMPF R10 #0011
0x80040600, // 000F RET 1 R3
0x70020016, // 0010 JMP #0028
0x1C280103, // 0011 EQ R10 R0 K3
0x782A0001, // 0012 JMPF R10 #0015
0x80040800, // 0013 RET 1 R4
0x70020012, // 0014 JMP #0028
0x1C280104, // 0015 EQ R10 R0 K4
0x782A0001, // 0016 JMPF R10 #0019
0x80040A00, // 0017 RET 1 R5
0x7002000E, // 0018 JMP #0028
0x1C280105, // 0019 EQ R10 R0 K5
0x782A0001, // 001A JMPF R10 #001D
0x80040C00, // 001B RET 1 R6
0x7002000A, // 001C JMP #0028
0x1C280106, // 001D EQ R10 R0 K6
0x782A0001, // 001E JMPF R10 #0021
0x80040E00, // 001F RET 1 R7
0x70020006, // 0020 JMP #0028
0x1C280107, // 0021 EQ R10 R0 K7
0x782A0001, // 0022 JMPF R10 #0025
0x80041000, // 0023 RET 1 R8
0x70020002, // 0024 JMP #0028
0x1C280108, // 0025 EQ R10 R0 K8
0x782A0000, // 0026 JMPF R10 #0028
0x80041200, // 0027 RET 1 R9
0x80000000, // 0028 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: init
********************************************************************/
be_local_closure(Rule_Matcher_init, /* name */
be_nested_proto(
4, /* nstack */
4, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 3]) { /* constants */
/* K0 */ be_nested_str(rule),
/* K1 */ be_nested_str(trigger),
/* K2 */ be_nested_str(matchers),
}),
&be_const_str_init,
&be_const_str_solidified,
( &(const binstruction[ 4]) { /* code */
0x90020001, // 0000 SETMBR R0 K0 R1
0x90020202, // 0001 SETMBR R0 K1 R2
0x90020403, // 0002 SETMBR R0 K2 R3
0x80000000, // 0003 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: parse
********************************************************************/
@ -914,7 +1096,7 @@ be_local_closure(Rule_Matcher_parse, /* name */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[23]) { /* constants */
( &(const bvalue[22]) { /* constants */
/* K0 */ be_const_class(be_class_Rule_Matcher),
/* K1 */ be_nested_str(string),
/* K2 */ be_nested_str(tasmota),
@ -936,12 +1118,11 @@ be_local_closure(Rule_Matcher_parse, /* name */
/* K18 */ be_nested_str(Rule_Matcher_Wildcard),
/* K19 */ be_nested_str(Rule_Matcher_Key),
/* K20 */ be_nested_str(Rule_Matcher_Array),
/* K21 */ be_nested_str(op_parse),
/* K22 */ be_nested_str(Rule_Matcher_Operator),
/* K21 */ be_nested_str(Rule_Matcher_Operator),
}),
&be_const_str_parse,
&be_const_str_solidified,
( &(const binstruction[113]) { /* code */
( &(const binstruction[108]) { /* code */
0x58040000, // 0000 LDCONST R1 K0
0xA40A0200, // 0001 IMPORT R2 K1
0x4C0C0000, // 0002 LDNIL R3
@ -1034,27 +1215,53 @@ be_local_closure(Rule_Matcher_parse, /* name */
0x7001FFBA, // 0059 JMP #0015
0x4C2C0000, // 005A LDNIL R11
0x202C0C0B, // 005B NE R11 R6 R11
0x782E000D, // 005C JMPF R11 #006B
0x782E0008, // 005C JMPF R11 #0066
0x4C2C0000, // 005D LDNIL R11
0x202C0E0B, // 005E NE R11 R7 R11
0x782E000A, // 005F JMPF R11 #006B
0x8C2C0315, // 0060 GETMET R11 R1 K21
0x5C340C00, // 0061 MOVE R13 R6
0x7C2C0400, // 0062 CALL R11 2
0x782E0006, // 0063 JMPF R11 #006B
0x8C300711, // 0064 GETMET R12 R3 K17
0x8C380316, // 0065 GETMET R14 R1 K22
0x5C401600, // 0066 MOVE R16 R11
0x5C440E00, // 0067 MOVE R17 R7
0x5C480C00, // 0068 MOVE R18 R6
0x7C380800, // 0069 CALL R14 4
0x7C300400, // 006A CALL R12 2
0x5C2C0200, // 006B MOVE R11 R1
0x5C300000, // 006C MOVE R12 R0
0x5C340A00, // 006D MOVE R13 R5
0x5C380600, // 006E MOVE R14 R3
0x7C2C0600, // 006F CALL R11 3
0x80041600, // 0070 RET 1 R11
0x782E0005, // 005F JMPF R11 #0066
0x8C2C0711, // 0060 GETMET R11 R3 K17
0x8C340315, // 0061 GETMET R13 R1 K21
0x5C3C0C00, // 0062 MOVE R15 R6
0x5C400E00, // 0063 MOVE R16 R7
0x7C340600, // 0064 CALL R13 3
0x7C2C0400, // 0065 CALL R11 2
0x5C2C0200, // 0066 MOVE R11 R1
0x5C300000, // 0067 MOVE R12 R0
0x5C340A00, // 0068 MOVE R13 R5
0x5C380600, // 0069 MOVE R14 R3
0x7C2C0600, // 006A CALL R11 3
0x80041600, // 006B RET 1 R11
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: init
********************************************************************/
be_local_closure(Rule_Matcher_init, /* name */
be_nested_proto(
4, /* nstack */
4, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 3]) { /* constants */
/* K0 */ be_nested_str(rule),
/* K1 */ be_nested_str(trigger),
/* K2 */ be_nested_str(matchers),
}),
&be_const_str_init,
&be_const_str_solidified,
( &(const binstruction[ 4]) { /* code */
0x90020001, // 0000 SETMBR R0 K0 R1
0x90020202, // 0001 SETMBR R0 K1 R2
0x90020403, // 0002 SETMBR R0 K2 R3
0x80000000, // 0003 RET 0
})
)
);
@ -1122,20 +1329,19 @@ be_local_closure(Rule_Matcher_match, /* name */
be_local_class(Rule_Matcher,
3,
NULL,
be_nested_map(12,
be_nested_map(11,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key(rule, -1), be_const_var(0) },
{ be_const_key(tostring, -1), be_const_closure(Rule_Matcher_tostring_closure) },
{ be_const_key(op_parse, -1), be_const_static_closure(Rule_Matcher_op_parse_closure) },
{ be_const_key(init, 0), be_const_closure(Rule_Matcher_init_closure) },
{ be_const_key(Rule_Matcher_Array, 11), be_const_class(be_class_Rule_Matcher_Array) },
{ be_const_key(Rule_Matcher_Key, 6), be_const_class(be_class_Rule_Matcher_Key) },
{ be_const_key(match, -1), be_const_closure(Rule_Matcher_match_closure) },
{ be_const_key(Rule_Matcher_Operator, 8), be_const_class(be_class_Rule_Matcher_Operator) },
{ be_const_key(trigger, -1), be_const_var(1) },
{ be_const_key(Rule_Matcher_Wildcard, -1), be_const_class(be_class_Rule_Matcher_Wildcard) },
{ be_const_key(matchers, 5), be_const_var(2) },
{ be_const_key(Rule_Matcher_Array, -1), be_const_class(be_class_Rule_Matcher_Array) },
{ be_const_key(trigger, -1), be_const_var(1) },
{ be_const_key(tostring, 2), be_const_closure(Rule_Matcher_tostring_closure) },
{ be_const_key(init, 7), be_const_closure(Rule_Matcher_init_closure) },
{ be_const_key(Rule_Matcher_Key, -1), be_const_class(be_class_Rule_Matcher_Key) },
{ be_const_key(parse, -1), be_const_static_closure(Rule_Matcher_parse_closure) },
{ be_const_key(rule, -1), be_const_var(0) },
{ be_const_key(matchers, 6), be_const_var(2) },
{ be_const_key(Rule_Matcher_Operator, 4), be_const_class(be_class_Rule_Matcher_Operator) },
{ be_const_key(match, -1), be_const_closure(Rule_Matcher_match_closure) },
})),
(bstring*) &be_const_str_Rule_Matcher
);

View File

@ -2113,11 +2113,11 @@ be_local_closure(Tasmota_find_op, /* name */
0x401A0206, // 000C CONNECT R6 K1 R6
0x94180206, // 000D GETIDX R6 R1 R6
0x40180A06, // 000E CONNECT R6 R5 R6
0x40180604, // 000F CONNECT R6 R3 R4
0x94180206, // 0010 GETIDX R6 R1 R6
0x40180A06, // 0011 CONNECT R6 R5 R6
0x00180902, // 0012 ADD R6 R4 K2
0x40180D03, // 0013 CONNECT R6 R6 K3
0x04180902, // 000F SUB R6 R4 K2
0x40180606, // 0010 CONNECT R6 R3 R6
0x94180206, // 0011 GETIDX R6 R1 R6
0x40180A06, // 0012 CONNECT R6 R5 R6
0x40180903, // 0013 CONNECT R6 R4 K3
0x94180206, // 0014 GETIDX R6 R1 R6
0x40180A06, // 0015 CONNECT R6 R5 R6
0x80040A00, // 0016 RET 1 R5

View File

@ -454,10 +454,11 @@ extern "C" {
// Find for an operator in the string
// returns -1 if not found, or returns start in low 16 bits, end in high 16 bits
//
// Detects the following operators: `=`, `==`, `!=`, `!==`, `<`, `<=`, `>`, `>=`, `$<`, `$>`, `$!`, `$|`, `$^`, `|`
int32_t tasm_find_op(bvm *vm);
int32_t tasm_find_op(bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
bool second_phase = false;
int32_t ret = -1;
if (top >= 2 && be_isstring(vm, 2)) {
const char *c = be_tostring(vm, 2);
@ -465,45 +466,48 @@ extern "C" {
int32_t idx_start = -1;
int32_t idx = 0;
// search for `=`, `==`, `!=`, `!==`, `<`, `<=`, `>`, `>=`
int32_t idx_end = -1;
// search for `=`, `==`, `!=`, `!==`, `<`, `<=`, `>`, `>=`, `$<`, `$>`, `$!`, `$|`, `$^`, `|`
while (*c && idx_start < 0) {
switch (c[0]) {
case '=':
case '<':
case '>':
idx_start = idx;
break; // anything starting with `=`, `<` or `>` is a valid operator
if (c[1] == '=') { idx_end = idx_start + 2; } // `<=` or `>=` or `==`
else { idx_end = idx_start + 1; } // `<` or `>` or `=`
break;
case '!':
if (c[1] == '=') {
idx_start = idx; // needs to start with `!=`
if (c[1] == '=') { // this is invalid if isolated `!`
idx_start = idx;
if (c[2] != '=') { idx_end = idx_start + 2; } // `!=`
else { idx_end = idx_start + 3; } // `!==`
}
break;
case '$':
switch (c[1]) {
case '<':
case '>':
case '!':
case '|':
case '^':
idx_start = idx; // `$<`, `$>`, `$!`, `$|`, `$^`
idx_end = idx_start + 2;
break;
default:
break;
}
break;
case '|':
idx_start = idx; // `|`
idx_end = idx_start + 1;
break;
default:
break;
}
c++;
idx++;
}
int idx_end = -1;
if (idx_start >= 0) {
idx_end = idx_start;
// second phase
switch (c[0]) {
case '<':
case '>':
case '=':
if (c[1] != '=') { idx_end += 1; } // `<` or `>` or `=`
else { idx_end += 2; } // `<=` or `>=` or `==`
break;
case '!':
if (c[1] != '=') { ; } // this is invalid if isolated `!`
if (c[2] != '=') { idx_end += 2; } // `!=`
else { idx_end += 3; } // `!==`
break;
default:
break;
}
}
if (idx_start >= 0 && idx_end >= idx_start) {
ret = ((idx_end & 0x7FFF) << 16) | (idx_start & 0x7FFF);
@ -522,6 +526,157 @@ extern "C" {
*/
// String utilities
// From https://stackoverflow.com/questions/68816324/substring-exists-in-string-in-c
//
// changed to case-insensitive version
static const char* substr_i(const char *haystack, const char *needle) {
do {
const char *htmp = haystack;
const char *ntmp = needle;
while (toupper(*htmp) == toupper(*ntmp) && *ntmp) {
htmp++;
ntmp++;
}
if (!*ntmp) {
return haystack; // Beginning of match
}
} while (*haystack++);
return NULL;
}
static bool startswith_i(const char *haystack, const char *needle) {
const char *htmp = haystack;
const char *ntmp = needle;
while (toupper(*htmp) == toupper(*ntmp) && *ntmp) {
htmp++;
ntmp++;
}
return !*ntmp;
}
static bool endswith_i(const char *haystack, const char *needle) {
size_t h_len = strlen(haystack);
size_t n_len = strlen(needle);
if (h_len >= n_len) {
const char *htmp = haystack + h_len - n_len;
const char *ntmp = needle;
return (strcasecmp(htmp, ntmp) == 0);
}
return false;
}
// Apply a string operator, without allocating any object (no pressure on GC)
//
// `tasmota._apply_str_op(op, a, b)`
// Args:
// op: operator (int)
// 1: `==` (equals) case insensitive
// 2: `!==` or `$!` (not equals) case insensitive
// 3: `$<` (starts with) case insensitive
// 4: `$>` (ends with) case insensitive
// 5: `$|` (contains) case insensitive
// 6: `$^` (does not contain) case insensitive
// a: first string
// b: second string
//
int32_t tasm_apply_str_op(bvm *vm);
int32_t tasm_apply_str_op(bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
bbool ret = bfalse;
if (top >= 4 && be_isint(vm, 2) && be_isstring(vm, 3) && be_isstring(vm, 4)) {
int32_t op = be_toint(vm, 2);
const char *a = be_tostring(vm, 3);
const char *b = be_tostring(vm, 4);
switch (op) {
case 1: // `==` (equals) case insensitive
ret = (strcasecmp(a, b) == 0);
break;
case 2: // `!==` or `$!` (not equals) case insensitive
ret = (strcasecmp(a, b) != 0);
break;
case 3: // `$<` (starts with) case insensitive
ret = startswith_i(a, b);
break;
case 4: // `$>` (ends with) case insensitive
ret = endswith_i(a, b);
break;
case 5: // `$|` (contains) case insensitive
ret = (substr_i(a, b) != NULL);
break;
case 6: // `$^` (does not contain) case insensitive
ret = (substr_i(a, b) == NULL);
break;
}
}
be_pushbool(vm, ret);
be_return(vm);
}
/*
# unit tests
# equals
assert(tasmota._apply_str_op(1, "aa", "AA") == true)
assert(tasmota._apply_str_op(1, "aa", "AAA") == false)
assert(tasmota._apply_str_op(1, "a", "AA") == false)
assert(tasmota._apply_str_op(1, "", "AA") == false)
assert(tasmota._apply_str_op(1, "aa", "") == false)
assert(tasmota._apply_str_op(1, "", "") == true)
# not equals
assert(tasmota._apply_str_op(2, "aa", "AA") == false)
assert(tasmota._apply_str_op(2, "aa", "AAA") == true)
assert(tasmota._apply_str_op(2, "a", "AA") == true)
assert(tasmota._apply_str_op(2, "", "AA") == true)
assert(tasmota._apply_str_op(2, "aa", "") == true)
assert(tasmota._apply_str_op(2, "", "") == false)
# starts with
assert(tasmota._apply_str_op(3, "aabbcc", "AA") == true)
assert(tasmota._apply_str_op(3, "aaabbcc", "AA") == true)
assert(tasmota._apply_str_op(3, "abbaacc", "AA") == false)
assert(tasmota._apply_str_op(3, "aabbcc", "a") == true)
assert(tasmota._apply_str_op(3, "aabbcc", "") == true)
assert(tasmota._apply_str_op(3, "", "") == true)
assert(tasmota._apply_str_op(3, "", "a") == false)
assert(tasmota._apply_str_op(3, "azeaze", "az") == true)
assert(tasmota._apply_str_op(3, "azeaze", "ze") == false)
# ends with
assert(tasmota._apply_str_op(4, "azeaze", "az") == false)
assert(tasmota._apply_str_op(4, "azeaze", "ze") == true)
assert(tasmota._apply_str_op(4, "azeaze", "") == true)
assert(tasmota._apply_str_op(4, "", "aa") == false)
assert(tasmota._apply_str_op(4, "aa", "aa") == true)
assert(tasmota._apply_str_op(4, "aabaa", "aa") == true)
# contains
assert(tasmota._apply_str_op(5, "azeaze", "az") == true)
assert(tasmota._apply_str_op(5, "azeaze", "ze") == true)
assert(tasmota._apply_str_op(5, "azeaze", "") == true)
assert(tasmota._apply_str_op(5, "azeaze", "e") == true)
assert(tasmota._apply_str_op(5, "azeaze", "a") == true)
assert(tasmota._apply_str_op(5, "azeaze", "z") == true)
assert(tasmota._apply_str_op(5, "azertyuiop", "tyui") == true)
assert(tasmota._apply_str_op(5, "azertyuiop", "azr") == false)
assert(tasmota._apply_str_op(5, "", "aze") == false)
# not contains
assert(tasmota._apply_str_op(6, "azeaze", "az") == false)
assert(tasmota._apply_str_op(6, "azeaze", "ze") == false)
assert(tasmota._apply_str_op(6, "azeaze", "") == false)
assert(tasmota._apply_str_op(6, "azeaze", "e") == false)
assert(tasmota._apply_str_op(6, "azeaze", "a") == false)
assert(tasmota._apply_str_op(6, "azeaze", "z") == false)
assert(tasmota._apply_str_op(6, "azertyuiop", "tyui") == false)
assert(tasmota._apply_str_op(6, "azertyuiop", "azr") == true)
assert(tasmota._apply_str_op(6, "", "aze") == true)
*/
// web append with decimal conversion
int32_t l_webSend(bvm *vm);
int32_t l_webSend(bvm *vm) {