github.com/coveo/gotemplate@v2.7.7+incompatible/template/razor_expr.go (about) 1 package template 2 3 import ( 4 "fmt" 5 "go/ast" 6 "go/token" 7 "reflect" 8 "strings" 9 "unicode" 10 11 "github.com/coveo/gotemplate/collections" 12 "github.com/fatih/color" 13 ) 14 15 func nodeValue(node ast.Node) (result string, err error) { 16 switch n := node.(type) { 17 case *ast.UnaryExpr: 18 var op, x string 19 if op, err = opName(n.Op); err != nil { 20 return 21 } 22 if x, err = nodeValueInternal(n.X); err != nil { 23 return 24 } 25 if op == "sub" { 26 result = iif(unicode.IsDigit(rune(x[0])), "-"+x, fmt.Sprintf("sub 0 %s", x)).(string) 27 break 28 } 29 result = fmt.Sprintf("%s %s", op, x) 30 case *ast.BinaryExpr: 31 var op, x, y string 32 if op, err = opName(n.Op); err != nil { 33 return 34 } 35 if x, err = nodeValueInternal(n.X); err != nil { 36 return 37 } 38 if y, err = nodeValueInternal(n.Y); err != nil { 39 return 40 } 41 if op == "mul" && strings.Contains(y, "*") { 42 // This is a special case where the expression contains 2 following *, meaning power instead of mul 43 result = fmt.Sprintf("power %s %s", x, strings.Replace(y, "*", "", -1)) 44 return 45 } 46 result = fmt.Sprintf("%s %s %s", op, x, y) 47 case *ast.Ident: 48 result = n.Name 49 if !strings.HasPrefix(result, dotRep) && !strings.HasPrefix(result, stringRep) && !strings.Contains(result, funcCall) { 50 result = globalRep + result 51 } 52 case *ast.BasicLit: 53 result = fmt.Sprint(n.Value) 54 case *ast.SelectorExpr: 55 var x, sel string 56 if x, err = nodeValueInternal(n.X); err != nil { 57 return 58 } 59 if sel, err = nodeValueInternal(n.Sel); err != nil { 60 return 61 } 62 result = fmt.Sprintf("%s.%s", x, strings.TrimPrefix(sel, globalRep)) 63 case *ast.ParenExpr: 64 var content string 65 if content, err = nodeValue(n.X); err == nil { 66 result = content 67 } 68 case *ast.CallExpr: 69 var fun string 70 if fun, err = nodeValue(n.Fun); err != nil { 71 return 72 } 73 if !strings.ContainsRune(fun, '.') { 74 fun = strings.TrimPrefix(fun, globalRep) 75 } 76 fun = fun + funcCall 77 if len(n.Args) == 0 { 78 result = fmt.Sprint(fun) 79 } else { 80 args := make([]string, len(n.Args)) 81 for i := range n.Args { 82 s, err := nodeValueInternal(n.Args[i]) 83 if err != nil { 84 return "", err 85 } 86 args[i] = s 87 } 88 result = fmt.Sprintf("%s %s", fun, strings.Join(args, " ")) 89 90 if n.Ellipsis != token.NoPos { 91 result = fmt.Sprintf("ellipsis %q %s", fun, strings.Join(args, " ")) 92 } 93 } 94 case *ast.StarExpr: 95 var x string 96 if x, err = nodeValueInternal(n.X); err != nil { 97 return 98 } 99 // This is a special case where the expression contains 2 following *, meaning power instead of mul 100 result = fmt.Sprintf("*%s", x) 101 102 case *ast.IndexExpr: 103 var x, index string 104 if x, err = nodeValueInternal(n.X); err != nil { 105 return 106 } 107 if index, err = nodeValueInternal(n.Index); err != nil { 108 return 109 } 110 result = fmt.Sprintf("slice %s %s", x, index) 111 112 case *ast.SliceExpr: 113 var x, low, high string 114 if x, err = nodeValueInternal(n.X); err != nil { 115 return 116 } 117 if low, err = nodeValueInternal(n.Low); err != nil { 118 return 119 } 120 if high, err = nodeValueInternal(n.High); err != nil { 121 return 122 } 123 result = fmt.Sprintf("slice %s %s %s", x, low, high) 124 125 default: 126 err = fmt.Errorf("Unknown: %v", reflect.TypeOf(node)) 127 } 128 if !debugMode && getLogLevelInternal() >= 6 { 129 log.Debugf(color.HiBlueString("%T => %s"), node, result) 130 } 131 return 132 } 133 134 var ops = map[string]string{ 135 "==": "eq", 136 "!=": "ne", 137 "<": "lt", 138 "<=": "le", 139 ">": "gt", 140 ">=": "ge", 141 "+": "add", 142 "-": "sub", 143 "/": "div", 144 "*": "mul", 145 "%": "mod", 146 "||": "or", 147 "&&": "and", 148 "!": "not", 149 "<<": "lshift", 150 ">>": "rshift", 151 "|": "bor", 152 "&": "band", 153 "^": "bxor", 154 "&^": "bclear", 155 } 156 157 func opName(token token.Token) (string, error) { 158 if name, ok := ops[token.String()]; ok { 159 return name, nil 160 } 161 return "", fmt.Errorf("Unknown operator %v", token) 162 } 163 164 func nodeValueInternal(node ast.Node) (result string, err error) { 165 result, err = nodeValue(node) 166 167 if strings.HasPrefix(result, `"`) || !strings.ContainsAny(result, " \t") { 168 return 169 } 170 171 // if first, _ := collections.Split2(result, " "); !strings.HasPrefix(first, dotRep) || strings.Contains(first, funcCall) { 172 if first, _ := collections.Split2(result, " "); !(strings.HasPrefix(first, dotRep) && strings.Contains(first, funcCall)) { 173 result = fmt.Sprintf("(%s)", result) 174 } 175 return 176 }