implement new features on parser
This commit is contained in:
parent
ba40814729
commit
15dab24125
@ -56,6 +56,16 @@ RewardData *RewardInfo `eq2:"substruct,ifvariableset=HasRewards"`
|
||||
|
||||
// Only parse if we set the "has_equipment" flag
|
||||
Equipment []Equipment `eq2:"equipment,ifflag=has_equipment"`
|
||||
|
||||
// Array index variables - access specific array elements
|
||||
ModCount uint8 `eq2:"int8"`
|
||||
Mods []Mod `eq2:"array,arraysize=ModCount"`
|
||||
// This checks if Mods[0] exists and is truthy
|
||||
ExtraData []byte `eq2:"char,len=10,ifvariableset=header_info_mod_need_0"`
|
||||
|
||||
// Dynamic array index using %i (replaced with current array index)
|
||||
StatTypes []uint8 `eq2:"int8,len=5"`
|
||||
StatValues []any `eq2:"int32,type2=float,type2criteria=stat_type_%i!=6"`
|
||||
```
|
||||
|
||||
### Type switching (when EQ2 reuses the same bytes for different things)
|
||||
@ -63,6 +73,21 @@ Equipment []Equipment `eq2:"equipment,ifflag=has_equipment"`
|
||||
// Normally parse as int32, but if StatType != 6, parse as float instead
|
||||
StatType uint8 `eq2:"int8"`
|
||||
StatValue any `eq2:"int32,type2=float,type2criteria=StatType!=6"`
|
||||
|
||||
// String length operators for type switching
|
||||
NameLength uint8 `eq2:"int8"`
|
||||
Name string `eq2:"string16,type2=string8,type2criteria=stat_name!>10"`
|
||||
```
|
||||
|
||||
### String length operators
|
||||
Use `!>`, `!<`, `!>=`, `!<=`, `!=` for string length comparisons:
|
||||
```go
|
||||
// Switch to string8 if name length > 10 characters
|
||||
Name string `eq2:"string16,type2=string8,type2criteria=player_name!>10"`
|
||||
|
||||
// Only parse if description is not empty
|
||||
HasDesc uint8 `eq2:"int8"`
|
||||
Description string `eq2:"string16,ifvariableset=HasDesc,if=description!>0"`
|
||||
```
|
||||
|
||||
### Size limits (because EQ2 packets can get weird)
|
||||
@ -104,12 +129,22 @@ type CharacterData struct {
|
||||
|
||||
// Nested stuff
|
||||
Stats PlayerStats `eq2:"substruct"`
|
||||
|
||||
// Array index access example
|
||||
BuffCount uint8 `eq2:"int8"`
|
||||
Buffs []BuffData `eq2:"array,arraysize=BuffCount"`
|
||||
// Only parse extended data if first buff exists
|
||||
ExtendedBuffData []byte `eq2:"char,len=20,ifvariableset=buffs_0"`
|
||||
}
|
||||
|
||||
type InventoryItem struct {
|
||||
ItemID uint32 `eq2:"int32"`
|
||||
Quantity uint16 `eq2:"int16"`
|
||||
Color common.EQ2Color `eq2:"color"`
|
||||
|
||||
// Type switching based on string length
|
||||
NameType uint8 `eq2:"int8"`
|
||||
Name any `eq2:"string16,type2=string8,type2criteria=item_name!<=8"`
|
||||
}
|
||||
|
||||
type PlayerStats struct {
|
||||
@ -117,6 +152,34 @@ type PlayerStats struct {
|
||||
Mana uint32 `eq2:"int32"`
|
||||
Stamina uint32 `eq2:"int32"`
|
||||
}
|
||||
|
||||
type BuffData struct {
|
||||
BuffID uint32 `eq2:"int32"`
|
||||
Duration uint16 `eq2:"int16"`
|
||||
}
|
||||
```
|
||||
|
||||
## Advanced conditional patterns
|
||||
|
||||
```go
|
||||
type ComplexPacket struct {
|
||||
// Array with per-element conditionals using %i
|
||||
StatCount uint8 `eq2:"int8"`
|
||||
StatTypes []uint8 `eq2:"int8,len=StatCount"`
|
||||
StatValues []any `eq2:"int32,type2=float,type2criteria=stat_type_%i!=6"`
|
||||
|
||||
// Array index access for conditionals
|
||||
ModCount uint8 `eq2:"int8"`
|
||||
Mods []Mod `eq2:"array,arraysize=ModCount"`
|
||||
// Parse only if specific array elements exist
|
||||
Bonus1 uint32 `eq2:"int32,ifvariableset=header_info_mod_need_0"`
|
||||
Bonus2 uint32 `eq2:"int32,ifvariableset=header_info_mod_need_1"`
|
||||
|
||||
// String length conditionals
|
||||
PlayerName string `eq2:"string16"`
|
||||
ShortName string `eq2:"string8,if=player_name!<=8"`
|
||||
LongDesc string `eq2:"string32,if=player_name!>15"`
|
||||
}
|
||||
```
|
||||
|
||||
## Converting from XML
|
||||
@ -128,4 +191,8 @@ If you've got EQ2's XML packet definitions, the conversion is pretty straightfor
|
||||
| `Type="int32"` | `eq2:"int32"` |
|
||||
| `ArraySizeVariable="count"` | `arraysize=Count` |
|
||||
| `IfVariableSet="flag"` | `ifvariableset=Flag` |
|
||||
| `Size="5"` | `len=5` |
|
||||
| `Size="5"` | `len=5` |
|
||||
| `Type2Criteria="field!=value"` | `type2criteria=Field!=value` |
|
||||
| `Type2Criteria="name!>10"` | `type2criteria=name!>10` |
|
||||
| Array index access | `ifvariableset=array_name_0` |
|
||||
| Dynamic index patterns | `type2criteria=field_%i!=value` |
|
@ -2,6 +2,7 @@ package parser
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -50,17 +51,9 @@ func (p *Parser) evaluateCondition(condition *FieldCondition) bool {
|
||||
return p.isVariableSet(condition.Variable)
|
||||
}
|
||||
|
||||
cachedValue, exists := p.fieldCache[condition.Variable]
|
||||
cachedValue, exists := p.resolveVariable(condition.Variable)
|
||||
if !exists {
|
||||
if p.currentStruct.IsValid() {
|
||||
if structField := p.currentStruct.FieldByName(condition.Variable); structField.IsValid() {
|
||||
cachedValue = structField.Interface()
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
compareValue, err := p.convertValue(condition.Value, cachedValue)
|
||||
@ -73,29 +66,16 @@ func (p *Parser) evaluateCondition(condition *FieldCondition) bool {
|
||||
|
||||
// isVariableSet checks if a variable exists and has a truthy value
|
||||
func (p *Parser) isVariableSet(variable string) bool {
|
||||
if cachedValue, exists := p.fieldCache[variable]; exists {
|
||||
return p.isTruthy(cachedValue)
|
||||
cachedValue, exists := p.resolveVariable(variable)
|
||||
if !exists {
|
||||
return false
|
||||
}
|
||||
|
||||
if p.currentStruct.IsValid() {
|
||||
if field := p.currentStruct.FieldByName(variable); field.IsValid() {
|
||||
return p.isTruthy(field.Interface())
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return p.isTruthy(cachedValue)
|
||||
}
|
||||
|
||||
// evaluateEqualsCondition checks field equality
|
||||
func (p *Parser) evaluateEqualsCondition(variable, value string) bool {
|
||||
cachedValue, exists := p.fieldCache[variable]
|
||||
if !exists && p.currentStruct.IsValid() {
|
||||
if field := p.currentStruct.FieldByName(variable); field.IsValid() {
|
||||
cachedValue = field.Interface()
|
||||
exists = true
|
||||
}
|
||||
}
|
||||
|
||||
cachedValue, exists := p.resolveVariable(variable)
|
||||
if !exists {
|
||||
return false
|
||||
}
|
||||
@ -108,16 +88,34 @@ func (p *Parser) evaluateEqualsCondition(variable, value string) bool {
|
||||
return p.compareValues(cachedValue, compareValue, "==")
|
||||
}
|
||||
|
||||
// evaluateType2Criteria evaluates type2 criteria for alternative types
|
||||
// evaluateType2Criteria evaluates type2 criteria for alternative types with string length support
|
||||
func (p *Parser) evaluateType2Criteria(criteria string) bool {
|
||||
operators := []string{"!=", "==", ">=", "<=", ">", "<"}
|
||||
// String length operators: !>, !<, !>=, !<=, !=
|
||||
stringLengthOps := []string{"!>=", "!<=", "!>", "!<", "!="}
|
||||
|
||||
for _, op := range stringLengthOps {
|
||||
if idx := strings.Index(criteria, op); idx > 0 {
|
||||
fieldName := strings.TrimSpace(criteria[:idx])
|
||||
valueStr := strings.TrimSpace(criteria[idx+len(op):])
|
||||
|
||||
cachedValue, exists := p.resolveVariable(fieldName)
|
||||
if !exists {
|
||||
return false
|
||||
}
|
||||
|
||||
return p.evaluateStringLengthCondition(cachedValue, valueStr, op)
|
||||
}
|
||||
}
|
||||
|
||||
// Standard comparison operators
|
||||
operators := []string{">=", "<=", ">", "<", "=="}
|
||||
|
||||
for _, op := range operators {
|
||||
if idx := strings.Index(criteria, op); idx > 0 {
|
||||
fieldName := strings.TrimSpace(criteria[:idx])
|
||||
valueStr := strings.TrimSpace(criteria[idx+len(op):])
|
||||
|
||||
cachedValue, exists := p.fieldCache[fieldName]
|
||||
cachedValue, exists := p.resolveVariable(fieldName)
|
||||
if !exists {
|
||||
return false
|
||||
}
|
||||
@ -133,3 +131,137 @@ func (p *Parser) evaluateType2Criteria(criteria string) bool {
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// evaluateStringLengthCondition evaluates string length conditions
|
||||
func (p *Parser) evaluateStringLengthCondition(value any, lengthStr, operator string) bool {
|
||||
var stringVal string
|
||||
|
||||
// Extract string value from various types
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
stringVal = v
|
||||
default:
|
||||
// Try to get string representation from struct fields
|
||||
if reflect.TypeOf(value).Kind() == reflect.Struct {
|
||||
val := reflect.ValueOf(value)
|
||||
if dataField := val.FieldByName("Data"); dataField.IsValid() && dataField.Kind() == reflect.String {
|
||||
stringVal = dataField.String()
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
targetLength, err := strconv.Atoi(lengthStr)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
stringLength := len(stringVal)
|
||||
|
||||
switch operator {
|
||||
case "!>":
|
||||
return stringLength > targetLength
|
||||
case "!<":
|
||||
return stringLength < targetLength
|
||||
case "!>=":
|
||||
return stringLength >= targetLength
|
||||
case "!<=":
|
||||
return stringLength <= targetLength
|
||||
case "!=":
|
||||
return stringLength != targetLength
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// resolveVariable resolves variables with support for array indices and complex patterns
|
||||
func (p *Parser) resolveVariable(variable string) (any, bool) {
|
||||
// Handle %i patterns by replacing with current array index
|
||||
if strings.Contains(variable, "%i") {
|
||||
currentIndex := p.GetCurrentArrayIndex()
|
||||
if currentIndex >= 0 {
|
||||
variable = strings.ReplaceAll(variable, "%i", strconv.Itoa(currentIndex))
|
||||
}
|
||||
}
|
||||
|
||||
// Check field cache first
|
||||
if cachedValue, exists := p.fieldCache[variable]; exists {
|
||||
return cachedValue, true
|
||||
}
|
||||
|
||||
// Handle array index patterns like "header_info_mod_need_0"
|
||||
if strings.Contains(variable, "_") {
|
||||
if value, exists := p.resolveArrayIndexVariable(variable); exists {
|
||||
return value, true
|
||||
}
|
||||
}
|
||||
|
||||
// Check current struct
|
||||
if p.currentStruct.IsValid() {
|
||||
if field := p.currentStruct.FieldByName(variable); field.IsValid() {
|
||||
return field.Interface(), true
|
||||
}
|
||||
}
|
||||
|
||||
// Check struct stack for nested resolution
|
||||
for i := len(p.structStack) - 1; i >= 0; i-- {
|
||||
if field := p.structStack[i].FieldByName(variable); field.IsValid() {
|
||||
return field.Interface(), true
|
||||
}
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// resolveArrayIndexVariable handles variables with array index suffixes
|
||||
func (p *Parser) resolveArrayIndexVariable(variable string) (any, bool) {
|
||||
parts := strings.Split(variable, "_")
|
||||
if len(parts) < 2 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Try to extract index from last part
|
||||
lastPart := parts[len(parts)-1]
|
||||
if index, err := strconv.Atoi(lastPart); err == nil {
|
||||
// Reconstruct base variable name without index
|
||||
baseVar := strings.Join(parts[:len(parts)-1], "_")
|
||||
|
||||
// Look for array/slice field with this base name
|
||||
if cachedValue, exists := p.fieldCache[baseVar]; exists {
|
||||
return p.getArrayElement(cachedValue, index)
|
||||
}
|
||||
|
||||
// Check current struct for array field
|
||||
if p.currentStruct.IsValid() {
|
||||
if field := p.currentStruct.FieldByName(baseVar); field.IsValid() {
|
||||
return p.getArrayElement(field.Interface(), index)
|
||||
}
|
||||
}
|
||||
|
||||
// Check struct stack
|
||||
for i := len(p.structStack) - 1; i >= 0; i-- {
|
||||
if field := p.structStack[i].FieldByName(baseVar); field.IsValid() {
|
||||
return p.getArrayElement(field.Interface(), index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// getArrayElement safely extracts element from array/slice
|
||||
func (p *Parser) getArrayElement(value any, index int) (any, bool) {
|
||||
val := reflect.ValueOf(value)
|
||||
|
||||
switch val.Kind() {
|
||||
case reflect.Slice, reflect.Array:
|
||||
if index >= 0 && index < val.Len() {
|
||||
return val.Index(index).Interface(), true
|
||||
}
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
@ -102,9 +102,23 @@ func (p *Parser) parseTagParameter(fieldTag *FieldTag, part string) {
|
||||
}
|
||||
}
|
||||
|
||||
// parseCondition creates FieldCondition from condition string
|
||||
// parseCondition creates FieldCondition from condition string with enhanced operator support
|
||||
func (p *Parser) parseCondition(condition string) *FieldCondition {
|
||||
operators := []string{"!=", "==", ">=", "<=", ">", "<", "&", "|"}
|
||||
// String length operators must be checked first due to overlapping patterns
|
||||
stringLengthOps := []string{"!>=", "!<=", "!>", "!<", "!="}
|
||||
|
||||
for _, op := range stringLengthOps {
|
||||
if idx := strings.Index(condition, op); idx > 0 {
|
||||
return &FieldCondition{
|
||||
Variable: strings.TrimSpace(condition[:idx]),
|
||||
Value: strings.TrimSpace(condition[idx+len(op):]),
|
||||
Operator: op,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Standard comparison operators
|
||||
operators := []string{">=", "<=", ">", "<", "==", "&", "|"}
|
||||
|
||||
for _, op := range operators {
|
||||
if idx := strings.Index(condition, op); idx > 0 {
|
||||
|
@ -3,20 +3,39 @@ package parser
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// getDynamicLength gets length from another field with stack support
|
||||
// getDynamicLength gets length from another field with stack support and array index resolution
|
||||
func (p *Parser) getDynamicLength(fieldName string) int {
|
||||
// Handle %i patterns by replacing with current array index
|
||||
if strings.Contains(fieldName, "%i") {
|
||||
currentIndex := p.GetCurrentArrayIndex()
|
||||
if currentIndex >= 0 {
|
||||
fieldName = strings.ReplaceAll(fieldName, "%i", strconv.Itoa(currentIndex))
|
||||
}
|
||||
}
|
||||
|
||||
// Check field cache first
|
||||
if cachedValue, exists := p.fieldCache[fieldName]; exists {
|
||||
return p.valueToInt(cachedValue)
|
||||
}
|
||||
|
||||
// Handle array index patterns like "header_info_mod_need_0"
|
||||
if strings.Contains(fieldName, "_") {
|
||||
if value, exists := p.resolveArrayIndexVariableForLength(fieldName); exists {
|
||||
return p.valueToInt(value)
|
||||
}
|
||||
}
|
||||
|
||||
// Check current struct
|
||||
if p.currentStruct.IsValid() {
|
||||
if field := p.currentStruct.FieldByName(fieldName); field.IsValid() {
|
||||
return p.valueToInt(field.Interface())
|
||||
}
|
||||
}
|
||||
|
||||
// Check struct stack for nested resolution
|
||||
for i := len(p.structStack) - 1; i >= 0; i-- {
|
||||
if field := p.structStack[i].FieldByName(fieldName); field.IsValid() {
|
||||
return p.valueToInt(field.Interface())
|
||||
@ -26,7 +45,57 @@ func (p *Parser) getDynamicLength(fieldName string) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// convertValue converts string to appropriate type for comparison
|
||||
// resolveArrayIndexVariableForLength handles array index variable resolution for length calculations
|
||||
func (p *Parser) resolveArrayIndexVariableForLength(variable string) (any, bool) {
|
||||
parts := strings.Split(variable, "_")
|
||||
if len(parts) < 2 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Try to extract index from last part
|
||||
lastPart := parts[len(parts)-1]
|
||||
if index, err := strconv.Atoi(lastPart); err == nil {
|
||||
// Reconstruct base variable name without index
|
||||
baseVar := strings.Join(parts[:len(parts)-1], "_")
|
||||
|
||||
// Look for array/slice field with this base name
|
||||
if cachedValue, exists := p.fieldCache[baseVar]; exists {
|
||||
return p.getArrayElementSafe(cachedValue, index)
|
||||
}
|
||||
|
||||
// Check current struct for array field
|
||||
if p.currentStruct.IsValid() {
|
||||
if field := p.currentStruct.FieldByName(baseVar); field.IsValid() {
|
||||
return p.getArrayElementSafe(field.Interface(), index)
|
||||
}
|
||||
}
|
||||
|
||||
// Check struct stack
|
||||
for i := len(p.structStack) - 1; i >= 0; i-- {
|
||||
if field := p.structStack[i].FieldByName(baseVar); field.IsValid() {
|
||||
return p.getArrayElementSafe(field.Interface(), index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// getArrayElementSafe safely extracts element from array/slice with bounds checking
|
||||
func (p *Parser) getArrayElementSafe(value any, index int) (any, bool) {
|
||||
val := reflect.ValueOf(value)
|
||||
|
||||
switch val.Kind() {
|
||||
case reflect.Slice, reflect.Array:
|
||||
if index >= 0 && index < val.Len() {
|
||||
return val.Index(index).Interface(), true
|
||||
}
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// convertValue converts string to appropriate type for comparison with enhanced string support
|
||||
func (p *Parser) convertValue(valueStr string, reference any) (any, error) {
|
||||
switch reference.(type) {
|
||||
case uint8, int8:
|
||||
@ -57,6 +126,14 @@ func (p *Parser) convertValue(valueStr string, reference any) (any, error) {
|
||||
return valueStr, nil
|
||||
}
|
||||
|
||||
// Handle struct types with Data field (EQ2String types)
|
||||
if reflect.TypeOf(reference).Kind() == reflect.Struct {
|
||||
refVal := reflect.ValueOf(reference)
|
||||
if dataField := refVal.FieldByName("Data"); dataField.IsValid() && dataField.Kind() == reflect.String {
|
||||
return valueStr, nil
|
||||
}
|
||||
}
|
||||
|
||||
if val, err := strconv.ParseInt(valueStr, 0, 32); err == nil {
|
||||
return int(val), nil
|
||||
}
|
||||
@ -64,8 +141,16 @@ func (p *Parser) convertValue(valueStr string, reference any) (any, error) {
|
||||
return valueStr, nil
|
||||
}
|
||||
|
||||
// compareValues performs comparison between two values
|
||||
// compareValues performs comparison between two values with enhanced string support
|
||||
func (p *Parser) compareValues(a, b any, op string) bool {
|
||||
// Handle string comparisons first
|
||||
if p.isStringValue(a) && p.isStringValue(b) {
|
||||
aStr := p.extractStringValue(a)
|
||||
bStr := p.extractStringValue(b)
|
||||
return p.compareStrings(aStr, bStr, op)
|
||||
}
|
||||
|
||||
// Fall back to numeric comparison
|
||||
aVal := p.valueToInt64(a)
|
||||
bVal := p.valueToInt64(b)
|
||||
|
||||
@ -91,7 +176,59 @@ func (p *Parser) compareValues(a, b any, op string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// valueToInt converts various types to int
|
||||
// isStringValue checks if a value is or contains a string
|
||||
func (p *Parser) isStringValue(value any) bool {
|
||||
switch value.(type) {
|
||||
case string:
|
||||
return true
|
||||
default:
|
||||
if reflect.TypeOf(value).Kind() == reflect.Struct {
|
||||
val := reflect.ValueOf(value)
|
||||
if dataField := val.FieldByName("Data"); dataField.IsValid() && dataField.Kind() == reflect.String {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// extractStringValue extracts string from value or struct Data field
|
||||
func (p *Parser) extractStringValue(value any) string {
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
return v
|
||||
default:
|
||||
if reflect.TypeOf(value).Kind() == reflect.Struct {
|
||||
val := reflect.ValueOf(value)
|
||||
if dataField := val.FieldByName("Data"); dataField.IsValid() && dataField.Kind() == reflect.String {
|
||||
return dataField.String()
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// compareStrings performs string comparison operations
|
||||
func (p *Parser) compareStrings(a, b, op string) bool {
|
||||
switch op {
|
||||
case "==":
|
||||
return a == b
|
||||
case "!=":
|
||||
return a != b
|
||||
case ">":
|
||||
return a > b
|
||||
case ">=":
|
||||
return a >= b
|
||||
case "<":
|
||||
return a < b
|
||||
case "<=":
|
||||
return a <= b
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// valueToInt converts various types to int with enhanced type support
|
||||
func (p *Parser) valueToInt(v any) int {
|
||||
switch val := v.(type) {
|
||||
case uint8:
|
||||
@ -112,11 +249,27 @@ func (p *Parser) valueToInt(v any) int {
|
||||
return int(val)
|
||||
case int:
|
||||
return val
|
||||
case bool:
|
||||
if val {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
default:
|
||||
// Handle struct types that might have numeric fields
|
||||
if reflect.TypeOf(v).Kind() == reflect.Struct {
|
||||
refVal := reflect.ValueOf(v)
|
||||
// Try common numeric field names
|
||||
for _, fieldName := range []string{"Value", "Size", "Length", "Count"} {
|
||||
if field := refVal.FieldByName(fieldName); field.IsValid() {
|
||||
return p.valueToInt(field.Interface())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// valueToInt64 converts various types to int64 for comparison
|
||||
// valueToInt64 converts various types to int64 for comparison with enhanced support
|
||||
func (p *Parser) valueToInt64(v any) int64 {
|
||||
switch val := v.(type) {
|
||||
case uint8:
|
||||
@ -141,11 +294,27 @@ func (p *Parser) valueToInt64(v any) int64 {
|
||||
return int64(val)
|
||||
case float64:
|
||||
return int64(val)
|
||||
case bool:
|
||||
if val {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
default:
|
||||
// Handle struct types that might have numeric fields
|
||||
if reflect.TypeOf(v).Kind() == reflect.Struct {
|
||||
refVal := reflect.ValueOf(v)
|
||||
// Try common numeric field names
|
||||
for _, fieldName := range []string{"Value", "Size", "Length", "Count"} {
|
||||
if field := refVal.FieldByName(fieldName); field.IsValid() {
|
||||
return p.valueToInt64(field.Interface())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// isTruthy checks if a value is truthy
|
||||
// isTruthy checks if a value is truthy with enhanced type support
|
||||
func (p *Parser) isTruthy(v any) bool {
|
||||
switch val := v.(type) {
|
||||
case bool:
|
||||
@ -154,6 +323,21 @@ func (p *Parser) isTruthy(v any) bool {
|
||||
return p.valueToInt64(val) != 0
|
||||
case string:
|
||||
return val != ""
|
||||
default:
|
||||
// Handle struct types
|
||||
if reflect.TypeOf(v).Kind() == reflect.Struct {
|
||||
refVal := reflect.ValueOf(v)
|
||||
// Check for Data field (string types)
|
||||
if dataField := refVal.FieldByName("Data"); dataField.IsValid() && dataField.Kind() == reflect.String {
|
||||
return dataField.String() != ""
|
||||
}
|
||||
// Check for numeric fields
|
||||
for _, fieldName := range []string{"Value", "Size", "Length", "Count"} {
|
||||
if field := refVal.FieldByName(fieldName); field.IsValid() {
|
||||
return p.valueToInt64(field.Interface()) != 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user