-
Notifications
You must be signed in to change notification settings - Fork 0
/
identifier.go
120 lines (110 loc) · 2.35 KB
/
identifier.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
116
117
118
119
120
package djson
import (
"errors"
"fmt"
"strconv"
)
type Identifier interface {
Value() Value
Assign(val Value) error
SetParent(p Value)
Call(scanner TokenScanner, vars Context) (val Value, err error)
}
type identifier struct {
name []byte
p Value
vars Context
}
func NewIdentifier(name []byte, ctx Context) *identifier {
return &identifier{name: name, vars: ctx}
}
func (id *identifier) SetParent(p Value) {
id.p = p
}
func (id *identifier) String() string {
n := id.name
tmp := id.p
for tmp.Type == ValueIdentifier {
t := append(tmp.Value.(*identifier).name, '.')
n = append(t, n...)
}
if tmp.Type == ValueNull {
return string(n)
}
return tmp.String() + "." + string(n)
}
func (id identifier) Value() Value {
root, err := id.root()
if err != nil {
return Value{Type: ValueNull}
}
if lookuper, ok := root.(lookuper); ok {
return lookuper.lookup(id.name)
}
return Value{Type: ValueNull}
}
func (id identifier) Assign(right Value) error {
root, err := id.root()
if err != nil {
return err
}
if vars, ok := root.(*ctx); ok {
vars.Assign(id.name, right)
return nil
} else if obj, ok := root.(Object); ok {
obj.Set(id.name, right)
} else if arr, ok := root.(Array); ok {
idx, err := strconv.Atoi(string(id.name))
if err != nil {
return err
}
arr.Set(idx, right)
} else {
return errors.New("can't support assign")
}
return nil
}
func (id identifier) root() (root interface{}, err error) {
dots := []byte{}
tmp := &id
for tmp.p.Type == ValueIdentifier {
tmp = tmp.p.Value.(*identifier)
n := tmp.name
if len(dots) > 0 {
n = append(n, '.')
}
dots = append(n, dots...)
}
root = id.vars
if tmp.p.Type != ValueNull {
root = tmp.p.Value
}
if len(dots) == 0 {
return
}
if lookuper, ok := root.(lookuper); ok {
val := lookuper.lookup(dots)
if val.Type == ValueNull {
err = errors.New("can't find root")
return
}
root = val.Value
return
}
err = errors.New("can't find root")
return
}
func (id identifier) Call(scanner TokenScanner, ctx Context) (val Value, err error) {
name := id.name
if id.p.Type == ValueNull {
err = fmt.Errorf("can't call function [%s] without caller", name)
return
}
val = id.p.RealValue()
call, ok := val.Value.(Callable)
if !ok {
err = fmt.Errorf("%s can't support call function", val.TypeName())
return
}
return call.call(string(name), val, scanner, ctx)
}