package swag import ( "go/ast" "go/token" "reflect" "strconv" "strings" "unicode/utf8" ) // ConstVariable a model to record a const variable type ConstVariable struct { Name *ast.Ident Type ast.Expr Value interface{} Comment *ast.CommentGroup File *ast.File Pkg *PackageDefinitions } var escapedChars = map[uint8]uint8{ 'n': '\n', 'r': '\r', 't': '\t', 'v': '\v', '\\': '\\', '"': '"', } // EvaluateEscapedChar parse escaped character func EvaluateEscapedChar(text string) rune { if len(text) == 1 { return rune(text[0]) } if len(text) == 2 && text[0] == '\\' { return rune(escapedChars[text[1]]) } if len(text) == 6 && text[0:2] == "\\u" { n, err := strconv.ParseInt(text[2:], 16, 32) if err == nil { return rune(n) } } return 0 } // EvaluateEscapedString parse escaped characters in string func EvaluateEscapedString(text string) string { if !strings.ContainsRune(text, '\\') { return text } result := make([]byte, 0, len(text)) for i := 0; i < len(text); i++ { if text[i] == '\\' { i++ if text[i] == 'u' { i++ char, err := strconv.ParseInt(text[i:i+4], 16, 32) if err == nil { result = utf8.AppendRune(result, rune(char)) } i += 3 } else if c, ok := escapedChars[text[i]]; ok { result = append(result, c) } } else { result = append(result, text[i]) } } return string(result) } // EvaluateDataConversion evaluate the type a explicit type conversion func EvaluateDataConversion(x interface{}, typeName string) interface{} { switch value := x.(type) { case int: switch typeName { case "int": return int(value) case "byte": return byte(value) case "int8": return int8(value) case "int16": return int16(value) case "int32": return int32(value) case "int64": return int64(value) case "uint": return uint(value) case "uint8": return uint8(value) case "uint16": return uint16(value) case "uint32": return uint32(value) case "uint64": return uint64(value) case "rune": return rune(value) } case uint: switch typeName { case "int": return int(value) case "byte": return byte(value) case "int8": return int8(value) case "int16": return int16(value) case "int32": return int32(value) case "int64": return int64(value) case "uint": return uint(value) case "uint8": return uint8(value) case "uint16": return uint16(value) case "uint32": return uint32(value) case "uint64": return uint64(value) case "rune": return rune(value) } case int8: switch typeName { case "int": return int(value) case "byte": return byte(value) case "int8": return int8(value) case "int16": return int16(value) case "int32": return int32(value) case "int64": return int64(value) case "uint": return uint(value) case "uint8": return uint8(value) case "uint16": return uint16(value) case "uint32": return uint32(value) case "uint64": return uint64(value) case "rune": return rune(value) } case uint8: switch typeName { case "int": return int(value) case "byte": return byte(value) case "int8": return int8(value) case "int16": return int16(value) case "int32": return int32(value) case "int64": return int64(value) case "uint": return uint(value) case "uint8": return uint8(value) case "uint16": return uint16(value) case "uint32": return uint32(value) case "uint64": return uint64(value) case "rune": return rune(value) } case int16: switch typeName { case "int": return int(value) case "byte": return byte(value) case "int8": return int8(value) case "int16": return int16(value) case "int32": return int32(value) case "int64": return int64(value) case "uint": return uint(value) case "uint8": return uint8(value) case "uint16": return uint16(value) case "uint32": return uint32(value) case "uint64": return uint64(value) case "rune": return rune(value) } case uint16: switch typeName { case "int": return int(value) case "byte": return byte(value) case "int8": return int8(value) case "int16": return int16(value) case "int32": return int32(value) case "int64": return int64(value) case "uint": return uint(value) case "uint8": return uint8(value) case "uint16": return uint16(value) case "uint32": return uint32(value) case "uint64": return uint64(value) case "rune": return rune(value) } case int32: switch typeName { case "int": return int(value) case "byte": return byte(value) case "int8": return int8(value) case "int16": return int16(value) case "int32": return int32(value) case "int64": return int64(value) case "uint": return uint(value) case "uint8": return uint8(value) case "uint16": return uint16(value) case "uint32": return uint32(value) case "uint64": return uint64(value) case "rune": return rune(value) case "string": return string(value) } case uint32: switch typeName { case "int": return int(value) case "byte": return byte(value) case "int8": return int8(value) case "int16": return int16(value) case "int32": return int32(value) case "int64": return int64(value) case "uint": return uint(value) case "uint8": return uint8(value) case "uint16": return uint16(value) case "uint32": return uint32(value) case "uint64": return uint64(value) case "rune": return rune(value) } case int64: switch typeName { case "int": return int(value) case "byte": return byte(value) case "int8": return int8(value) case "int16": return int16(value) case "int32": return int32(value) case "int64": return int64(value) case "uint": return uint(value) case "uint8": return uint8(value) case "uint16": return uint16(value) case "uint32": return uint32(value) case "uint64": return uint64(value) case "rune": return rune(value) } case uint64: switch typeName { case "int": return int(value) case "byte": return byte(value) case "int8": return int8(value) case "int16": return int16(value) case "int32": return int32(value) case "int64": return int64(value) case "uint": return uint(value) case "uint8": return uint8(value) case "uint16": return uint16(value) case "uint32": return uint32(value) case "uint64": return uint64(value) case "rune": return rune(value) } case string: switch typeName { case "string": return value } } return nil } // EvaluateUnary evaluate the type and value of a unary expression func EvaluateUnary(x interface{}, operator token.Token, xtype ast.Expr) (interface{}, ast.Expr) { switch operator { case token.SUB: switch value := x.(type) { case int: return -value, xtype case int8: return -value, xtype case int16: return -value, xtype case int32: return -value, xtype case int64: return -value, xtype } case token.XOR: switch value := x.(type) { case int: return ^value, xtype case int8: return ^value, xtype case int16: return ^value, xtype case int32: return ^value, xtype case int64: return ^value, xtype case uint: return ^value, xtype case uint8: return ^value, xtype case uint16: return ^value, xtype case uint32: return ^value, xtype case uint64: return ^value, xtype } } return nil, nil } // EvaluateBinary evaluate the type and value of a binary expression func EvaluateBinary(x, y interface{}, operator token.Token, xtype, ytype ast.Expr) (interface{}, ast.Expr) { if operator == token.SHR || operator == token.SHL { var rightOperand uint64 yValue := reflect.ValueOf(y) if yValue.CanUint() { rightOperand = yValue.Uint() } else if yValue.CanInt() { rightOperand = uint64(yValue.Int()) } switch operator { case token.SHL: switch xValue := x.(type) { case int: return xValue << rightOperand, xtype case int8: return xValue << rightOperand, xtype case int16: return xValue << rightOperand, xtype case int32: return xValue << rightOperand, xtype case int64: return xValue << rightOperand, xtype case uint: return xValue << rightOperand, xtype case uint8: return xValue << rightOperand, xtype case uint16: return xValue << rightOperand, xtype case uint32: return xValue << rightOperand, xtype case uint64: return xValue << rightOperand, xtype } case token.SHR: switch xValue := x.(type) { case int: return xValue >> rightOperand, xtype case int8: return xValue >> rightOperand, xtype case int16: return xValue >> rightOperand, xtype case int32: return xValue >> rightOperand, xtype case int64: return xValue >> rightOperand, xtype case uint: return xValue >> rightOperand, xtype case uint8: return xValue >> rightOperand, xtype case uint16: return xValue >> rightOperand, xtype case uint32: return xValue >> rightOperand, xtype case uint64: return xValue >> rightOperand, xtype } } return nil, nil } evalType := xtype if evalType == nil { evalType = ytype } xValue := reflect.ValueOf(x) yValue := reflect.ValueOf(y) if xValue.Kind() == reflect.String && yValue.Kind() == reflect.String { return xValue.String() + yValue.String(), evalType } var targetValue reflect.Value if xValue.Kind() != reflect.Int { targetValue = reflect.New(xValue.Type()).Elem() } else { targetValue = reflect.New(yValue.Type()).Elem() } switch operator { case token.ADD: if xValue.CanInt() && yValue.CanInt() { targetValue.SetInt(xValue.Int() + yValue.Int()) } else if xValue.CanUint() && yValue.CanUint() { targetValue.SetUint(xValue.Uint() + yValue.Uint()) } else if xValue.CanInt() && yValue.CanUint() { targetValue.SetUint(uint64(xValue.Int()) + yValue.Uint()) } else if xValue.CanUint() && yValue.CanInt() { targetValue.SetUint(xValue.Uint() + uint64(yValue.Int())) } case token.SUB: if xValue.CanInt() && yValue.CanInt() { targetValue.SetInt(xValue.Int() - yValue.Int()) } else if xValue.CanUint() && yValue.CanUint() { targetValue.SetUint(xValue.Uint() - yValue.Uint()) } else if xValue.CanInt() && yValue.CanUint() { targetValue.SetUint(uint64(xValue.Int()) - yValue.Uint()) } else if xValue.CanUint() && yValue.CanInt() { targetValue.SetUint(xValue.Uint() - uint64(yValue.Int())) } case token.MUL: if xValue.CanInt() && yValue.CanInt() { targetValue.SetInt(xValue.Int() * yValue.Int()) } else if xValue.CanUint() && yValue.CanUint() { targetValue.SetUint(xValue.Uint() * yValue.Uint()) } else if xValue.CanInt() && yValue.CanUint() { targetValue.SetUint(uint64(xValue.Int()) * yValue.Uint()) } else if xValue.CanUint() && yValue.CanInt() { targetValue.SetUint(xValue.Uint() * uint64(yValue.Int())) } case token.QUO: if xValue.CanInt() && yValue.CanInt() { targetValue.SetInt(xValue.Int() / yValue.Int()) } else if xValue.CanUint() && yValue.CanUint() { targetValue.SetUint(xValue.Uint() / yValue.Uint()) } else if xValue.CanInt() && yValue.CanUint() { targetValue.SetUint(uint64(xValue.Int()) / yValue.Uint()) } else if xValue.CanUint() && yValue.CanInt() { targetValue.SetUint(xValue.Uint() / uint64(yValue.Int())) } case token.REM: if xValue.CanInt() && yValue.CanInt() { targetValue.SetInt(xValue.Int() % yValue.Int()) } else if xValue.CanUint() && yValue.CanUint() { targetValue.SetUint(xValue.Uint() % yValue.Uint()) } else if xValue.CanInt() && yValue.CanUint() { targetValue.SetUint(uint64(xValue.Int()) % yValue.Uint()) } else if xValue.CanUint() && yValue.CanInt() { targetValue.SetUint(xValue.Uint() % uint64(yValue.Int())) } case token.AND: if xValue.CanInt() && yValue.CanInt() { targetValue.SetInt(xValue.Int() & yValue.Int()) } else if xValue.CanUint() && yValue.CanUint() { targetValue.SetUint(xValue.Uint() & yValue.Uint()) } else if xValue.CanInt() && yValue.CanUint() { targetValue.SetUint(uint64(xValue.Int()) & yValue.Uint()) } else if xValue.CanUint() && yValue.CanInt() { targetValue.SetUint(xValue.Uint() & uint64(yValue.Int())) } case token.OR: if xValue.CanInt() && yValue.CanInt() { targetValue.SetInt(xValue.Int() | yValue.Int()) } else if xValue.CanUint() && yValue.CanUint() { targetValue.SetUint(xValue.Uint() | yValue.Uint()) } else if xValue.CanInt() && yValue.CanUint() { targetValue.SetUint(uint64(xValue.Int()) | yValue.Uint()) } else if xValue.CanUint() && yValue.CanInt() { targetValue.SetUint(xValue.Uint() | uint64(yValue.Int())) } case token.XOR: if xValue.CanInt() && yValue.CanInt() { targetValue.SetInt(xValue.Int() ^ yValue.Int()) } else if xValue.CanUint() && yValue.CanUint() { targetValue.SetUint(xValue.Uint() ^ yValue.Uint()) } else if xValue.CanInt() && yValue.CanUint() { targetValue.SetUint(uint64(xValue.Int()) ^ yValue.Uint()) } else if xValue.CanUint() && yValue.CanInt() { targetValue.SetUint(xValue.Uint() ^ uint64(yValue.Int())) } } return targetValue.Interface(), evalType }