1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612 |
- // Copyright 2016 José Santos <henrique_1609@me.com>
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package jet
- import (
- "fmt"
- "github.com/CloudyKit/fastprinter"
- "io"
- "reflect"
- "runtime"
- "strconv"
- "sync"
- )
- var (
- funcType = reflect.TypeOf(Func(nil))
- stringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
- rangerType = reflect.TypeOf((*Ranger)(nil)).Elem()
- rendererType = reflect.TypeOf((*Renderer)(nil)).Elem()
- safeWriterType = reflect.TypeOf(SafeWriter(nil))
- pool_State = sync.Pool{
- New: func() interface{} {
- return &Runtime{scope: &scope{}, escapeeWriter: new(escapeeWriter)}
- },
- }
- )
- // Renderer any resulting value from an expression in an action that implements this
- // interface will not be printed, instead, we will invoke his Render() method which will be responsible
- // to render his self
- type Renderer interface {
- Render(*Runtime)
- }
- // RendererFunc func implementing interface Renderer
- type RendererFunc func(*Runtime)
- func (renderer RendererFunc) Render(r *Runtime) {
- renderer(r)
- }
- // Ranger a value implementing a ranger interface is able to iterate on his value
- // and can be used directly in a range statement
- type Ranger interface {
- Range() (reflect.Value, reflect.Value, bool)
- }
- type escapeeWriter struct {
- Writer io.Writer
- escapee SafeWriter
- set *Set
- }
- func (w *escapeeWriter) Write(b []byte) (int, error) {
- if w.set.escapee == nil {
- w.Writer.Write(b)
- } else {
- w.set.escapee(w.Writer, b)
- }
- return 0, nil
- }
- // Runtime this type holds the state of the execution of an template
- type Runtime struct {
- *escapeeWriter
- *scope
- content func(*Runtime, Expression)
- translator Translator
- context reflect.Value
- }
- // Context returns the current context value
- func (r *Runtime) Context() reflect.Value {
- return r.context
- }
- func (st *Runtime) newScope() {
- st.scope = &scope{parent: st.scope, variables: make(VarMap), blocks: st.blocks}
- }
- func (st *Runtime) releaseScope() {
- st.scope = st.scope.parent
- }
- type scope struct {
- parent *scope
- variables VarMap
- blocks map[string]*BlockNode
- }
- // YieldBlock yields a block in the current context, will panic if the context is not available
- func (st *Runtime) YieldBlock(name string, context interface{}) {
- block, has := st.getBlock(name)
- if has == false {
- panic(fmt.Errorf("Block %q was not found!!", name))
- }
- if context != nil {
- current := st.context
- st.context = reflect.ValueOf(context)
- st.executeList(block.List)
- st.context = current
- }
- st.executeList(block.List)
- }
- func (st *scope) getBlock(name string) (block *BlockNode, has bool) {
- block, has = st.blocks[name]
- for !has && st.parent != nil {
- st = st.parent
- block, has = st.blocks[name]
- }
- return
- }
- // YieldTemplate yields a template same as include
- func (st *Runtime) YieldTemplate(name string, context interface{}) {
- t, err := st.set.GetTemplate(name)
- if err != nil {
- panic(fmt.Errorf("include: template %q was not found", name))
- }
- st.newScope()
- st.blocks = t.processedBlocks
- Root := t.Root
- if t.extends != nil {
- Root = t.extends.Root
- }
- if context != nil {
- c := st.context
- st.context = reflect.ValueOf(context)
- st.executeList(Root)
- st.context = c
- } else {
- st.executeList(Root)
- }
- st.releaseScope()
- }
- // Set sets variable ${name} in the current template scope
- func (state *Runtime) Set(name string, val interface{}) {
- state.setValue(name, reflect.ValueOf(val))
- }
- func (state *Runtime) setValue(name string, val reflect.Value) bool {
- sc := state.scope
- initial := sc
- // try to resolve variables in the current scope
- _, ok := sc.variables[name]
- // if not found walks parent scopes
- for !ok && sc.parent != nil {
- sc = sc.parent
- _, ok = sc.variables[name]
- }
- if ok {
- sc.variables[name] = val
- return false
- }
- for initial.variables == nil && initial.parent != nil {
- initial = initial.parent
- }
- if initial.variables != nil {
- sc.variables[name] = val
- return false
- }
- return true
- }
- // Resolve resolves a value from the execution context
- func (state *Runtime) Resolve(name string) reflect.Value {
- if name == "." {
- return state.context
- }
- sc := state.scope
- // try to resolve variables in the current scope
- vl, ok := sc.variables[name]
- // if not found walks parent scopes
- for !ok && sc.parent != nil {
- sc = sc.parent
- vl, ok = sc.variables[name]
- }
- // if not found check globals
- if !ok {
- state.set.gmx.RLock()
- vl, ok = state.set.globals[name]
- state.set.gmx.RUnlock()
- // not found check defaultVariables
- if !ok {
- vl, ok = defaultVariables[name]
- }
- }
- return vl
- }
- func (st *Runtime) recover(err *error) {
- pool_State.Put(st)
- if recovered := recover(); recovered != nil {
- var is bool
- if _, is = recovered.(runtime.Error); is {
- panic(recovered)
- }
- *err, is = recovered.(error)
- if !is {
- panic(recovered)
- }
- }
- }
- func (st *Runtime) executeSet(left Expression, right reflect.Value) {
- typ := left.Type()
- if typ == NodeIdentifier {
- st.setValue(left.(*IdentifierNode).Ident, right)
- return
- }
- var value reflect.Value
- var fields []string
- if typ == NodeChain {
- chain := left.(*ChainNode)
- value = st.evalPrimaryExpressionGroup(chain.Node)
- fields = chain.Field
- } else {
- fields = left.(*FieldNode).Ident
- value = st.context
- }
- lef := len(fields) - 1
- for i := 0; i < lef; i++ {
- value = getFieldOrMethodValue(fields[i], value)
- if !value.IsValid() {
- left.errorf("identifier %q is not available in the current scope", fields[i])
- }
- }
- RESTART:
- switch value.Kind() {
- case reflect.Ptr:
- value = value.Elem()
- goto RESTART
- case reflect.Struct:
- value = value.FieldByName(fields[lef])
- if !value.IsValid() {
- left.errorf("identifier %q is not available in the current scope", fields[lef])
- }
- value.Set(right)
- case reflect.Map:
- value.SetMapIndex(reflect.ValueOf(&fields[lef]).Elem(), right)
- }
- }
- func (st *Runtime) executeSetList(set *SetNode) {
- if set.IndexExprGetLookup {
- value := st.evalPrimaryExpressionGroup(set.Right[0])
- st.executeSet(set.Left[0], value)
- if value.IsValid() {
- st.executeSet(set.Left[1], valueBoolTRUE)
- } else {
- st.executeSet(set.Left[1], valueBoolFALSE)
- }
- } else {
- for i := 0; i < len(set.Left); i++ {
- st.executeSet(set.Left[i], st.evalPrimaryExpressionGroup(set.Right[i]))
- }
- }
- }
- func (st *Runtime) executeLetList(set *SetNode) {
- if set.IndexExprGetLookup {
- value := st.evalPrimaryExpressionGroup(set.Right[0])
- st.variables[set.Left[0].(*IdentifierNode).Ident] = value
- if value.IsValid() {
- st.variables[set.Left[1].(*IdentifierNode).Ident] = valueBoolTRUE
- } else {
- st.variables[set.Left[1].(*IdentifierNode).Ident] = valueBoolFALSE
- }
- } else {
- for i := 0; i < len(set.Left); i++ {
- st.variables[set.Left[i].(*IdentifierNode).Ident] = st.evalPrimaryExpressionGroup(set.Right[i])
- }
- }
- }
- func (st *Runtime) executeYieldBlock(block *BlockNode, blockParam, yieldParam *BlockParameterList, expression Expression, content *ListNode) {
- needNewScope := len(blockParam.List) > 0 || len(yieldParam.List) > 0
- if needNewScope {
- st.newScope()
- for i := 0; i < len(yieldParam.List); i++ {
- p := &yieldParam.List[i]
- st.variables[p.Identifier] = st.evalPrimaryExpressionGroup(p.Expression)
- }
- for i := 0; i < len(blockParam.List); i++ {
- p := &blockParam.List[i]
- if _, found := st.variables[p.Identifier]; !found {
- if p.Expression == nil {
- st.variables[p.Identifier] = valueBoolFALSE
- } else {
- st.variables[p.Identifier] = st.evalPrimaryExpressionGroup(p.Expression)
- }
- }
- }
- }
- mycontent := st.content
- if content != nil {
- myscope := st.scope
- st.content = func(st *Runtime, expression Expression) {
- outscope := st.scope
- outcontent := st.content
- st.scope = myscope
- st.content = mycontent
- if expression != nil {
- context := st.context
- st.context = st.evalPrimaryExpressionGroup(expression)
- st.executeList(content)
- st.context = context
- } else {
- st.executeList(content)
- }
- st.scope = outscope
- st.content = outcontent
- }
- }
- if expression != nil {
- context := st.context
- st.context = st.evalPrimaryExpressionGroup(expression)
- st.executeList(block.List)
- st.context = context
- } else {
- st.executeList(block.List)
- }
- st.content = mycontent
- if needNewScope {
- st.releaseScope()
- }
- }
- func (st *Runtime) executeList(list *ListNode) {
- inNewSCOPE := false
- for i := 0; i < len(list.Nodes); i++ {
- node := list.Nodes[i]
- switch node.Type() {
- case NodeText:
- node := node.(*TextNode)
- _, err := st.Writer.Write(node.Text)
- if err != nil {
- node.error(err)
- }
- case NodeAction:
- node := node.(*ActionNode)
- if node.Set != nil {
- if node.Set.Let {
- if !inNewSCOPE {
- st.newScope() //creates new scope in the back state
- inNewSCOPE = true
- }
- st.executeLetList(node.Set)
- } else {
- st.executeSetList(node.Set)
- }
- }
- if node.Pipe != nil {
- v, safeWriter := st.evalPipelineExpression(node.Pipe)
- if !safeWriter && v.IsValid() {
- if v.Type().Implements(rendererType) {
- v.Interface().(Renderer).Render(st)
- } else {
- _, err := fastprinter.PrintValue(st.escapeeWriter, v)
- if err != nil {
- node.error(err)
- }
- }
- }
- }
- case NodeIf:
- node := node.(*IfNode)
- var isLet bool
- if node.Set != nil {
- if node.Set.Let {
- isLet = true
- st.newScope()
- st.executeLetList(node.Set)
- } else {
- st.executeSetList(node.Set)
- }
- }
- if castBoolean(st.evalPrimaryExpressionGroup(node.Expression)) {
- st.executeList(node.List)
- } else if node.ElseList != nil {
- st.executeList(node.ElseList)
- }
- if isLet {
- st.releaseScope()
- }
- case NodeRange:
- node := node.(*RangeNode)
- var expression reflect.Value
- isSet := node.Set != nil
- isLet := false
- isKeyVal := false
- context := st.context
- if isSet {
- isKeyVal = len(node.Set.Left) > 1
- expression = st.evalPrimaryExpressionGroup(node.Set.Right[0])
- if node.Set.Let {
- isLet = true
- st.newScope()
- }
- } else {
- expression = st.evalPrimaryExpressionGroup(node.Expression)
- }
- ranger := getRanger(expression)
- indexValue, rangeValue, end := ranger.Range()
- if !end {
- for !end {
- if isSet {
- if isLet {
- if isKeyVal {
- st.variables[node.Set.Left[0].String()] = indexValue
- st.variables[node.Set.Left[1].String()] = rangeValue
- } else {
- st.variables[node.Set.Left[0].String()] = rangeValue
- }
- } else {
- if isKeyVal {
- st.executeSet(node.Set.Left[0], indexValue)
- st.executeSet(node.Set.Left[1], rangeValue)
- } else {
- st.executeSet(node.Set.Left[0], rangeValue)
- }
- }
- } else {
- st.context = rangeValue
- }
- st.executeList(node.List)
- indexValue, rangeValue, end = ranger.Range()
- }
- } else if node.ElseList != nil {
- st.executeList(node.ElseList)
- }
- st.context = context
- if isLet {
- st.releaseScope()
- }
- case NodeYield:
- node := node.(*YieldNode)
- if node.IsContent {
- if st.content != nil {
- st.content(st, node.Expression)
- }
- } else {
- block, has := st.getBlock(node.Name)
- if has == false || block == nil {
- node.errorf("unresolved block %q!!", node.Name)
- }
- st.executeYieldBlock(block, block.Parameters, node.Parameters, node.Expression, node.Content)
- }
- case NodeBlock:
- node := node.(*BlockNode)
- block, has := st.getBlock(node.Name)
- if has == false {
- block = node
- }
- st.executeYieldBlock(block, block.Parameters, block.Parameters, block.Expression, block.Content)
- case NodeInclude:
- node := node.(*IncludeNode)
- var Name string
- name := st.evalPrimaryExpressionGroup(node.Name)
- if name.Type().Implements(stringerType) {
- Name = name.String()
- } else if name.Kind() == reflect.String {
- Name = name.String()
- } else {
- node.errorf("unexpected expression type %q in template yielding", getTypeString(name))
- }
- t, err := st.set.getTemplate(Name, node.TemplateName)
- if err != nil {
- node.error(err)
- } else {
- st.newScope()
- st.blocks = t.processedBlocks
- var context reflect.Value
- if node.Expression != nil {
- context = st.context
- st.context = st.evalPrimaryExpressionGroup(node.Expression)
- }
- Root := t.Root
- for t.extends != nil {
- t = t.extends
- Root = t.Root
- }
- st.executeList(Root)
- st.releaseScope()
- if node.Expression != nil {
- st.context = context
- }
- }
- }
- }
- if inNewSCOPE {
- st.releaseScope()
- }
- }
- var (
- valueBoolTRUE = reflect.ValueOf(true)
- valueBoolFALSE = reflect.ValueOf(false)
- )
- func (st *Runtime) evalPrimaryExpressionGroup(node Expression) reflect.Value {
- switch node.Type() {
- case NodeAdditiveExpr:
- return st.evalAdditiveExpression(node.(*AdditiveExprNode))
- case NodeMultiplicativeExpr:
- return st.evalMultiplicativeExpression(node.(*MultiplicativeExprNode))
- case NodeComparativeExpr:
- return st.evalComparativeExpression(node.(*ComparativeExprNode))
- case NodeNumericComparativeExpr:
- return st.evalNumericComparativeExpression(node.(*NumericComparativeExprNode))
- case NodeLogicalExpr:
- return st.evalLogicalExpression(node.(*LogicalExprNode))
- case NodeNotExpr:
- return boolValue(!castBoolean(st.evalPrimaryExpressionGroup(node.(*NotExprNode).Expr)))
- case NodeTernaryExpr:
- node := node.(*TernaryExprNode)
- if castBoolean(st.evalPrimaryExpressionGroup(node.Boolean)) {
- return st.evalPrimaryExpressionGroup(node.Left)
- }
- return st.evalPrimaryExpressionGroup(node.Right)
- case NodeCallExpr:
- node := node.(*CallExprNode)
- baseExpr := st.evalBaseExpressionGroup(node.BaseExpr)
- if baseExpr.Kind() != reflect.Func {
- node.errorf("node %q is not func kind %q", node.BaseExpr, baseExpr.Type())
- }
- return st.evalCallExpression(baseExpr, node.Args)
- case NodeIndexExpr:
- node := node.(*IndexExprNode)
- baseExpression := st.evalPrimaryExpressionGroup(node.Base)
- indexExpression := st.evalPrimaryExpressionGroup(node.Index)
- indexType := indexExpression.Type()
- if baseExpression.Kind() == reflect.Interface {
- baseExpression = baseExpression.Elem()
- }
- if baseExpression.Kind() == reflect.Ptr {
- baseExpression = baseExpression.Elem()
- }
- switch baseExpression.Kind() {
- case reflect.Map:
- key := baseExpression.Type().Key()
- if !indexType.AssignableTo(key) {
- if indexType.ConvertibleTo(key) {
- indexExpression = indexExpression.Convert(key)
- } else {
- node.errorf("%s is not assignable|convertible to map key %s", indexType.String(), key.String())
- }
- }
- return baseExpression.MapIndex(indexExpression)
- case reflect.Array, reflect.String, reflect.Slice:
- if canNumber(indexType.Kind()) {
- return baseExpression.Index(int(castInt64(indexExpression)))
- } else {
- node.errorf("non numeric value in index expression kind %s", baseExpression.Kind().String())
- }
- case reflect.Struct:
- if canNumber(indexType.Kind()) {
- return baseExpression.Field(int(castInt64(indexExpression)))
- } else if indexType.Kind() == reflect.String {
- return getFieldOrMethodValue(indexExpression.String(), baseExpression)
- } else {
- node.errorf("non numeric value in index expression kind %s", baseExpression.Kind().String())
- }
- default:
- node.errorf("indexing is not supported in value type %s", baseExpression.Kind().String())
- }
- case NodeSliceExpr:
- node := node.(*SliceExprNode)
- baseExpression := st.evalPrimaryExpressionGroup(node.Base)
- var index, length int
- if node.Index != nil {
- indexExpression := st.evalPrimaryExpressionGroup(node.Index)
- if canNumber(indexExpression.Kind()) {
- index = int(castInt64(indexExpression))
- } else {
- node.Index.errorf("non numeric value in index expression kind %s", indexExpression.Kind().String())
- }
- }
- if node.EndIndex != nil {
- indexExpression := st.evalPrimaryExpressionGroup(node.EndIndex)
- if canNumber(indexExpression.Kind()) {
- length = int(castInt64(indexExpression))
- } else {
- node.EndIndex.errorf("non numeric value in index expression kind %s", indexExpression.Kind().String())
- }
- } else {
- length = baseExpression.Len()
- }
- return baseExpression.Slice(index, length)
- }
- return st.evalBaseExpressionGroup(node)
- }
- func (st *Runtime) isSet(node Node) bool {
- nodeType := node.Type()
- switch nodeType {
- case NodeIndexExpr:
- node := node.(*IndexExprNode)
- if !st.isSet(node.Base) {
- return false
- }
- if !st.isSet(node.Index) {
- return false
- }
- baseExpression := st.evalPrimaryExpressionGroup(node.Base)
- indexExpression := st.evalPrimaryExpressionGroup(node.Index)
- indexType := indexExpression.Type()
- if baseExpression.Kind() == reflect.Ptr {
- baseExpression = baseExpression.Elem()
- }
- switch baseExpression.Kind() {
- case reflect.Map:
- key := baseExpression.Type().Key()
- if !indexType.AssignableTo(key) {
- if indexType.ConvertibleTo(key) {
- indexExpression = indexExpression.Convert(key)
- } else {
- node.errorf("%s is not assignable|convertible to map key %s", indexType.String(), key.String())
- }
- }
- return baseExpression.MapIndex(indexExpression).IsValid()
- case reflect.Array, reflect.String, reflect.Slice:
- if canNumber(indexType.Kind()) {
- i := int(castInt64(indexExpression))
- return i >= 0 && i < baseExpression.Len()
- } else {
- node.errorf("non numeric value in index expression kind %s", baseExpression.Kind().String())
- }
- case reflect.Struct:
- if canNumber(indexType.Kind()) {
- i := int(castInt64(indexExpression))
- return i >= 0 && i < baseExpression.NumField()
- } else if indexType.Kind() == reflect.String {
- return getFieldOrMethodValue(indexExpression.String(), baseExpression).IsValid()
- } else {
- node.errorf("non numeric value in index expression kind %s", baseExpression.Kind().String())
- }
- default:
- node.errorf("indexing is not supported in value type %s", baseExpression.Kind().String())
- }
- case NodeIdentifier:
- if st.Resolve(node.String()).IsValid() == false {
- return false
- }
- case NodeField:
- node := node.(*FieldNode)
- resolved := st.context
- for i := 0; i < len(node.Ident); i++ {
- resolved = getFieldOrMethodValue(node.Ident[i], resolved)
- if !resolved.IsValid() {
- return false
- }
- }
- case NodeChain:
- node := node.(*ChainNode)
- var value = st.evalPrimaryExpressionGroup(node.Node)
- if !value.IsValid() {
- return false
- }
- for i := 0; i < len(node.Field); i++ {
- value := getFieldOrMethodValue(node.Field[i], value)
- if !value.IsValid() {
- return false
- }
- }
- default:
- //todo: maybe work some edge cases
- if !(nodeType > beginExpressions && nodeType < endExpressions) {
- node.errorf("unexpected %q node in isset clause", node)
- }
- }
- return true
- }
- func (st *Runtime) evalNumericComparativeExpression(node *NumericComparativeExprNode) reflect.Value {
- left, right := st.evalPrimaryExpressionGroup(node.Left), st.evalPrimaryExpressionGroup(node.Right)
- isTrue := false
- kind := left.Kind()
- // if the left value is not a float and the right is, we need to promote the left value to a float before the calculation
- // this is necessary for expressions like 4*1.23
- needFloatPromotion := !isFloat(kind) && isFloat(right.Kind())
- switch node.Operator.typ {
- case itemGreat:
- if isInt(kind) {
- if needFloatPromotion {
- isTrue = float64(left.Int()) > right.Float()
- } else {
- isTrue = left.Int() > toInt(right)
- }
- } else if isFloat(kind) {
- isTrue = left.Float() > toFloat(right)
- } else if isUint(kind) {
- if needFloatPromotion {
- isTrue = float64(left.Uint()) > right.Float()
- } else {
- isTrue = left.Uint() > toUint(right)
- }
- } else {
- node.Left.errorf("a non numeric value in numeric comparative expression")
- }
- case itemGreatEquals:
- if isInt(kind) {
- if needFloatPromotion {
- isTrue = float64(left.Int()) >= right.Float()
- } else {
- isTrue = left.Int() >= toInt(right)
- }
- } else if isFloat(kind) {
- isTrue = left.Float() >= toFloat(right)
- } else if isUint(kind) {
- if needFloatPromotion {
- isTrue = float64(left.Uint()) >= right.Float()
- } else {
- isTrue = left.Uint() >= toUint(right)
- }
- } else {
- node.Left.errorf("a non numeric value in numeric comparative expression")
- }
- case itemLess:
- if isInt(kind) {
- if needFloatPromotion {
- isTrue = float64(left.Int()) < right.Float()
- } else {
- isTrue = left.Int() < toInt(right)
- }
- } else if isFloat(kind) {
- isTrue = left.Float() < toFloat(right)
- } else if isUint(kind) {
- if needFloatPromotion {
- isTrue = float64(left.Uint()) < right.Float()
- } else {
- isTrue = left.Uint() < toUint(right)
- }
- } else {
- node.Left.errorf("a non numeric value in numeric comparative expression")
- }
- case itemLessEquals:
- if isInt(kind) {
- if needFloatPromotion {
- isTrue = float64(left.Int()) <= right.Float()
- } else {
- isTrue = left.Int() <= toInt(right)
- }
- } else if isFloat(kind) {
- isTrue = left.Float() <= toFloat(right)
- } else if isUint(kind) {
- if needFloatPromotion {
- isTrue = float64(left.Uint()) <= right.Float()
- } else {
- isTrue = left.Uint() <= toUint(right)
- }
- } else {
- node.Left.errorf("a non numeric value in numeric comparative expression")
- }
- }
- return boolValue(isTrue)
- }
- func (st *Runtime) evalLogicalExpression(node *LogicalExprNode) reflect.Value {
- isTrue := castBoolean(st.evalPrimaryExpressionGroup(node.Left))
- if node.Operator.typ == itemAnd {
- isTrue = isTrue && castBoolean(st.evalPrimaryExpressionGroup(node.Right))
- } else {
- isTrue = isTrue || castBoolean(st.evalPrimaryExpressionGroup(node.Right))
- }
- return boolValue(isTrue)
- }
- func boolValue(isTrue bool) reflect.Value {
- if isTrue {
- return valueBoolTRUE
- }
- return valueBoolFALSE
- }
- func (st *Runtime) evalComparativeExpression(node *ComparativeExprNode) reflect.Value {
- left, right := st.evalPrimaryExpressionGroup(node.Left), st.evalPrimaryExpressionGroup(node.Right)
- if node.Operator.typ == itemNotEquals {
- return boolValue(!checkEquality(left, right))
- }
- return boolValue(checkEquality(left, right))
- }
- func toInt(v reflect.Value) int64 {
- kind := v.Kind()
- if isInt(kind) {
- return v.Int()
- } else if isFloat(kind) {
- return int64(v.Float())
- } else if isUint(kind) {
- return int64(v.Uint())
- } else if kind == reflect.String {
- n, e := strconv.ParseInt(v.String(), 10, 0)
- if e != nil {
- panic(e)
- }
- return n
- } else if kind == reflect.Bool {
- if v.Bool() {
- return 0
- }
- return 1
- }
- panic(fmt.Errorf("type: %q can't be converted to int64", v.Type()))
- }
- func toUint(v reflect.Value) uint64 {
- kind := v.Kind()
- if isUint(kind) {
- return v.Uint()
- } else if isInt(kind) {
- return uint64(v.Int())
- } else if isFloat(kind) {
- return uint64(v.Float())
- } else if kind == reflect.String {
- n, e := strconv.ParseUint(v.String(), 10, 0)
- if e != nil {
- panic(e)
- }
- return n
- } else if kind == reflect.Bool {
- if v.Bool() {
- return 0
- }
- return 1
- }
- panic(fmt.Errorf("type: %q can't be converted to uint64", v.Type()))
- }
- func toFloat(v reflect.Value) float64 {
- kind := v.Kind()
- if isFloat(kind) {
- return v.Float()
- } else if isInt(kind) {
- return float64(v.Int())
- } else if isUint(kind) {
- return float64(v.Uint())
- } else if kind == reflect.String {
- n, e := strconv.ParseFloat(v.String(), 0)
- if e != nil {
- panic(e)
- }
- return n
- } else if kind == reflect.Bool {
- if v.Bool() {
- return 0
- }
- return 1
- }
- panic(fmt.Errorf("type: %q can't be converted to float64", v.Type()))
- }
- func (st *Runtime) evalMultiplicativeExpression(node *MultiplicativeExprNode) reflect.Value {
- left, right := st.evalPrimaryExpressionGroup(node.Left), st.evalPrimaryExpressionGroup(node.Right)
- kind := left.Kind()
- // if the left value is not a float and the right is, we need to promote the left value to a float before the calculation
- // this is necessary for expressions like 4*1.23
- needFloatPromotion := !isFloat(kind) && isFloat(right.Kind())
- switch node.Operator.typ {
- case itemMul:
- if isInt(kind) {
- if needFloatPromotion {
- // do the promotion and calculates
- left = reflect.ValueOf(float64(left.Int()) * right.Float())
- } else {
- // do not need float promotion
- left = reflect.ValueOf(left.Int() * toInt(right))
- }
- } else if isFloat(kind) {
- left = reflect.ValueOf(left.Float() * toFloat(right))
- } else if isUint(kind) {
- if needFloatPromotion {
- left = reflect.ValueOf(float64(left.Uint()) * right.Float())
- } else {
- left = reflect.ValueOf(left.Uint() * toUint(right))
- }
- } else {
- node.Left.errorf("a non numeric value in multiplicative expression")
- }
- case itemDiv:
- if isInt(kind) {
- if needFloatPromotion {
- left = reflect.ValueOf(float64(left.Int()) / right.Float())
- } else {
- left = reflect.ValueOf(left.Int() / toInt(right))
- }
- } else if isFloat(kind) {
- left = reflect.ValueOf(left.Float() / toFloat(right))
- } else if isUint(kind) {
- if needFloatPromotion {
- left = reflect.ValueOf(float64(left.Uint()) / right.Float())
- } else {
- left = reflect.ValueOf(left.Uint() / toUint(right))
- }
- } else {
- node.Left.errorf("a non numeric value in multiplicative expression")
- }
- case itemMod:
- if isInt(kind) {
- left = reflect.ValueOf(left.Int() % toInt(right))
- } else if isFloat(kind) {
- left = reflect.ValueOf(int64(left.Float()) % toInt(right))
- } else if isUint(kind) {
- left = reflect.ValueOf(left.Uint() % toUint(right))
- } else {
- node.Left.errorf("a non numeric value in multiplicative expression")
- }
- }
- return left
- }
- func (st *Runtime) evalAdditiveExpression(node *AdditiveExprNode) reflect.Value {
- isAdditive := node.Operator.typ == itemAdd
- if node.Left == nil {
- right := st.evalPrimaryExpressionGroup(node.Right)
- kind := right.Kind()
- // todo: optimize
- // todo:
- if isInt(kind) {
- if isAdditive {
- return reflect.ValueOf(+right.Int())
- } else {
- return reflect.ValueOf(-right.Int())
- }
- } else if isUint(kind) {
- if isAdditive {
- return right
- } else {
- return reflect.ValueOf(-int64(right.Uint()))
- }
- } else if isFloat(kind) {
- if isAdditive {
- return reflect.ValueOf(+right.Float())
- } else {
- return reflect.ValueOf(-right.Float())
- }
- }
- node.Left.errorf("a non numeric value in additive expression")
- }
- left, right := st.evalPrimaryExpressionGroup(node.Left), st.evalPrimaryExpressionGroup(node.Right)
- kind := left.Kind()
- // if the left value is not a float and the right is, we need to promote the left value to a float before the calculation
- // this is necessary for expressions like 4+1.23
- needFloatPromotion := !isFloat(kind) && kind != reflect.String && isFloat(right.Kind())
- if needFloatPromotion {
- if isInt(kind) {
- if isAdditive {
- left = reflect.ValueOf(float64(left.Int()) + right.Float())
- } else {
- left = reflect.ValueOf(float64(left.Int()) - right.Float())
- }
- } else if isUint(kind) {
- if isAdditive {
- left = reflect.ValueOf(float64(left.Uint()) + right.Float())
- } else {
- left = reflect.ValueOf(float64(left.Uint()) - right.Float())
- }
- } else {
- node.Left.errorf("a non numeric value in additive expression")
- }
- } else {
- if isInt(kind) {
- if isAdditive {
- left = reflect.ValueOf(left.Int() + toInt(right))
- } else {
- left = reflect.ValueOf(left.Int() - toInt(right))
- }
- } else if isFloat(kind) {
- if isAdditive {
- left = reflect.ValueOf(left.Float() + toFloat(right))
- } else {
- left = reflect.ValueOf(left.Float() - toFloat(right))
- }
- } else if isUint(kind) {
- if isAdditive {
- left = reflect.ValueOf(left.Uint() + toUint(right))
- } else {
- left = reflect.ValueOf(left.Uint() - toUint(right))
- }
- } else if kind == reflect.String {
- if isAdditive {
- left = reflect.ValueOf(left.String() + fmt.Sprint(right))
- } else {
- node.Right.errorf("minus signal is not allowed with strings")
- }
- } else {
- node.Left.errorf("a non numeric value in additive expression")
- }
- }
- return left
- }
- func getTypeString(value reflect.Value) string {
- if value.IsValid() {
- return value.Type().String()
- }
- return "nil"
- }
- func (st *Runtime) evalBaseExpressionGroup(node Node) reflect.Value {
- switch node.Type() {
- case NodeNil:
- return reflect.ValueOf(nil)
- case NodeBool:
- if node.(*BoolNode).True {
- return valueBoolTRUE
- }
- return valueBoolFALSE
- case NodeString:
- return reflect.ValueOf(&node.(*StringNode).Text).Elem()
- case NodeIdentifier:
- resolved := st.Resolve(node.(*IdentifierNode).Ident)
- if !resolved.IsValid() {
- node.errorf("identifier %q is not available in the current scope %v", node, st.variables)
- }
- return resolved
- case NodeField:
- node := node.(*FieldNode)
- resolved := st.context
- for i := 0; i < len(node.Ident); i++ {
- fieldResolved := getFieldOrMethodValue(node.Ident[i], resolved)
- if !fieldResolved.IsValid() {
- node.errorf("there is no field or method %q in %s", node.Ident[i], getTypeString(resolved))
- }
- resolved = fieldResolved
- }
- return resolved
- case NodeChain:
- node := node.(*ChainNode)
- var resolved = st.evalPrimaryExpressionGroup(node.Node)
- for i := 0; i < len(node.Field); i++ {
- fieldValue := getFieldOrMethodValue(node.Field[i], resolved)
- if !fieldValue.IsValid() {
- node.errorf("there is no field or method %q in %s", node.Field[i], getTypeString(resolved))
- }
- resolved = fieldValue
- }
- return resolved
- case NodeNumber:
- node := node.(*NumberNode)
- if node.IsFloat {
- return reflect.ValueOf(&node.Float64).Elem()
- }
- if node.IsInt {
- return reflect.ValueOf(&node.Int64).Elem()
- }
- if node.IsUint {
- return reflect.ValueOf(&node.Uint64).Elem()
- }
- }
- node.errorf("unexpected node type %s in unary expression evaluating", node)
- return reflect.Value{}
- }
- func (st *Runtime) evalCallExpression(baseExpr reflect.Value, args []Expression, values ...reflect.Value) reflect.Value {
- if funcType.AssignableTo(baseExpr.Type()) {
- return baseExpr.Interface().(Func)(Arguments{runtime: st, argExpr: args, argVal: values})
- }
- i := len(args) + len(values)
- var returns []reflect.Value
- if i <= 10 {
- returns = reflect_Call10(i, st, baseExpr, args, values...)
- } else {
- returns = reflect_Call(make([]reflect.Value, i, i), st, baseExpr, args, values...)
- }
- if len(returns) == 0 {
- return reflect.Value{}
- }
- return returns[0]
- }
- func (st *Runtime) evalCommandExpression(node *CommandNode) (reflect.Value, bool) {
- term := st.evalPrimaryExpressionGroup(node.BaseExpr)
- if node.Call {
- if term.Kind() == reflect.Func {
- if term.Type() == safeWriterType {
- st.evalSafeWriter(term, node)
- return reflect.Value{}, true
- }
- return st.evalCallExpression(term, node.Args), false
- } else {
- node.Args[0].errorf("command %q type %s is not func", node.Args[0], term.Type())
- }
- }
- return term, false
- }
- type escapeWriter struct {
- rawWriter io.Writer
- safeWriter SafeWriter
- }
- func (w *escapeWriter) Write(b []byte) (int, error) {
- w.safeWriter(w.rawWriter, b)
- return 0, nil
- }
- func (st *Runtime) evalSafeWriter(term reflect.Value, node *CommandNode, v ...reflect.Value) {
- sw := &escapeWriter{rawWriter: st.Writer, safeWriter: term.Interface().(SafeWriter)}
- for i := 0; i < len(v); i++ {
- fastprinter.PrintValue(sw, v[i])
- }
- for i := 0; i < len(node.Args); i++ {
- fastprinter.PrintValue(sw, st.evalPrimaryExpressionGroup(node.Args[i]))
- }
- }
- func (st *Runtime) evalCommandPipeExpression(node *CommandNode, value reflect.Value) (reflect.Value, bool) {
- term := st.evalPrimaryExpressionGroup(node.BaseExpr)
- if term.Kind() == reflect.Func {
- if term.Type() == safeWriterType {
- st.evalSafeWriter(term, node, value)
- return reflect.Value{}, true
- }
- return st.evalCallExpression(term, node.Args, value), false
- } else {
- node.BaseExpr.errorf("pipe command %q type %s is not func", node.BaseExpr, term.Type())
- }
- return term, false
- }
- func (st *Runtime) evalPipelineExpression(node *PipeNode) (value reflect.Value, safeWriter bool) {
- value, safeWriter = st.evalCommandExpression(node.Cmds[0])
- for i := 1; i < len(node.Cmds); i++ {
- if safeWriter {
- node.Cmds[i].errorf("unexpected command %s, writer command should be the last command", node.Cmds[i])
- }
- value, safeWriter = st.evalCommandPipeExpression(node.Cmds[i], value)
- }
- return
- }
- func reflect_Call(arguments []reflect.Value, st *Runtime, fn reflect.Value, args []Expression, values ...reflect.Value) []reflect.Value {
- typ := fn.Type()
- numIn := typ.NumIn()
- isVariadic := typ.IsVariadic()
- if isVariadic {
- numIn--
- }
- i, j := 0, 0
- for ; i < numIn && i < len(values); i++ {
- in := typ.In(i)
- term := values[i]
- if !term.Type().AssignableTo(in) {
- term = term.Convert(in)
- }
- arguments[i] = term
- }
- if isVariadic {
- in := typ.In(numIn).Elem()
- for ; i < len(values); i++ {
- term := values[i]
- if !term.Type().AssignableTo(in) {
- term = term.Convert(in)
- }
- arguments[i] = term
- }
- }
- for ; i < numIn && j < len(args); i, j = i+1, j+1 {
- in := typ.In(i)
- term := st.evalPrimaryExpressionGroup(args[j])
- if !term.Type().AssignableTo(in) {
- term = term.Convert(in)
- }
- arguments[i] = term
- }
- if isVariadic {
- in := typ.In(numIn).Elem()
- for ; j < len(args); i, j = i+1, j+1 {
- term := st.evalPrimaryExpressionGroup(args[j])
- if !term.Type().AssignableTo(in) {
- term = term.Convert(in)
- }
- arguments[i] = term
- }
- }
- return fn.Call(arguments[0:i])
- }
- func reflect_Call10(i int, st *Runtime, fn reflect.Value, args []Expression, values ...reflect.Value) []reflect.Value {
- var arguments [10]reflect.Value
- return reflect_Call(arguments[0:i], st, fn, args, values...)
- }
- func isUint(kind reflect.Kind) bool {
- return kind >= reflect.Uint && kind <= reflect.Uint64
- }
- func isInt(kind reflect.Kind) bool {
- return kind >= reflect.Int && kind <= reflect.Int64
- }
- func isFloat(kind reflect.Kind) bool {
- return kind == reflect.Float32 || kind == reflect.Float64
- }
- // checkEquality of two reflect values in the semantic of the jet runtime
- func checkEquality(v1, v2 reflect.Value) bool {
- if !v1.IsValid() || !v2.IsValid() {
- return v1.IsValid() == v2.IsValid()
- }
- v1Type := v1.Type()
- v2Type := v2.Type()
- // fast path
- if v1Type != v2.Type() && !v2Type.AssignableTo(v1Type) && !v2Type.ConvertibleTo(v1Type) {
- return false
- }
- kind := v1.Kind()
- if isInt(kind) {
- return v1.Int() == toInt(v2)
- }
- if isFloat(kind) {
- return v1.Float() == toFloat(v2)
- }
- if isUint(kind) {
- return v1.Uint() == toUint(v2)
- }
- switch kind {
- case reflect.Bool:
- return v1.Bool() == castBoolean(v2)
- case reflect.String:
- return v1.String() == v2.String()
- case reflect.Array:
- vlen := v1.Len()
- if vlen == v2.Len() {
- return false
- }
- for i := 0; i < vlen; i++ {
- if !checkEquality(v1.Index(i), v2.Index(i)) {
- return false
- }
- }
- return true
- case reflect.Slice:
- if v1.IsNil() != v2.IsNil() {
- return false
- }
- vlen := v1.Len()
- if vlen != v2.Len() {
- return false
- }
- if v1.CanAddr() && v2.CanAddr() && v1.Pointer() == v2.Pointer() {
- return true
- }
- for i := 0; i < vlen; i++ {
- if !checkEquality(v1.Index(i), v2.Index(i)) {
- return false
- }
- }
- return true
- case reflect.Interface:
- if v1.IsNil() || v2.IsNil() {
- return v1.IsNil() == v2.IsNil()
- }
- return checkEquality(v1.Elem(), v2.Elem())
- case reflect.Ptr:
- return v1.Pointer() == v2.Pointer()
- case reflect.Struct:
- numField := v1.NumField()
- for i, n := 0, numField; i < n; i++ {
- if !checkEquality(v1.Field(i), v2.Field(i)) {
- return false
- }
- }
- return true
- case reflect.Map:
- if v1.IsNil() != v2.IsNil() {
- return false
- }
- if v1.Len() != v2.Len() {
- return false
- }
- if v1.Pointer() == v2.Pointer() {
- return true
- }
- for _, k := range v1.MapKeys() {
- val1 := v1.MapIndex(k)
- val2 := v2.MapIndex(k)
- if !val1.IsValid() || !val2.IsValid() || !checkEquality(v1.MapIndex(k), v2.MapIndex(k)) {
- return false
- }
- }
- return true
- case reflect.Func:
- return v1.IsNil() && v2.IsNil()
- default:
- // Normal equality suffices
- return v1.Interface() == v2.Interface()
- }
- }
- func castBoolean(v reflect.Value) bool {
- kind := v.Kind()
- switch kind {
- case reflect.Ptr:
- return v.IsNil() == false
- case reflect.Bool:
- return v.Bool()
- case reflect.Array:
- numItems := v.Len()
- for i, n := 0, numItems; i < n; i++ {
- if !castBoolean(v.Index(i)) {
- return false
- }
- }
- return true
- case reflect.Struct:
- numField := v.NumField()
- for i, n := 0, numField; i < n; i++ {
- if !castBoolean(v.Field(i)) {
- return false
- }
- }
- return true
- case reflect.Map, reflect.Slice, reflect.String:
- return v.Len() > 0
- default:
- if isInt(kind) {
- return v.Int() > 0
- }
- if isUint(kind) {
- return v.Uint() > 0
- }
- if isFloat(kind) {
- return v.Float() > 0
- }
- }
- return false
- }
- func canNumber(kind reflect.Kind) bool {
- return isInt(kind) || isUint(kind) || isFloat(kind)
- }
- func castInt64(v reflect.Value) int64 {
- kind := v.Kind()
- switch {
- case isInt(kind):
- return v.Int()
- case isUint(kind):
- return int64(v.Uint())
- case isFloat(kind):
- return int64(v.Float())
- }
- return 0
- }
- var cachedStructsMutex = sync.RWMutex{}
- var cachedStructsFieldIndex = map[reflect.Type]map[string][]int{}
- func getFieldOrMethodValue(key string, v reflect.Value) reflect.Value {
- value := getValue(key, v)
- if value.Kind() == reflect.Interface {
- value = value.Elem()
- }
- return value
- }
- func getValue(key string, v reflect.Value) reflect.Value {
- if !v.IsValid() {
- return reflect.Value{}
- }
- value := v.MethodByName(key)
- if value.IsValid() {
- return value
- }
- k := v.Kind()
- if k == reflect.Ptr || k == reflect.Interface {
- v = v.Elem()
- k = v.Kind()
- value = v.MethodByName(key)
- if value.IsValid() {
- return value
- }
- } else if v.CanAddr() {
- value = v.Addr().MethodByName(key)
- if value.IsValid() {
- return value
- }
- }
- if k == reflect.Struct {
- typ := v.Type()
- cachedStructsMutex.RLock()
- cache, ok := cachedStructsFieldIndex[typ]
- cachedStructsMutex.RUnlock()
- if !ok {
- cachedStructsMutex.Lock()
- if cache, ok = cachedStructsFieldIndex[typ]; !ok {
- cache = make(map[string][]int)
- buildCache(typ, cache, nil)
- cachedStructsFieldIndex[typ] = cache
- }
- cachedStructsMutex.Unlock()
- }
- if id, ok := cache[key]; ok {
- return v.FieldByIndex(id)
- }
- return reflect.Value{}
- } else if k == reflect.Map {
- return v.MapIndex(reflect.ValueOf(key))
- }
- return reflect.Value{}
- }
- func buildCache(typ reflect.Type, cache map[string][]int, parent []int) {
- numFields := typ.NumField()
- max := len(parent) + 1
- for i := 0; i < numFields; i++ {
- index := make([]int, max)
- copy(index, parent)
- index[len(parent)] = i
- field := typ.Field(i)
- if field.Anonymous {
- typ := field.Type
- if typ.Kind() == reflect.Struct {
- buildCache(typ, cache, index)
- }
- }
- cache[field.Name] = index
- }
- }
- func getRanger(v reflect.Value) Ranger {
- tuP := v.Type()
- if tuP.Implements(rangerType) {
- return v.Interface().(Ranger)
- }
- k := tuP.Kind()
- switch k {
- case reflect.Ptr, reflect.Interface:
- v = v.Elem()
- k = v.Kind()
- fallthrough
- case reflect.Slice, reflect.Array:
- sliceranger := pool_sliceRanger.Get().(*sliceRanger)
- sliceranger.i = -1
- sliceranger.len = v.Len()
- sliceranger.v = v
- return sliceranger
- case reflect.Map:
- mapranger := pool_mapRanger.Get().(*mapRanger)
- *mapranger = mapRanger{v: v, keys: v.MapKeys(), len: v.Len()}
- return mapranger
- case reflect.Chan:
- chanranger := pool_chanRanger.Get().(*chanRanger)
- *chanranger = chanRanger{v: v}
- return chanranger
- }
- panic(fmt.Errorf("type %s is not rangeable", tuP))
- }
- var (
- pool_sliceRanger = sync.Pool{
- New: func() interface{} {
- return new(sliceRanger)
- },
- }
- pool_mapRanger = sync.Pool{
- New: func() interface{} {
- return new(mapRanger)
- },
- }
- pool_chanRanger = sync.Pool{
- New: func() interface{} {
- return new(chanRanger)
- },
- }
- )
- type sliceRanger struct {
- v reflect.Value
- len int
- i int
- }
- func (s *sliceRanger) Range() (index, value reflect.Value, end bool) {
- s.i++
- index = reflect.ValueOf(&s.i).Elem()
- if s.i < s.len {
- value = s.v.Index(s.i)
- return
- }
- pool_sliceRanger.Put(s)
- end = true
- return
- }
- type chanRanger struct {
- v reflect.Value
- }
- func (s *chanRanger) Range() (_, value reflect.Value, end bool) {
- value, end = s.v.Recv()
- if end {
- pool_chanRanger.Put(s)
- }
- return
- }
- type mapRanger struct {
- v reflect.Value
- keys []reflect.Value
- len int
- i int
- }
- func (s *mapRanger) Range() (index, value reflect.Value, end bool) {
- if s.i < s.len {
- index = s.keys[s.i]
- value = s.v.MapIndex(index)
- s.i++
- return
- }
- end = true
- pool_mapRanger.Put(s)
- return
- }
|