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 }