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  }