github.com/coyove/nj@v0.0.0-20221110084952-c7f8db1065c3/bas/env.go (about) 1 package bas 2 3 import ( 4 "bytes" 5 "unsafe" 6 7 "github.com/coyove/nj/internal" 8 "github.com/coyove/nj/typ" 9 ) 10 11 // Env is the environment for a function to run within. 12 // 'stack' represents the global stack, a running function use 'stack[stackOffset:]' as its local stack. 13 // 'A' stores the result of the execution. 'global' is the topmost function scope, a.k.a. Program. 14 type Env struct { 15 stack *[]Value 16 top *Program 17 A Value 18 stackOffset uint32 19 runtime stacktraces 20 } 21 22 type stacktraces struct { 23 // Stacktrace layout: N, N-1, ..., 2, 1, 0(current) 24 stackN []Stacktrace // [N, N-1, ..., 2] 25 stack1 Stacktrace // 1. If nil, then 'stack0' is the only one in stacktrace 26 stack0 Stacktrace // 0 27 } 28 29 func (r stacktraces) Stacktrace(copy bool) []Stacktrace { 30 if r.stack0.Callable == nil { 31 return nil 32 } 33 if r.stack1.Callable == nil { 34 return []Stacktrace{r.stack0} 35 } 36 s := append(r.stackN, r.stack1, r.stack0) 37 if copy { 38 return append([]Stacktrace{}, s...) 39 } 40 return s 41 } 42 43 func (r stacktraces) push(k Stacktrace) stacktraces { 44 if r.stack1.Callable != nil { 45 r.stackN = append(r.stackN, r.stack1) 46 } 47 r.stack1 = r.stack0 48 r.stack0 = k 49 return r 50 } 51 52 func (env *Env) getTop() *Program { 53 if env == nil { 54 return nil 55 } 56 return env.top 57 } 58 59 func (env *Env) getStacktraces() stacktraces { 60 if env == nil { 61 return stacktraces{} 62 } 63 return env.runtime 64 } 65 66 func (env *Env) resizeZero(newSize, zeroSize int) { 67 // old := len(*env.stack) 68 env.resize(newSize) 69 // for i := old; i < int(env.stackOffset())+zeroSize; i++ { 70 // (*env.stack)[i] = Value{} 71 // } 72 } 73 74 func (env *Env) resize(newSize int) { 75 s := *env.stack 76 sz := int(env.stackOffset) + newSize 77 if sz > cap(s) { 78 old := s 79 s = make([]Value, sz+newSize) 80 copy(s, old) 81 } 82 *env.stack = s[:sz] 83 } 84 85 // Get gets value at 'index' in current stack, Get(-1) means env.A. 86 func (env *Env) Get(index int) Value { 87 if index == -1 { 88 return env.A 89 } 90 s := *env.stack 91 index += int(env.stackOffset) 92 if index < len(s) { 93 return s[index] 94 } 95 return Nil 96 } 97 98 // Set sets 'value' at 'index' in current stack. 99 func (env *Env) Set(index int, value Value) { 100 env._set(uint16(index)&typ.RegLocalMask, value) 101 } 102 103 func (env *Env) clear() { 104 *env.stack = (*env.stack)[:env.stackOffset] 105 env.A = Value{} 106 } 107 108 func (env *Env) push(v Value) { 109 *env.stack = append(*env.stack, v) 110 } 111 112 func (env *Env) Size() int { 113 return len(*env.stack) - int(env.stackOffset) 114 } 115 116 func (env *Env) _ref(yx uint16) *Value { 117 if yx == typ.RegA { 118 return &env.A 119 } 120 if yx <= typ.RegLocalMask { 121 offset := uintptr(uint32(yx)+env.stackOffset) * ValueSize 122 return (*Value)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(env.stack)) + offset)) 123 // return &(*env.stack)[uint32(yx)+env.stackOffset] 124 } 125 offset := uintptr(yx&typ.RegLocalMask) * ValueSize 126 return (*Value)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(env.top.stack)) + offset)) 127 // return (*env.global.stack)[yx&typ.RegLocalMask] 128 } 129 130 func (env *Env) _refgp(yx uint16) *Value { 131 if yx > typ.RegA { 132 offset := uintptr(yx&typ.RegLocalMask) * ValueSize 133 return (*Value)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(env.top.stack)) + offset)) 134 // return (*env.global.stack)[yx&typ.RegLocalMask] 135 } 136 if yx == typ.RegA { 137 return &env.A 138 } 139 offset := uintptr(uint32(yx)+env.stackOffset) * ValueSize 140 return (*Value)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(env.stack)) + offset)) 141 // return &(*env.stack)[uint32(yx)+env.stackOffset] 142 } 143 144 func (env *Env) _get(yx uint16) Value { 145 return *env._ref(yx) 146 } 147 148 func (env *Env) _set(yx uint16, v Value) { 149 *env._ref(yx) = v 150 } 151 152 // Stack returns current stack as a reference. 153 func (env *Env) Stack() []Value { return (*env.stack)[env.stackOffset:] } 154 155 // CopyStack returns a copy of current stack. 156 func (env *Env) CopyStack() []Value { return append([]Value{}, env.Stack()...) } 157 158 func (env *Env) String() string { 159 buf := bytes.NewBufferString("env(") 160 buf.WriteString(env.A.String()) 161 buf.WriteString(")") 162 return buf.String() 163 } 164 165 // Bool returns value at 'idx' in current stack and asserts its Type() to be a boolean. 166 func (env *Env) Bool(idx int) bool { return env.mustBe(typ.Bool, idx).Bool() } 167 168 // Str returns value at 'idx' in current stack and asserts its Type() to be a string. 169 func (env *Env) Str(idx int) string { return env.mustBe(typ.String, idx).String() } 170 171 func (env *Env) StrDefault(idx int, defaultValue string, minLen int) (res string) { 172 v := env.Get(idx) 173 switch v.Type() { 174 case typ.String: 175 if v.Len() < minLen { 176 return defaultValue 177 } 178 return v.Str() 179 case typ.Nil: 180 return defaultValue 181 case typ.Native: 182 if buf, ok := v.Native().Unwrap().([]byte); ok { 183 if len(buf) < minLen { 184 return defaultValue 185 } 186 *(*[2]int)(unsafe.Pointer(&res)) = *(*[2]int)(unsafe.Pointer(&buf)) 187 return 188 } 189 } 190 if minLen > 0 { 191 internal.Panic("expects argument #%d to be string and at least %db long, got %v", idx+1, minLen, v.simple()) 192 } 193 internal.Panic("expects argument #%d to be string, bytes or nil, got %v", idx+1, v.simple()) 194 return 195 } 196 197 // Num returns value at 'idx' in current stack and asserts its Type() to be a number. 198 func (env *Env) Num(idx int) Value { return env.mustBe(typ.Number, idx) } 199 200 // Int64 returns value at 'idx' in current stack and asserts its Type() to be a number. 201 func (env *Env) Int64(idx int) int64 { return env.mustBe(typ.Number, idx).Int64() } 202 203 // Int returns value at 'idx' in current stack and asserts its Type() to be a number. 204 func (env *Env) Int(idx int) int { return env.mustBe(typ.Number, idx).Int() } 205 206 // IntDefault returns value at 'idx' in current stack and asserts its Type() to be a number. 207 // If value is Nil, then 'defaultValue' will be returned. 208 func (env *Env) IntDefault(idx int, defaultValue int) int { 209 if v := env.Get(idx); v.pType() == typ.Number { 210 return v.Int() 211 } else if v != Nil { 212 internal.Panic("expects argument #%d to be number or nil, got %v", idx+1, v.simple()) 213 } 214 return defaultValue 215 } 216 217 // Float64 returns value at 'idx' in current stack and asserts its Type() to be a number. 218 func (env *Env) Float64(idx int) float64 { return env.mustBe(typ.Number, idx).Float64() } 219 220 // Object returns value at 'idx' in current stack and asserts its Type() to be an Object. 221 func (env *Env) Object(idx int) *Object { return env.mustBe(typ.Object, idx).Object() } 222 223 // Native returns value at 'idx' in current stack and asserts its Type() to be a Native. 224 func (env *Env) Native(idx int) *Native { return env.mustBe(typ.Native, idx).Native() } 225 226 // Interface returns value at 'idx' in current stack as interface{} 227 func (env *Env) Interface(idx int) interface{} { 228 if idx == -1 { 229 return env.A.Interface() 230 } 231 return env.Get(idx).Interface() 232 } 233 234 func (env *Env) Shape(idx int, s string) Value { 235 v := env.Get(idx) 236 if err := TestShapeFast(v, s); err != nil { 237 internal.Panic("argument #%d: %v", idx, err) 238 } 239 return v 240 } 241 242 func (env *Env) This() Value { return env.A } 243 244 func (env *Env) Self() *Object { return env.runtime.stack0.Callable } 245 246 func (env *Env) Caller() *Object { return env.runtime.stack1.Callable } 247 248 func (env *Env) mustBe(t typ.ValueType, idx int) (v Value) { 249 if idx == -1 { 250 v = env.A 251 if v.Type() != t { 252 internal.Panic("expects 'this' to be %v, got %v", t, v.simple()) 253 } 254 } else { 255 v = env.Get(idx) 256 if v.Type() != t { 257 internal.Panic("expects argument #%d to be %v, got %v", idx+1, t, v.simple()) 258 } 259 } 260 return v 261 } 262 263 func (env *Env) SetA(a Value) bool { 264 env.A = a 265 return true 266 } 267 268 func (env *Env) SetError(err error) bool { 269 env.A = Error(env, err) 270 return true 271 } 272 273 func (e *Env) MustProgram() *Program { 274 if e.top != nil { 275 return e.top 276 } 277 panic("out of program") 278 } 279 280 func (e *Env) Copy() *Env { 281 stk := e.CopyStack() 282 e2 := &Env{} 283 e2.A = e.A 284 e2.top = e.top 285 e2.stack = &stk 286 e2.runtime = e.runtime 287 e2.runtime.stackN = append([]Stacktrace{}, e2.runtime.stackN...) 288 return e2 289 } 290 291 func (e *Env) checkStackOverflow() { 292 if g := e.top; g != nil { 293 if int64(len(*g.stack)) > g.MaxStackSize { 294 panic("stack overflow") 295 } 296 if g.stopped { 297 panic("program stopped") 298 } 299 } 300 } 301 302 func (e *Env) Jump(label string) { 303 if label == "" { 304 return 305 } 306 pos, ok := e.Caller().fun.jumps[label] 307 if !ok { 308 internal.Panic("runtime jump: label %s not found", label) 309 } 310 e.runtime.stack1.Cursor = uint32(pos) 311 }