constructors.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. // Copyright 2016 José Santos <henrique_1609@me.com>
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package jet
  15. import (
  16. "fmt"
  17. "strconv"
  18. "strings"
  19. )
  20. func (t *Template) newSliceExpr(pos Pos, line int, base, index, endIndex Expression) *SliceExprNode {
  21. return &SliceExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeSliceExpr, Pos: pos, Line: line}, Index: index, Base: base, EndIndex: endIndex}
  22. }
  23. func (t *Template) newIndexExpr(pos Pos, line int, base, index Expression) *IndexExprNode {
  24. return &IndexExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeIndexExpr, Pos: pos, Line: line}, Index: index, Base: base}
  25. }
  26. func (t *Template) newTernaryExpr(pos Pos, line int, boolean, left, right Expression) *TernaryExprNode {
  27. return &TernaryExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeTernaryExpr, Pos: pos, Line: line}, Boolean: boolean, Left: left, Right: right}
  28. }
  29. func (t *Template) newSet(pos Pos, line int, isLet, isIndexExprGetLookup bool, left, right []Expression) *SetNode {
  30. return &SetNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeSet, Pos: pos, Line: line}, Let: isLet, IndexExprGetLookup: isIndexExprGetLookup, Left: left, Right: right}
  31. }
  32. func (t *Template) newCallExpr(pos Pos, line int, expr Expression) *CallExprNode {
  33. return &CallExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeCallExpr, Pos: pos, Line: line}, BaseExpr: expr}
  34. }
  35. func (t *Template) newNotExpr(pos Pos, line int, expr Expression) *NotExprNode {
  36. return &NotExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeNotExpr, Pos: pos, Line: line}, Expr: expr}
  37. }
  38. func (t *Template) newNumericComparativeExpr(pos Pos, line int, left, right Expression, item item) *NumericComparativeExprNode {
  39. return &NumericComparativeExprNode{binaryExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeNumericComparativeExpr, Pos: pos, Line: line}, Operator: item, Left: left, Right: right}}
  40. }
  41. func (t *Template) newComparativeExpr(pos Pos, line int, left, right Expression, item item) *ComparativeExprNode {
  42. return &ComparativeExprNode{binaryExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeComparativeExpr, Pos: pos, Line: line}, Operator: item, Left: left, Right: right}}
  43. }
  44. func (t *Template) newLogicalExpr(pos Pos, line int, left, right Expression, item item) *LogicalExprNode {
  45. return &LogicalExprNode{binaryExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeLogicalExpr, Pos: pos, Line: line}, Operator: item, Left: left, Right: right}}
  46. }
  47. func (t *Template) newMultiplicativeExpr(pos Pos, line int, left, right Expression, item item) *MultiplicativeExprNode {
  48. return &MultiplicativeExprNode{binaryExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeMultiplicativeExpr, Pos: pos, Line: line}, Operator: item, Left: left, Right: right}}
  49. }
  50. func (t *Template) newAdditiveExpr(pos Pos, line int, left, right Expression, item item) *AdditiveExprNode {
  51. return &AdditiveExprNode{binaryExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeAdditiveExpr, Pos: pos, Line: line}, Operator: item, Left: left, Right: right}}
  52. }
  53. func (t *Template) newList(pos Pos) *ListNode {
  54. return &ListNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeList, Pos: pos}}
  55. }
  56. func (t *Template) newText(pos Pos, text string) *TextNode {
  57. return &TextNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeText, Pos: pos}, Text: []byte(text)}
  58. }
  59. func (t *Template) newPipeline(pos Pos, line int) *PipeNode {
  60. return &PipeNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodePipe, Pos: pos, Line: line}}
  61. }
  62. func (t *Template) newAction(pos Pos, line int) *ActionNode {
  63. return &ActionNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeAction, Pos: pos, Line: line}}
  64. }
  65. func (t *Template) newCommand(pos Pos) *CommandNode {
  66. return &CommandNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeCommand, Pos: pos}}
  67. }
  68. func (t *Template) newNil(pos Pos) *NilNode {
  69. return &NilNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeNil, Pos: pos}}
  70. }
  71. func (t *Template) newField(pos Pos, ident string) *FieldNode {
  72. return &FieldNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeField, Pos: pos}, Ident: strings.Split(ident[1:], ".")} //[1:] to drop leading period
  73. }
  74. func (t *Template) newChain(pos Pos, node Node) *ChainNode {
  75. return &ChainNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeChain, Pos: pos}, Node: node}
  76. }
  77. func (t *Template) newBool(pos Pos, true bool) *BoolNode {
  78. return &BoolNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeBool, Pos: pos}, True: true}
  79. }
  80. func (t *Template) newString(pos Pos, orig, text string) *StringNode {
  81. return &StringNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeString, Pos: pos}, Quoted: orig, Text: text}
  82. }
  83. func (t *Template) newEnd(pos Pos) *endNode {
  84. return &endNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: nodeEnd, Pos: pos}}
  85. }
  86. func (t *Template) newContent(pos Pos) *contentNode {
  87. return &contentNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: nodeContent, Pos: pos}}
  88. }
  89. func (t *Template) newElse(pos Pos, line int) *elseNode {
  90. return &elseNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: nodeElse, Pos: pos, Line: line}}
  91. }
  92. func (t *Template) newIf(pos Pos, line int, set *SetNode, pipe Expression, list, elseList *ListNode) *IfNode {
  93. return &IfNode{BranchNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeIf, Pos: pos, Line: line}, Set: set, Expression: pipe, List: list, ElseList: elseList}}
  94. }
  95. func (t *Template) newRange(pos Pos, line int, set *SetNode, pipe Expression, list, elseList *ListNode) *RangeNode {
  96. return &RangeNode{BranchNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeRange, Pos: pos, Line: line}, Set: set, Expression: pipe, List: list, ElseList: elseList}}
  97. }
  98. func (t *Template) newBlock(pos Pos, line int, name string, parameters *BlockParameterList, pipe Expression, listNode, contentListNode *ListNode) *BlockNode {
  99. return &BlockNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeBlock, Line: line, Pos: pos}, Name: name, Parameters: parameters, Expression: pipe, List: listNode, Content: contentListNode}
  100. }
  101. func (t *Template) newYield(pos Pos, line int, name string, bplist *BlockParameterList, pipe Expression, content *ListNode, isContent bool) *YieldNode {
  102. return &YieldNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeYield, Pos: pos, Line: line}, Name: name, Parameters: bplist, Expression: pipe, Content: content, IsContent: isContent}
  103. }
  104. func (t *Template) newInclude(pos Pos, line int, name, context Expression) *IncludeNode {
  105. return &IncludeNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeInclude, Pos: pos, Line: line}, Name: name, Context: context}
  106. }
  107. func (t *Template) newReturn(pos Pos, line int, pipe Expression) *ReturnNode {
  108. return &ReturnNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeReturn, Pos: pos, Line: line}, Value: pipe}
  109. }
  110. func (t *Template) newTry(pos Pos, line int, list *ListNode, catch *catchNode) *TryNode {
  111. return &TryNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeTry, Pos: pos, Line: line}, List: list, Catch: catch}
  112. }
  113. func (t *Template) newCatch(pos Pos, line int, errVar *IdentifierNode, list *ListNode) *catchNode {
  114. return &catchNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: nodeCatch, Pos: pos, Line: line}, Err: errVar, List: list}
  115. }
  116. func (t *Template) newNumber(pos Pos, text string, typ itemType) (*NumberNode, error) {
  117. n := &NumberNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeNumber, Pos: pos}, Text: text}
  118. // todo: optimize
  119. switch typ {
  120. case itemCharConstant:
  121. _rune, _, tail, err := strconv.UnquoteChar(text[1:], text[0])
  122. if err != nil {
  123. return nil, err
  124. }
  125. if tail != "'" {
  126. return nil, fmt.Errorf("malformed character constant: %s", text)
  127. }
  128. n.Int64 = int64(_rune)
  129. n.IsInt = true
  130. n.Uint64 = uint64(_rune)
  131. n.IsUint = true
  132. n.Float64 = float64(_rune) //odd but those are the rules.
  133. n.IsFloat = true
  134. return n, nil
  135. case itemComplex:
  136. //fmt.Sscan can parse the pair, so let it do the work.
  137. if _, err := fmt.Sscan(text, &n.Complex128); err != nil {
  138. return nil, err
  139. }
  140. n.IsComplex = true
  141. n.simplifyComplex()
  142. return n, nil
  143. }
  144. //Imaginary constants can only be complex unless they are zero.
  145. if len(text) > 0 && text[len(text)-1] == 'i' {
  146. f, err := strconv.ParseFloat(text[:len(text)-1], 64)
  147. if err == nil {
  148. n.IsComplex = true
  149. n.Complex128 = complex(0, f)
  150. n.simplifyComplex()
  151. return n, nil
  152. }
  153. }
  154. // Do integer test first so we get 0x123 etc.
  155. u, err := strconv.ParseUint(text, 0, 64) // will fail for -0; fixed below.
  156. if err == nil {
  157. n.IsUint = true
  158. n.Uint64 = u
  159. }
  160. i, err := strconv.ParseInt(text, 0, 64)
  161. if err == nil {
  162. n.IsInt = true
  163. n.Int64 = i
  164. if i == 0 {
  165. n.IsUint = true // in case of -0.
  166. n.Uint64 = u
  167. }
  168. }
  169. // If an integer extraction succeeded, promote the float.
  170. if n.IsInt {
  171. n.IsFloat = true
  172. n.Float64 = float64(n.Int64)
  173. } else if n.IsUint {
  174. n.IsFloat = true
  175. n.Float64 = float64(n.Uint64)
  176. } else {
  177. f, err := strconv.ParseFloat(text, 64)
  178. if err == nil {
  179. // If we parsed it as a float but it looks like an integer,
  180. // it's a huge number too large to fit in an int. Reject it.
  181. if !strings.ContainsAny(text, ".eE") {
  182. return nil, fmt.Errorf("integer overflow: %q", text)
  183. }
  184. n.IsFloat = true
  185. n.Float64 = f
  186. // If a floating-point extraction succeeded, extract the int if needed.
  187. if !n.IsInt && float64(int64(f)) == f {
  188. n.IsInt = true
  189. n.Int64 = int64(f)
  190. }
  191. if !n.IsUint && float64(uint64(f)) == f {
  192. n.IsUint = true
  193. n.Uint64 = uint64(f)
  194. }
  195. }
  196. }
  197. if !n.IsInt && !n.IsUint && !n.IsFloat {
  198. return nil, fmt.Errorf("illegal number syntax: %q", text)
  199. }
  200. return n, nil
  201. }
  202. func (t *Template) newIdentifier(ident string, pos Pos, line int) *IdentifierNode {
  203. return &IdentifierNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeIdentifier, Pos: pos, Line: line}, Ident: ident}
  204. }
  205. func (t *Template) newUnderscore(pos Pos, line int) *UnderscoreNode {
  206. return &UnderscoreNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeUnderscore, Pos: pos, Line: line}}
  207. }