eval.go 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025
  1. package raymond
  2. import (
  3. "bytes"
  4. "fmt"
  5. "reflect"
  6. "strconv"
  7. "strings"
  8. "github.com/mailgun/raymond/v2/ast"
  9. )
  10. var (
  11. // @note borrowed from https://github.com/golang/go/tree/master/src/text/template/exec.go
  12. errorType = reflect.TypeOf((*error)(nil)).Elem()
  13. fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
  14. zero reflect.Value
  15. )
  16. // evalVisitor evaluates a handlebars template with context
  17. type evalVisitor struct {
  18. tpl *Template
  19. // contexts stack
  20. ctx []reflect.Value
  21. // current data frame (chained with parent)
  22. dataFrame *DataFrame
  23. // block parameters stack
  24. blockParams []map[string]interface{}
  25. // block statements stack
  26. blocks []*ast.BlockStatement
  27. // expressions stack
  28. exprs []*ast.Expression
  29. // memoize expressions that were function calls
  30. exprFunc map[*ast.Expression]bool
  31. // used for info on panic
  32. curNode ast.Node
  33. }
  34. // NewEvalVisitor instanciate a new evaluation visitor with given context and initial private data frame
  35. //
  36. // If privData is nil, then a default data frame is created
  37. func newEvalVisitor(tpl *Template, ctx interface{}, privData *DataFrame) *evalVisitor {
  38. frame := privData
  39. if frame == nil {
  40. frame = NewDataFrame()
  41. }
  42. return &evalVisitor{
  43. tpl: tpl,
  44. ctx: []reflect.Value{reflect.ValueOf(ctx)},
  45. dataFrame: frame,
  46. exprFunc: make(map[*ast.Expression]bool),
  47. }
  48. }
  49. // at sets current node
  50. func (v *evalVisitor) at(node ast.Node) {
  51. v.curNode = node
  52. }
  53. //
  54. // Contexts stack
  55. //
  56. // pushCtx pushes new context to the stack
  57. func (v *evalVisitor) pushCtx(ctx reflect.Value) {
  58. v.ctx = append(v.ctx, ctx)
  59. }
  60. // popCtx pops last context from stack
  61. func (v *evalVisitor) popCtx() reflect.Value {
  62. if len(v.ctx) == 0 {
  63. return zero
  64. }
  65. var result reflect.Value
  66. result, v.ctx = v.ctx[len(v.ctx)-1], v.ctx[:len(v.ctx)-1]
  67. return result
  68. }
  69. // rootCtx returns root context
  70. func (v *evalVisitor) rootCtx() reflect.Value {
  71. return v.ctx[0]
  72. }
  73. // curCtx returns current context
  74. func (v *evalVisitor) curCtx() reflect.Value {
  75. return v.ancestorCtx(0)
  76. }
  77. // ancestorCtx returns ancestor context
  78. func (v *evalVisitor) ancestorCtx(depth int) reflect.Value {
  79. index := len(v.ctx) - 1 - depth
  80. if index < 0 {
  81. return zero
  82. }
  83. return v.ctx[index]
  84. }
  85. //
  86. // Private data frame
  87. //
  88. // setDataFrame sets new data frame
  89. func (v *evalVisitor) setDataFrame(frame *DataFrame) {
  90. v.dataFrame = frame
  91. }
  92. // popDataFrame sets back parent data frame
  93. func (v *evalVisitor) popDataFrame() {
  94. v.dataFrame = v.dataFrame.parent
  95. }
  96. //
  97. // Block Parameters stack
  98. //
  99. // pushBlockParams pushes new block params to the stack
  100. func (v *evalVisitor) pushBlockParams(params map[string]interface{}) {
  101. v.blockParams = append(v.blockParams, params)
  102. }
  103. // popBlockParams pops last block params from stack
  104. func (v *evalVisitor) popBlockParams() map[string]interface{} {
  105. var result map[string]interface{}
  106. if len(v.blockParams) == 0 {
  107. return result
  108. }
  109. result, v.blockParams = v.blockParams[len(v.blockParams)-1], v.blockParams[:len(v.blockParams)-1]
  110. return result
  111. }
  112. // blockParam iterates on stack to find given block parameter, and returns its value or nil if not founc
  113. func (v *evalVisitor) blockParam(name string) interface{} {
  114. for i := len(v.blockParams) - 1; i >= 0; i-- {
  115. for k, v := range v.blockParams[i] {
  116. if name == k {
  117. return v
  118. }
  119. }
  120. }
  121. return nil
  122. }
  123. //
  124. // Blocks stack
  125. //
  126. // pushBlock pushes new block statement to stack
  127. func (v *evalVisitor) pushBlock(block *ast.BlockStatement) {
  128. v.blocks = append(v.blocks, block)
  129. }
  130. // popBlock pops last block statement from stack
  131. func (v *evalVisitor) popBlock() *ast.BlockStatement {
  132. if len(v.blocks) == 0 {
  133. return nil
  134. }
  135. var result *ast.BlockStatement
  136. result, v.blocks = v.blocks[len(v.blocks)-1], v.blocks[:len(v.blocks)-1]
  137. return result
  138. }
  139. // curBlock returns current block statement
  140. func (v *evalVisitor) curBlock() *ast.BlockStatement {
  141. if len(v.blocks) == 0 {
  142. return nil
  143. }
  144. return v.blocks[len(v.blocks)-1]
  145. }
  146. //
  147. // Expressions stack
  148. //
  149. // pushExpr pushes new expression to stack
  150. func (v *evalVisitor) pushExpr(expression *ast.Expression) {
  151. v.exprs = append(v.exprs, expression)
  152. }
  153. // popExpr pops last expression from stack
  154. func (v *evalVisitor) popExpr() *ast.Expression {
  155. if len(v.exprs) == 0 {
  156. return nil
  157. }
  158. var result *ast.Expression
  159. result, v.exprs = v.exprs[len(v.exprs)-1], v.exprs[:len(v.exprs)-1]
  160. return result
  161. }
  162. // curExpr returns current expression
  163. func (v *evalVisitor) curExpr() *ast.Expression {
  164. if len(v.exprs) == 0 {
  165. return nil
  166. }
  167. return v.exprs[len(v.exprs)-1]
  168. }
  169. //
  170. // Error functions
  171. //
  172. // errPanic panics
  173. func (v *evalVisitor) errPanic(err error) {
  174. panic(fmt.Errorf("Evaluation error: %s\nCurrent node:\n\t%s", err, v.curNode))
  175. }
  176. // errorf panics with a custom message
  177. func (v *evalVisitor) errorf(format string, args ...interface{}) {
  178. v.errPanic(fmt.Errorf(format, args...))
  179. }
  180. //
  181. // Evaluation
  182. //
  183. // evalProgram eEvaluates program with given context and returns string result
  184. func (v *evalVisitor) evalProgram(program *ast.Program, ctx interface{}, data *DataFrame, key interface{}) string {
  185. blockParams := make(map[string]interface{})
  186. // compute block params
  187. if len(program.BlockParams) > 0 {
  188. blockParams[program.BlockParams[0]] = ctx
  189. }
  190. if (len(program.BlockParams) > 1) && (key != nil) {
  191. blockParams[program.BlockParams[1]] = key
  192. }
  193. // push contexts
  194. if len(blockParams) > 0 {
  195. v.pushBlockParams(blockParams)
  196. }
  197. ctxVal := reflect.ValueOf(ctx)
  198. if ctxVal.IsValid() {
  199. v.pushCtx(ctxVal)
  200. }
  201. if data != nil {
  202. v.setDataFrame(data)
  203. }
  204. // evaluate program
  205. result, _ := program.Accept(v).(string)
  206. // pop contexts
  207. if data != nil {
  208. v.popDataFrame()
  209. }
  210. if ctxVal.IsValid() {
  211. v.popCtx()
  212. }
  213. if len(blockParams) > 0 {
  214. v.popBlockParams()
  215. }
  216. return result
  217. }
  218. // evalPath evaluates all path parts with given context
  219. func (v *evalVisitor) evalPath(ctx reflect.Value, parts []string, exprRoot bool) (reflect.Value, bool) {
  220. partResolved := false
  221. for i := 0; i < len(parts); i++ {
  222. part := parts[i]
  223. // "[foo bar]"" => "foo bar"
  224. if (len(part) >= 2) && (part[0] == '[') && (part[len(part)-1] == ']') {
  225. part = part[1 : len(part)-1]
  226. }
  227. ctx = v.evalField(ctx, part, exprRoot)
  228. if !ctx.IsValid() {
  229. break
  230. }
  231. // we resolved at least one part of path
  232. partResolved = true
  233. }
  234. return ctx, partResolved
  235. }
  236. // evalField evaluates field with given context
  237. func (v *evalVisitor) evalField(ctx reflect.Value, fieldName string, exprRoot bool) reflect.Value {
  238. result := zero
  239. ctx, _ = indirect(ctx)
  240. if !ctx.IsValid() {
  241. return result
  242. }
  243. // check if this is a method call
  244. result, isMeth := v.evalMethod(ctx, fieldName, exprRoot)
  245. if !isMeth {
  246. switch ctx.Kind() {
  247. case reflect.Struct:
  248. // example: firstName => FirstName
  249. expFieldName := strings.Title(fieldName)
  250. // check if struct have this field and that it is exported
  251. if tField, ok := ctx.Type().FieldByName(expFieldName); ok && (tField.PkgPath == "") {
  252. // struct field
  253. result = ctx.FieldByIndex(tField.Index)
  254. break
  255. }
  256. // attempts to find template variable name as a struct tag
  257. result = v.evalStructTag(ctx, fieldName)
  258. case reflect.Map:
  259. nameVal := reflect.ValueOf(fieldName)
  260. if nameVal.Type().AssignableTo(ctx.Type().Key()) {
  261. // map key
  262. result = ctx.MapIndex(nameVal)
  263. }
  264. case reflect.Array, reflect.Slice:
  265. if i, err := strconv.Atoi(fieldName); (err == nil) && (i < ctx.Len()) {
  266. result = ctx.Index(i)
  267. }
  268. }
  269. }
  270. // Perform an operation to the param if the result is zero and the field name
  271. // matches a param helper. This is to support mutations to user params such as
  272. // 'foo.length'.
  273. var helper paramHelperFunc
  274. if helper = findParamHelper(fieldName); helper != nil && result == zero {
  275. result = helper(ctx)
  276. }
  277. // check if result is a function
  278. result, _ = indirect(result)
  279. if result.Kind() == reflect.Func {
  280. result = v.evalFieldFunc(fieldName, result, exprRoot)
  281. }
  282. return result
  283. }
  284. // evalFieldFunc tries to evaluate given method name, and a boolean to indicate if this was a method call
  285. func (v *evalVisitor) evalMethod(ctx reflect.Value, name string, exprRoot bool) (reflect.Value, bool) {
  286. if ctx.Kind() != reflect.Interface && ctx.CanAddr() {
  287. ctx = ctx.Addr()
  288. }
  289. method := ctx.MethodByName(name)
  290. if !method.IsValid() {
  291. // example: subject() => Subject()
  292. method = ctx.MethodByName(strings.Title(name))
  293. }
  294. if !method.IsValid() {
  295. return zero, false
  296. }
  297. return v.evalFieldFunc(name, method, exprRoot), true
  298. }
  299. // evalFieldFunc evaluates given function
  300. func (v *evalVisitor) evalFieldFunc(name string, funcVal reflect.Value, exprRoot bool) reflect.Value {
  301. ensureValidHelper(name, funcVal)
  302. var options *Options
  303. if exprRoot {
  304. // create function arg with all params/hash
  305. expr := v.curExpr()
  306. options = v.helperOptions(expr)
  307. // ok, that expression was a function call
  308. v.exprFunc[expr] = true
  309. } else {
  310. // we are not at root of expression, so we are a parameter... and we don't like
  311. // infinite loops caused by trying to parse ourself forever
  312. options = newEmptyOptions(v)
  313. }
  314. return v.callFunc(name, funcVal, options)
  315. }
  316. // evalStructTag checks for the existence of a struct tag containing the
  317. // name of the variable in the template. This allows for a template variable to
  318. // be separated from the field in the struct.
  319. func (v *evalVisitor) evalStructTag(ctx reflect.Value, name string) reflect.Value {
  320. val := reflect.ValueOf(ctx.Interface())
  321. for i := 0; i < val.NumField(); i++ {
  322. field := val.Type().Field(i)
  323. tag := field.Tag.Get("handlebars")
  324. if tag == name {
  325. return val.Field(i)
  326. }
  327. }
  328. return zero
  329. }
  330. // findBlockParam returns node's block parameter
  331. func (v *evalVisitor) findBlockParam(node *ast.PathExpression) (string, interface{}) {
  332. if len(node.Parts) > 0 {
  333. name := node.Parts[0]
  334. if value := v.blockParam(name); value != nil {
  335. return name, value
  336. }
  337. }
  338. return "", nil
  339. }
  340. // evalPathExpression evaluates a path expression
  341. func (v *evalVisitor) evalPathExpression(node *ast.PathExpression, exprRoot bool) interface{} {
  342. var result interface{}
  343. if name, value := v.findBlockParam(node); value != nil {
  344. // block parameter value
  345. // We push a new context so we can evaluate the path expression (note: this may be a bad idea).
  346. //
  347. // Example:
  348. // {{#foo as |bar|}}
  349. // {{bar.baz}}
  350. // {{/foo}}
  351. //
  352. // With data:
  353. // {"foo": {"baz": "bat"}}
  354. newCtx := map[string]interface{}{name: value}
  355. v.pushCtx(reflect.ValueOf(newCtx))
  356. result = v.evalCtxPathExpression(node, exprRoot)
  357. v.popCtx()
  358. } else {
  359. ctxTried := false
  360. if node.IsDataRoot() {
  361. // context path
  362. result = v.evalCtxPathExpression(node, exprRoot)
  363. ctxTried = true
  364. }
  365. if (result == nil) && node.Data {
  366. // if it is @root, then we tried to evaluate with root context but nothing was found
  367. // so let's try with private data
  368. // private data
  369. result = v.evalDataPathExpression(node, exprRoot)
  370. }
  371. if (result == nil) && !ctxTried {
  372. // context path
  373. result = v.evalCtxPathExpression(node, exprRoot)
  374. }
  375. }
  376. return result
  377. }
  378. // evalDataPathExpression evaluates a private data path expression
  379. func (v *evalVisitor) evalDataPathExpression(node *ast.PathExpression, exprRoot bool) interface{} {
  380. // find data frame
  381. frame := v.dataFrame
  382. for i := node.Depth; i > 0; i-- {
  383. if frame.parent == nil {
  384. return nil
  385. }
  386. frame = frame.parent
  387. }
  388. // resolve data
  389. // @note Can be changed to v.evalCtx() as context can't be an array
  390. result, _ := v.evalCtxPath(reflect.ValueOf(frame.data), node.Parts, exprRoot)
  391. return result
  392. }
  393. // evalCtxPathExpression evaluates a context path expression
  394. func (v *evalVisitor) evalCtxPathExpression(node *ast.PathExpression, exprRoot bool) interface{} {
  395. v.at(node)
  396. if node.IsDataRoot() {
  397. // `@root` - remove the first part
  398. parts := node.Parts[1:len(node.Parts)]
  399. result, _ := v.evalCtxPath(v.rootCtx(), parts, exprRoot)
  400. return result
  401. }
  402. return v.evalDepthPath(node.Depth, node.Parts, exprRoot)
  403. }
  404. // evalDepthPath iterates on contexts, starting at given depth, until there is one that resolve given path parts
  405. func (v *evalVisitor) evalDepthPath(depth int, parts []string, exprRoot bool) interface{} {
  406. var result interface{}
  407. partResolved := false
  408. ctx := v.ancestorCtx(depth)
  409. for (result == nil) && ctx.IsValid() && (depth <= len(v.ctx) && !partResolved) {
  410. // try with context
  411. result, partResolved = v.evalCtxPath(ctx, parts, exprRoot)
  412. // As soon as we find the first part of a path, we must not try to resolve with parent context if result is finally `nil`
  413. // Reference: "Dotted Names - Context Precedence" mustache test
  414. if !partResolved && (result == nil) {
  415. // try with previous context
  416. depth++
  417. ctx = v.ancestorCtx(depth)
  418. }
  419. }
  420. return result
  421. }
  422. // evalCtxPath evaluates path with given context
  423. func (v *evalVisitor) evalCtxPath(ctx reflect.Value, parts []string, exprRoot bool) (interface{}, bool) {
  424. var result interface{}
  425. partResolved := false
  426. switch ctx.Kind() {
  427. case reflect.Array, reflect.Slice:
  428. // Array context
  429. var results []interface{}
  430. for i := 0; i < ctx.Len(); i++ {
  431. value, _ := v.evalPath(ctx.Index(i), parts, exprRoot)
  432. if value.IsValid() {
  433. results = append(results, value.Interface())
  434. }
  435. }
  436. result = results
  437. default:
  438. // NOT array context
  439. var value reflect.Value
  440. value, partResolved = v.evalPath(ctx, parts, exprRoot)
  441. if value.IsValid() {
  442. result = value.Interface()
  443. }
  444. }
  445. return result, partResolved
  446. }
  447. //
  448. // Helpers
  449. //
  450. // isHelperCall returns true if given expression is a helper call
  451. func (v *evalVisitor) isHelperCall(node *ast.Expression) bool {
  452. if helperName := node.HelperName(); helperName != "" {
  453. return v.findHelper(helperName) != zero
  454. }
  455. return false
  456. }
  457. // findHelper finds given helper
  458. func (v *evalVisitor) findHelper(name string) reflect.Value {
  459. // check template helpers
  460. if h := v.tpl.findHelper(name); h != zero {
  461. return h
  462. }
  463. // check global helpers
  464. return findHelper(name)
  465. }
  466. // callFunc calls function with given options
  467. func (v *evalVisitor) callFunc(name string, funcVal reflect.Value, options *Options) reflect.Value {
  468. params := options.Params()
  469. funcType := funcVal.Type()
  470. // @todo Is there a better way to do that ?
  471. strType := reflect.TypeOf("")
  472. boolType := reflect.TypeOf(true)
  473. // check parameters number
  474. addOptions := false
  475. numIn := funcType.NumIn()
  476. variadic := funcType.IsVariadic()
  477. if numIn == len(params)+1 {
  478. lastArgType := funcType.In(numIn - 1)
  479. if reflect.TypeOf(options).AssignableTo(lastArgType) {
  480. addOptions = true
  481. }
  482. }
  483. if !addOptions && (len(params) != numIn && !variadic) {
  484. v.errorf("Helper '%s' called with wrong number of arguments, needed %d but got %d", name, numIn, len(params))
  485. }
  486. vaCount := len(params) - numIn
  487. if vaCount < 0 {
  488. vaCount = 0
  489. }
  490. // check and collect arguments
  491. args := make([]reflect.Value, numIn+vaCount)
  492. for i, param := range params {
  493. arg := reflect.ValueOf(param)
  494. var argType reflect.Type
  495. if vaCount > 0 && i >= numIn {
  496. argType = funcType.In(numIn - 1)
  497. } else {
  498. argType = funcType.In(i)
  499. }
  500. if !arg.IsValid() {
  501. if canBeNil(argType) {
  502. arg = reflect.Zero(argType)
  503. } else if argType.Kind() == reflect.String {
  504. arg = reflect.ValueOf("")
  505. } else {
  506. // @todo Maybe we can panic on that
  507. return reflect.Zero(strType)
  508. }
  509. }
  510. if !arg.Type().AssignableTo(argType) && !variadic {
  511. if strType.AssignableTo(argType) {
  512. // convert parameter to string
  513. arg = reflect.ValueOf(strValue(arg))
  514. } else if boolType.AssignableTo(argType) {
  515. // convert parameter to bool
  516. val, _ := isTrueValue(arg)
  517. arg = reflect.ValueOf(val)
  518. } else {
  519. v.errorf("Helper %s called with argument %d with type %s but it should be %s", name, i, arg.Type(), argType)
  520. }
  521. }
  522. args[i] = arg
  523. }
  524. if addOptions {
  525. args[numIn+vaCount-1] = reflect.ValueOf(options)
  526. }
  527. result := funcVal.Call(args)
  528. return result[0]
  529. }
  530. // callHelper invoqs helper function for given expression node
  531. func (v *evalVisitor) callHelper(name string, helper reflect.Value, node *ast.Expression) interface{} {
  532. result := v.callFunc(name, helper, v.helperOptions(node))
  533. if !result.IsValid() {
  534. return nil
  535. }
  536. // @todo We maybe want to ensure here that helper returned a string or a SafeString
  537. return result.Interface()
  538. }
  539. // helperOptions computes helper options argument from an expression
  540. func (v *evalVisitor) helperOptions(node *ast.Expression) *Options {
  541. var params []interface{}
  542. var hash map[string]interface{}
  543. for _, paramNode := range node.Params {
  544. param := paramNode.Accept(v)
  545. params = append(params, param)
  546. }
  547. if node.Hash != nil {
  548. hash, _ = node.Hash.Accept(v).(map[string]interface{})
  549. }
  550. return newOptions(v, params, hash)
  551. }
  552. //
  553. // Partials
  554. //
  555. // findPartial finds given partial
  556. func (v *evalVisitor) findPartial(name string) *partial {
  557. // check template partials
  558. if p := v.tpl.findPartial(name); p != nil {
  559. return p
  560. }
  561. // check global partials
  562. return findPartial(name)
  563. }
  564. // partialContext computes partial context
  565. func (v *evalVisitor) partialContext(node *ast.PartialStatement) reflect.Value {
  566. if nb := len(node.Params); nb > 1 {
  567. v.errorf("Unsupported number of partial arguments: %d", nb)
  568. }
  569. if (len(node.Params) > 0) && (node.Hash != nil) {
  570. v.errorf("Passing both context and named parameters to a partial is not allowed")
  571. }
  572. if len(node.Params) == 1 {
  573. return reflect.ValueOf(node.Params[0].Accept(v))
  574. }
  575. if node.Hash != nil {
  576. hash, _ := node.Hash.Accept(v).(map[string]interface{})
  577. return reflect.ValueOf(hash)
  578. }
  579. return zero
  580. }
  581. // evalPartial evaluates a partial
  582. func (v *evalVisitor) evalPartial(p *partial, node *ast.PartialStatement) string {
  583. // get partial template
  584. partialTpl, err := p.template()
  585. if err != nil {
  586. v.errPanic(err)
  587. }
  588. // push partial context
  589. ctx := v.partialContext(node)
  590. if ctx.IsValid() {
  591. v.pushCtx(ctx)
  592. }
  593. // evaluate partial template
  594. result, _ := partialTpl.program.Accept(v).(string)
  595. // ident partial
  596. result = indentLines(result, node.Indent)
  597. if ctx.IsValid() {
  598. v.popCtx()
  599. }
  600. return result
  601. }
  602. // indentLines indents all lines of given string
  603. func indentLines(str string, indent string) string {
  604. if indent == "" {
  605. return str
  606. }
  607. var indented []string
  608. lines := strings.Split(str, "\n")
  609. for i, line := range lines {
  610. if (i == (len(lines) - 1)) && (line == "") {
  611. // input string ends with a new line
  612. indented = append(indented, line)
  613. } else {
  614. indented = append(indented, indent+line)
  615. }
  616. }
  617. return strings.Join(indented, "\n")
  618. }
  619. //
  620. // Functions
  621. //
  622. // wasFuncCall returns true if given expression was a function call
  623. func (v *evalVisitor) wasFuncCall(node *ast.Expression) bool {
  624. // check if expression was tagged as a function call
  625. return v.exprFunc[node]
  626. }
  627. //
  628. // Visitor interface
  629. //
  630. // Statements
  631. // VisitProgram implements corresponding Visitor interface method
  632. func (v *evalVisitor) VisitProgram(node *ast.Program) interface{} {
  633. v.at(node)
  634. buf := new(bytes.Buffer)
  635. for _, n := range node.Body {
  636. if str := Str(n.Accept(v)); str != "" {
  637. if _, err := buf.Write([]byte(str)); err != nil {
  638. v.errPanic(err)
  639. }
  640. }
  641. }
  642. return buf.String()
  643. }
  644. // VisitMustache implements corresponding Visitor interface method
  645. func (v *evalVisitor) VisitMustache(node *ast.MustacheStatement) interface{} {
  646. v.at(node)
  647. // evaluate expression
  648. expr := node.Expression.Accept(v)
  649. // check if this is a safe string
  650. isSafe := isSafeString(expr)
  651. // get string value
  652. str := Str(expr)
  653. if !isSafe && !node.Unescaped {
  654. // escape html
  655. str = Escape(str)
  656. }
  657. return str
  658. }
  659. // VisitBlock implements corresponding Visitor interface method
  660. func (v *evalVisitor) VisitBlock(node *ast.BlockStatement) interface{} {
  661. v.at(node)
  662. v.pushBlock(node)
  663. var result interface{}
  664. // evaluate expression
  665. expr := node.Expression.Accept(v)
  666. if v.isHelperCall(node.Expression) || v.wasFuncCall(node.Expression) {
  667. // it is the responsibility of the helper/function to evaluate block
  668. result = expr
  669. } else {
  670. val := reflect.ValueOf(expr)
  671. truth, _ := isTrueValue(val)
  672. if truth {
  673. if node.Program != nil {
  674. switch val.Kind() {
  675. case reflect.Array, reflect.Slice:
  676. concat := ""
  677. // Array context
  678. for i := 0; i < val.Len(); i++ {
  679. // Computes new private data frame
  680. frame := v.dataFrame.newIterDataFrame(val.Len(), i, nil)
  681. // Evaluate program
  682. concat += v.evalProgram(node.Program, val.Index(i).Interface(), frame, i)
  683. }
  684. result = concat
  685. default:
  686. // NOT array
  687. result = v.evalProgram(node.Program, expr, nil, nil)
  688. }
  689. }
  690. } else if node.Inverse != nil {
  691. result, _ = node.Inverse.Accept(v).(string)
  692. }
  693. }
  694. v.popBlock()
  695. return result
  696. }
  697. // VisitPartial implements corresponding Visitor interface method
  698. func (v *evalVisitor) VisitPartial(node *ast.PartialStatement) interface{} {
  699. v.at(node)
  700. // partialName: helperName | sexpr
  701. name, ok := ast.HelperNameStr(node.Name)
  702. if !ok {
  703. if subExpr, ok := node.Name.(*ast.SubExpression); ok {
  704. name, _ = subExpr.Accept(v).(string)
  705. }
  706. }
  707. if name == "" {
  708. v.errorf("Unexpected partial name: %q", node.Name)
  709. }
  710. partial := v.findPartial(name)
  711. if partial == nil {
  712. v.errorf("Partial not found: %s", name)
  713. }
  714. return v.evalPartial(partial, node)
  715. }
  716. // VisitContent implements corresponding Visitor interface method
  717. func (v *evalVisitor) VisitContent(node *ast.ContentStatement) interface{} {
  718. v.at(node)
  719. // write content as is
  720. return node.Value
  721. }
  722. // VisitComment implements corresponding Visitor interface method
  723. func (v *evalVisitor) VisitComment(node *ast.CommentStatement) interface{} {
  724. v.at(node)
  725. // ignore comments
  726. return ""
  727. }
  728. // Expressions
  729. // VisitExpression implements corresponding Visitor interface method
  730. func (v *evalVisitor) VisitExpression(node *ast.Expression) interface{} {
  731. v.at(node)
  732. var result interface{}
  733. done := false
  734. v.pushExpr(node)
  735. // helper call
  736. if helperName := node.HelperName(); helperName != "" {
  737. if helper := v.findHelper(helperName); helper != zero {
  738. result = v.callHelper(helperName, helper, node)
  739. done = true
  740. }
  741. }
  742. if !done {
  743. // literal
  744. if literal, ok := node.LiteralStr(); ok {
  745. if val := v.evalField(v.curCtx(), literal, true); val.IsValid() {
  746. result = val.Interface()
  747. done = true
  748. }
  749. }
  750. }
  751. if !done {
  752. // field path
  753. if path := node.FieldPath(); path != nil {
  754. // @todo Find a cleaner way ! Don't break the pattern !
  755. // this is an exception to visitor pattern, because we need to pass the info
  756. // that this path is at root of current expression
  757. if val := v.evalPathExpression(path, true); val != nil {
  758. result = val
  759. }
  760. }
  761. }
  762. v.popExpr()
  763. return result
  764. }
  765. // VisitSubExpression implements corresponding Visitor interface method
  766. func (v *evalVisitor) VisitSubExpression(node *ast.SubExpression) interface{} {
  767. v.at(node)
  768. return node.Expression.Accept(v)
  769. }
  770. // VisitPath implements corresponding Visitor interface method
  771. func (v *evalVisitor) VisitPath(node *ast.PathExpression) interface{} {
  772. return v.evalPathExpression(node, false)
  773. }
  774. // Literals
  775. // VisitString implements corresponding Visitor interface method
  776. func (v *evalVisitor) VisitString(node *ast.StringLiteral) interface{} {
  777. v.at(node)
  778. return node.Value
  779. }
  780. // VisitBoolean implements corresponding Visitor interface method
  781. func (v *evalVisitor) VisitBoolean(node *ast.BooleanLiteral) interface{} {
  782. v.at(node)
  783. return node.Value
  784. }
  785. // VisitNumber implements corresponding Visitor interface method
  786. func (v *evalVisitor) VisitNumber(node *ast.NumberLiteral) interface{} {
  787. v.at(node)
  788. return node.Number()
  789. }
  790. // Miscellaneous
  791. // VisitHash implements corresponding Visitor interface method
  792. func (v *evalVisitor) VisitHash(node *ast.Hash) interface{} {
  793. v.at(node)
  794. result := make(map[string]interface{})
  795. for _, pair := range node.Pairs {
  796. if value := pair.Accept(v); value != nil {
  797. result[pair.Key] = value
  798. }
  799. }
  800. return result
  801. }
  802. // VisitHashPair implements corresponding Visitor interface method
  803. func (v *evalVisitor) VisitHashPair(node *ast.HashPair) interface{} {
  804. v.at(node)
  805. return node.Val.Accept(v)
  806. }