github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/flosch/pongo2.v3/variable.go (about)

     1  package pongo2
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"reflect"
     7  	"strconv"
     8  	"strings"
     9  )
    10  
    11  const (
    12  	varTypeInt = iota
    13  	varTypeIdent
    14  )
    15  
    16  type variablePart struct {
    17  	typ int
    18  	s   string
    19  	i   int
    20  
    21  	is_function_call bool
    22  	calling_args     []functionCallArgument // needed for a function call, represents all argument nodes (INode supports nested function calls)
    23  }
    24  
    25  type functionCallArgument interface {
    26  	Evaluate(*ExecutionContext) (*Value, *Error)
    27  }
    28  
    29  // TODO: Add location tokens
    30  type stringResolver struct {
    31  	location_token *Token
    32  	val            string
    33  }
    34  
    35  type intResolver struct {
    36  	location_token *Token
    37  	val            int
    38  }
    39  
    40  type floatResolver struct {
    41  	location_token *Token
    42  	val            float64
    43  }
    44  
    45  type boolResolver struct {
    46  	location_token *Token
    47  	val            bool
    48  }
    49  
    50  type variableResolver struct {
    51  	location_token *Token
    52  
    53  	parts []*variablePart
    54  }
    55  
    56  type nodeFilteredVariable struct {
    57  	location_token *Token
    58  
    59  	resolver    IEvaluator
    60  	filterChain []*filterCall
    61  }
    62  
    63  type nodeVariable struct {
    64  	location_token *Token
    65  	expr           IEvaluator
    66  }
    67  
    68  func (expr *nodeFilteredVariable) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
    69  	value, err := expr.Evaluate(ctx)
    70  	if err != nil {
    71  		return err
    72  	}
    73  	buffer.WriteString(value.String())
    74  	return nil
    75  }
    76  
    77  func (expr *variableResolver) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
    78  	value, err := expr.Evaluate(ctx)
    79  	if err != nil {
    80  		return err
    81  	}
    82  	buffer.WriteString(value.String())
    83  	return nil
    84  }
    85  
    86  func (expr *stringResolver) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
    87  	value, err := expr.Evaluate(ctx)
    88  	if err != nil {
    89  		return err
    90  	}
    91  	buffer.WriteString(value.String())
    92  	return nil
    93  }
    94  
    95  func (expr *intResolver) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
    96  	value, err := expr.Evaluate(ctx)
    97  	if err != nil {
    98  		return err
    99  	}
   100  	buffer.WriteString(value.String())
   101  	return nil
   102  }
   103  
   104  func (expr *floatResolver) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
   105  	value, err := expr.Evaluate(ctx)
   106  	if err != nil {
   107  		return err
   108  	}
   109  	buffer.WriteString(value.String())
   110  	return nil
   111  }
   112  
   113  func (expr *boolResolver) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
   114  	value, err := expr.Evaluate(ctx)
   115  	if err != nil {
   116  		return err
   117  	}
   118  	buffer.WriteString(value.String())
   119  	return nil
   120  }
   121  
   122  func (v *nodeFilteredVariable) GetPositionToken() *Token {
   123  	return v.location_token
   124  }
   125  
   126  func (v *variableResolver) GetPositionToken() *Token {
   127  	return v.location_token
   128  }
   129  
   130  func (v *stringResolver) GetPositionToken() *Token {
   131  	return v.location_token
   132  }
   133  
   134  func (v *intResolver) GetPositionToken() *Token {
   135  	return v.location_token
   136  }
   137  
   138  func (v *floatResolver) GetPositionToken() *Token {
   139  	return v.location_token
   140  }
   141  
   142  func (v *boolResolver) GetPositionToken() *Token {
   143  	return v.location_token
   144  }
   145  
   146  func (s *stringResolver) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
   147  	return AsValue(s.val), nil
   148  }
   149  
   150  func (i *intResolver) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
   151  	return AsValue(i.val), nil
   152  }
   153  
   154  func (f *floatResolver) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
   155  	return AsValue(f.val), nil
   156  }
   157  
   158  func (b *boolResolver) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
   159  	return AsValue(b.val), nil
   160  }
   161  
   162  func (s *stringResolver) FilterApplied(name string) bool {
   163  	return false
   164  }
   165  
   166  func (i *intResolver) FilterApplied(name string) bool {
   167  	return false
   168  }
   169  
   170  func (f *floatResolver) FilterApplied(name string) bool {
   171  	return false
   172  }
   173  
   174  func (b *boolResolver) FilterApplied(name string) bool {
   175  	return false
   176  }
   177  
   178  func (nv *nodeVariable) FilterApplied(name string) bool {
   179  	return nv.expr.FilterApplied(name)
   180  }
   181  
   182  func (nv *nodeVariable) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
   183  	value, err := nv.expr.Evaluate(ctx)
   184  	if err != nil {
   185  		return err
   186  	}
   187  
   188  	if !nv.expr.FilterApplied("safe") && !value.safe && value.IsString() && ctx.Autoescape {
   189  		// apply escape filter
   190  		value, err = filters["escape"](value, nil)
   191  		if err != nil {
   192  			return err
   193  		}
   194  	}
   195  
   196  	buffer.WriteString(value.String())
   197  	return nil
   198  }
   199  
   200  func (vr *variableResolver) FilterApplied(name string) bool {
   201  	return false
   202  }
   203  
   204  func (vr *variableResolver) String() string {
   205  	parts := make([]string, 0, len(vr.parts))
   206  	for _, p := range vr.parts {
   207  		switch p.typ {
   208  		case varTypeInt:
   209  			parts = append(parts, strconv.Itoa(p.i))
   210  		case varTypeIdent:
   211  			parts = append(parts, p.s)
   212  		default:
   213  			panic("unimplemented")
   214  		}
   215  	}
   216  	return strings.Join(parts, ".")
   217  }
   218  
   219  func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
   220  	var current reflect.Value
   221  	var is_safe bool
   222  
   223  	for idx, part := range vr.parts {
   224  		if idx == 0 {
   225  			// We're looking up the first part of the variable.
   226  			// First we're having a look in our private
   227  			// context (e. g. information provided by tags, like the forloop)
   228  			val, in_private := ctx.Private[vr.parts[0].s]
   229  			if !in_private {
   230  				// Nothing found? Then have a final lookup in the public context
   231  				val = ctx.Public[vr.parts[0].s]
   232  			}
   233  			current = reflect.ValueOf(val) // Get the initial value
   234  		} else {
   235  			// Next parts, resolve it from current
   236  
   237  			// Before resolving the pointer, let's see if we have a method to call
   238  			// Problem with resolving the pointer is we're changing the receiver
   239  			is_func := false
   240  			if part.typ == varTypeIdent {
   241  				func_value := current.MethodByName(part.s)
   242  				if func_value.IsValid() {
   243  					current = func_value
   244  					is_func = true
   245  				}
   246  			}
   247  
   248  			if !is_func {
   249  				// If current a pointer, resolve it
   250  				if current.Kind() == reflect.Ptr {
   251  					current = current.Elem()
   252  					if !current.IsValid() {
   253  						// Value is not valid (anymore)
   254  						return AsValue(nil), nil
   255  					}
   256  				}
   257  
   258  				// Look up which part must be called now
   259  				switch part.typ {
   260  				case varTypeInt:
   261  					// Calling an index is only possible for:
   262  					// * slices/arrays/strings
   263  					switch current.Kind() {
   264  					case reflect.String, reflect.Array, reflect.Slice:
   265  						current = current.Index(part.i)
   266  					default:
   267  						return nil, fmt.Errorf("Can't access an index on type %s (variable %s)",
   268  							current.Kind().String(), vr.String())
   269  					}
   270  				case varTypeIdent:
   271  					// debugging:
   272  					// fmt.Printf("now = %s (kind: %s)\n", part.s, current.Kind().String())
   273  
   274  					// Calling a field or key
   275  					switch current.Kind() {
   276  					case reflect.Struct:
   277  						current = current.FieldByName(part.s)
   278  					case reflect.Map:
   279  						current = current.MapIndex(reflect.ValueOf(part.s))
   280  					default:
   281  						return nil, fmt.Errorf("Can't access a field by name on type %s (variable %s)",
   282  							current.Kind().String(), vr.String())
   283  					}
   284  				default:
   285  					panic("unimplemented")
   286  				}
   287  			}
   288  		}
   289  
   290  		if !current.IsValid() {
   291  			// Value is not valid (anymore)
   292  			return AsValue(nil), nil
   293  		}
   294  
   295  		// If current is a reflect.ValueOf(pongo2.Value), then unpack it
   296  		// Happens in function calls (as a return value) or by injecting
   297  		// into the execution context (e.g. in a for-loop)
   298  		if current.Type() == reflect.TypeOf(&Value{}) {
   299  			tmp_value := current.Interface().(*Value)
   300  			current = tmp_value.val
   301  			is_safe = tmp_value.safe
   302  		}
   303  
   304  		// Check whether this is an interface and resolve it where required
   305  		if current.Kind() == reflect.Interface {
   306  			current = reflect.ValueOf(current.Interface())
   307  		}
   308  
   309  		// Check if the part is a function call
   310  		if part.is_function_call || current.Kind() == reflect.Func {
   311  			// Check for callable
   312  			if current.Kind() != reflect.Func {
   313  				return nil, fmt.Errorf("'%s' is not a function (it is %s).", vr.String(), current.Kind().String())
   314  			}
   315  
   316  			// Check for correct function syntax and types
   317  			// func(*Value, ...) *Value
   318  			t := current.Type()
   319  
   320  			// Input arguments
   321  			if len(part.calling_args) != t.NumIn() && !(len(part.calling_args) >= t.NumIn()-1 && t.IsVariadic()) {
   322  				return nil,
   323  					fmt.Errorf("Function input argument count (%d) of '%s' must be equal to the calling argument count (%d).",
   324  						t.NumIn(), vr.String(), len(part.calling_args))
   325  			}
   326  
   327  			// Output arguments
   328  			if t.NumOut() != 1 {
   329  				return nil, fmt.Errorf("'%s' must have exactly 1 output argument.", vr.String())
   330  			}
   331  
   332  			// Evaluate all parameters
   333  			parameters := make([]reflect.Value, 0)
   334  
   335  			num_args := t.NumIn()
   336  			is_variadic := t.IsVariadic()
   337  			var fn_arg reflect.Type
   338  
   339  			for idx, arg := range part.calling_args {
   340  				pv, err := arg.Evaluate(ctx)
   341  				if err != nil {
   342  					return nil, err
   343  				}
   344  
   345  				if is_variadic {
   346  					if idx >= t.NumIn()-1 {
   347  						fn_arg = t.In(num_args - 1).Elem()
   348  					} else {
   349  						fn_arg = t.In(idx)
   350  					}
   351  				} else {
   352  					fn_arg = t.In(idx)
   353  				}
   354  
   355  				if fn_arg != reflect.TypeOf(new(Value)) {
   356  					// Function's argument is not a *pongo2.Value, then we have to check whether input argument is of the same type as the function's argument
   357  					if !is_variadic {
   358  						if fn_arg != reflect.TypeOf(pv.Interface()) && fn_arg.Kind() != reflect.Interface {
   359  							return nil, fmt.Errorf("Function input argument %d of '%s' must be of type %s or *pongo2.Value (not %T).",
   360  								idx, vr.String(), fn_arg.String(), pv.Interface())
   361  						} else {
   362  							// Function's argument has another type, using the interface-value
   363  							parameters = append(parameters, reflect.ValueOf(pv.Interface()))
   364  						}
   365  					} else {
   366  						if fn_arg != reflect.TypeOf(pv.Interface()) && fn_arg.Kind() != reflect.Interface {
   367  							return nil, fmt.Errorf("Function variadic input argument of '%s' must be of type %s or *pongo2.Value (not %T).",
   368  								vr.String(), fn_arg.String(), pv.Interface())
   369  						} else {
   370  							// Function's argument has another type, using the interface-value
   371  							parameters = append(parameters, reflect.ValueOf(pv.Interface()))
   372  						}
   373  					}
   374  				} else {
   375  					// Function's argument is a *pongo2.Value
   376  					parameters = append(parameters, reflect.ValueOf(pv))
   377  				}
   378  			}
   379  
   380  			// Call it and get first return parameter back
   381  			rv := current.Call(parameters)[0]
   382  
   383  			if rv.Type() != reflect.TypeOf(new(Value)) {
   384  				current = reflect.ValueOf(rv.Interface())
   385  			} else {
   386  				// Return the function call value
   387  				current = rv.Interface().(*Value).val
   388  				is_safe = rv.Interface().(*Value).safe
   389  			}
   390  		}
   391  	}
   392  
   393  	if !current.IsValid() {
   394  		// Value is not valid (e. g. NIL value)
   395  		return AsValue(nil), nil
   396  	}
   397  
   398  	return &Value{val: current, safe: is_safe}, nil
   399  }
   400  
   401  func (vr *variableResolver) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
   402  	value, err := vr.resolve(ctx)
   403  	if err != nil {
   404  		return AsValue(nil), ctx.Error(err.Error(), vr.location_token)
   405  	}
   406  	return value, nil
   407  }
   408  
   409  func (v *nodeFilteredVariable) FilterApplied(name string) bool {
   410  	for _, filter := range v.filterChain {
   411  		if filter.name == name {
   412  			return true
   413  		}
   414  	}
   415  	return false
   416  }
   417  
   418  func (v *nodeFilteredVariable) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
   419  	value, err := v.resolver.Evaluate(ctx)
   420  	if err != nil {
   421  		return nil, err
   422  	}
   423  
   424  	for _, filter := range v.filterChain {
   425  		value, err = filter.Execute(value, ctx)
   426  		if err != nil {
   427  			return nil, err
   428  		}
   429  	}
   430  
   431  	return value, nil
   432  }
   433  
   434  // IDENT | IDENT.(IDENT|NUMBER)...
   435  func (p *Parser) parseVariableOrLiteral() (IEvaluator, *Error) {
   436  	t := p.Current()
   437  
   438  	if t == nil {
   439  		return nil, p.Error("Unexpected EOF, expected a number, string, keyword or identifier.", p.last_token)
   440  	}
   441  
   442  	// Is first part a number or a string, there's nothing to resolve (because there's only to return the value then)
   443  	switch t.Typ {
   444  	case TokenNumber:
   445  		p.Consume()
   446  
   447  		// One exception to the rule that we don't have float64 literals is at the beginning
   448  		// of an expression (or a variable name). Since we know we started with an integer
   449  		// which can't obviously be a variable name, we can check whether the first number
   450  		// is followed by dot (and then a number again). If so we're converting it to a float64.
   451  
   452  		if p.Match(TokenSymbol, ".") != nil {
   453  			// float64
   454  			t2 := p.MatchType(TokenNumber)
   455  			if t2 == nil {
   456  				return nil, p.Error("Expected a number after the '.'.", nil)
   457  			}
   458  			f, err := strconv.ParseFloat(fmt.Sprintf("%s.%s", t.Val, t2.Val), 64)
   459  			if err != nil {
   460  				return nil, p.Error(err.Error(), t)
   461  			}
   462  			fr := &floatResolver{
   463  				location_token: t,
   464  				val:            f,
   465  			}
   466  			return fr, nil
   467  		} else {
   468  			i, err := strconv.Atoi(t.Val)
   469  			if err != nil {
   470  				return nil, p.Error(err.Error(), t)
   471  			}
   472  			nr := &intResolver{
   473  				location_token: t,
   474  				val:            i,
   475  			}
   476  			return nr, nil
   477  		}
   478  	case TokenString:
   479  		p.Consume()
   480  		sr := &stringResolver{
   481  			location_token: t,
   482  			val:            t.Val,
   483  		}
   484  		return sr, nil
   485  	case TokenKeyword:
   486  		p.Consume()
   487  		switch t.Val {
   488  		case "true":
   489  			br := &boolResolver{
   490  				location_token: t,
   491  				val:            true,
   492  			}
   493  			return br, nil
   494  		case "false":
   495  			br := &boolResolver{
   496  				location_token: t,
   497  				val:            false,
   498  			}
   499  			return br, nil
   500  		default:
   501  			return nil, p.Error("This keyword is not allowed here.", nil)
   502  		}
   503  	}
   504  
   505  	resolver := &variableResolver{
   506  		location_token: t,
   507  	}
   508  
   509  	// First part of a variable MUST be an identifier
   510  	if t.Typ != TokenIdentifier {
   511  		return nil, p.Error("Expected either a number, string, keyword or identifier.", t)
   512  	}
   513  
   514  	resolver.parts = append(resolver.parts, &variablePart{
   515  		typ: varTypeIdent,
   516  		s:   t.Val,
   517  	})
   518  
   519  	p.Consume() // we consumed the first identifier of the variable name
   520  
   521  variableLoop:
   522  	for p.Remaining() > 0 {
   523  		t = p.Current()
   524  
   525  		if p.Match(TokenSymbol, ".") != nil {
   526  			// Next variable part (can be either NUMBER or IDENT)
   527  			t2 := p.Current()
   528  			if t2 != nil {
   529  				switch t2.Typ {
   530  				case TokenIdentifier:
   531  					resolver.parts = append(resolver.parts, &variablePart{
   532  						typ: varTypeIdent,
   533  						s:   t2.Val,
   534  					})
   535  					p.Consume() // consume: IDENT
   536  					continue variableLoop
   537  				case TokenNumber:
   538  					i, err := strconv.Atoi(t2.Val)
   539  					if err != nil {
   540  						return nil, p.Error(err.Error(), t2)
   541  					}
   542  					resolver.parts = append(resolver.parts, &variablePart{
   543  						typ: varTypeInt,
   544  						i:   i,
   545  					})
   546  					p.Consume() // consume: NUMBER
   547  					continue variableLoop
   548  				default:
   549  					return nil, p.Error("This token is not allowed within a variable name.", t2)
   550  				}
   551  			} else {
   552  				// EOF
   553  				return nil, p.Error("Unexpected EOF, expected either IDENTIFIER or NUMBER after DOT.",
   554  					p.last_token)
   555  			}
   556  		} else if p.Match(TokenSymbol, "(") != nil {
   557  			// Function call
   558  			// FunctionName '(' Comma-separated list of expressions ')'
   559  			part := resolver.parts[len(resolver.parts)-1]
   560  			part.is_function_call = true
   561  		argumentLoop:
   562  			for {
   563  				if p.Remaining() == 0 {
   564  					return nil, p.Error("Unexpected EOF, expected function call argument list.", p.last_token)
   565  				}
   566  
   567  				if p.Peek(TokenSymbol, ")") == nil {
   568  					// No closing bracket, so we're parsing an expression
   569  					expr_arg, err := p.ParseExpression()
   570  					if err != nil {
   571  						return nil, err
   572  					}
   573  					part.calling_args = append(part.calling_args, expr_arg)
   574  
   575  					if p.Match(TokenSymbol, ")") != nil {
   576  						// If there's a closing bracket after an expression, we will stop parsing the arguments
   577  						break argumentLoop
   578  					} else {
   579  						// If there's NO closing bracket, there MUST be an comma
   580  						if p.Match(TokenSymbol, ",") == nil {
   581  							return nil, p.Error("Missing comma or closing bracket after argument.", nil)
   582  						}
   583  					}
   584  				} else {
   585  					// We got a closing bracket, so stop parsing arguments
   586  					p.Consume()
   587  					break argumentLoop
   588  				}
   589  
   590  			}
   591  			// We're done parsing the function call, next variable part
   592  			continue variableLoop
   593  		}
   594  
   595  		// No dot or function call? Then we're done with the variable parsing
   596  		break
   597  	}
   598  
   599  	return resolver, nil
   600  }
   601  
   602  func (p *Parser) parseVariableOrLiteralWithFilter() (*nodeFilteredVariable, *Error) {
   603  	v := &nodeFilteredVariable{
   604  		location_token: p.Current(),
   605  	}
   606  
   607  	// Parse the variable name
   608  	resolver, err := p.parseVariableOrLiteral()
   609  	if err != nil {
   610  		return nil, err
   611  	}
   612  	v.resolver = resolver
   613  
   614  	// Parse all the filters
   615  filterLoop:
   616  	for p.Match(TokenSymbol, "|") != nil {
   617  		// Parse one single filter
   618  		filter, err := p.parseFilter()
   619  		if err != nil {
   620  			return nil, err
   621  		}
   622  
   623  		// Check sandbox filter restriction
   624  		if _, is_banned := p.template.set.bannedFilters[filter.name]; is_banned {
   625  			return nil, p.Error(fmt.Sprintf("Usage of filter '%s' is not allowed (sandbox restriction active).", filter.name), nil)
   626  		}
   627  
   628  		v.filterChain = append(v.filterChain, filter)
   629  
   630  		continue filterLoop
   631  
   632  		return nil, p.Error("This token is not allowed within a variable.", nil)
   633  	}
   634  
   635  	return v, nil
   636  }
   637  
   638  func (p *Parser) parseVariableElement() (INode, *Error) {
   639  	node := &nodeVariable{
   640  		location_token: p.Current(),
   641  	}
   642  
   643  	p.Consume() // consume '{{'
   644  
   645  	expr, err := p.ParseExpression()
   646  	if err != nil {
   647  		return nil, err
   648  	}
   649  	node.expr = expr
   650  
   651  	if p.Match(TokenSymbol, "}}") == nil {
   652  		return nil, p.Error("'}}' expected", nil)
   653  	}
   654  
   655  	return node, nil
   656  }