-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsym.go
115 lines (103 loc) · 2.6 KB
/
sym.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// Copyright 2015 Seth Bunce. All rights reserved. Use of this source code is
// governed by a BSD-style license that can be found in the LICENSE file.
package stem
import (
"fmt"
"reflect"
)
// Symbol table.
type symtab struct {
scope []reflect.Value // scopes has inner most scope as the last elem.
arrayElem reflect.Value // arrayElem is zero value except when in array.
}
// indirect all interfaces/pointers.
func indirect(v reflect.Value) reflect.Value {
loop:
for {
switch v.Kind() {
case reflect.Interface:
v = v.Elem()
case reflect.Ptr:
v = v.Elem()
default:
break loop
}
}
return v
}
func newsymtab(data map[string]interface{}) *symtab {
return &symtab{
scope: []reflect.Value{reflect.ValueOf(data)},
}
}
// Array returns a slice or the zero value.
func (s *symtab) Array(key string) reflect.Value {
v := reflect.ValueOf(key)
for x := len(s.scope) - 1; x >= 0; x-- {
if e := s.scope[x].MapIndex(v); e.IsValid() {
e = indirect(e)
if e.Kind() == reflect.Slice && e.IsValid() && !e.IsNil() {
return e
}
break
}
}
return reflect.Value{}
}
// EnterArrayElem sets the current scope as an array element.
func (s *symtab) EnterArrayElem(elem reflect.Value) *symtab {
return &symtab{
scope: s.scope,
arrayElem: elem,
}
}
// EnterObject returns the symbol table with obj as the inner most scope.
func (s *symtab) EnterObject(obj reflect.Value) *symtab {
return &symtab{
scope: append(s.scope, obj),
}
}
// Ifdef returns true if the key is defined.
func (s *symtab) Ifdef(key string) bool {
if key == "" && s.arrayElem.IsValid() {
return true
}
v := reflect.ValueOf(key)
for x := len(s.scope) - 1; x >= 0; x-- {
if e := s.scope[x].MapIndex(v); e.IsValid() {
return true
}
}
return false
}
// Ifndef returns true if the key is not defined.
func (s *symtab) Ifndef(symbol string) bool {
return !s.Ifdef(symbol)
}
// Print returns the string representation of the value.
func (s *symtab) Print(symbol string) string {
if symbol == "" && s.arrayElem.IsValid() {
return fmt.Sprint(indirect(s.arrayElem).Interface())
}
v := reflect.ValueOf(symbol)
for x := len(s.scope) - 1; x >= 0; x-- {
if e := s.scope[x].MapIndex(v); e.IsValid() {
return fmt.Sprint(indirect(e).Interface())
}
}
return ""
}
// Object returns a map or the zero value.
func (s *symtab) Object(symbol string) reflect.Value {
v := reflect.ValueOf(symbol)
for x := len(s.scope) - 1; x >= 0; x-- {
if e := s.scope[x].MapIndex(v); e.IsValid() {
e = indirect(e)
if e.Kind() == reflect.Map && e.IsValid() && !e.IsNil() {
return e
}
break
}
}
return reflect.Value{}
}