github.com/tul/gopher-lua@v0.0.0-20181008131706-f6fcaab0c612/value.go (about) 1 package lua 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 ) 8 9 type LValueType int 10 11 const ( 12 LTNil LValueType = iota 13 LTBool 14 LTNumber 15 LTString 16 LTFunction 17 LTUserData 18 LTThread 19 LTTable 20 LTChannel 21 ) 22 23 var lValueNames = [9]string{"nil", "boolean", "number", "string", "function", "userdata", "thread", "table", "channel"} 24 25 func (vt LValueType) String() string { 26 return lValueNames[int(vt)] 27 } 28 29 type LValue interface { 30 String() string 31 Type() LValueType 32 // to reduce `runtime.assertI2T2` costs, this method should be used instead of the type assertion in heavy paths(typically inside the VM). 33 assertFloat64() (float64, bool) 34 // to reduce `runtime.assertI2T2` costs, this method should be used instead of the type assertion in heavy paths(typically inside the VM). 35 assertString() (string, bool) 36 // to reduce `runtime.assertI2T2` costs, this method should be used instead of the type assertion in heavy paths(typically inside the VM). 37 assertFunction() (*LFunction, bool) 38 } 39 40 // LVIsFalse returns true if a given LValue is a nil or false otherwise false. 41 func LVIsFalse(v LValue) bool { return v == LNil || v == LFalse } 42 43 // LVIsFalse returns false if a given LValue is a nil or false otherwise true. 44 func LVAsBool(v LValue) bool { return v != LNil && v != LFalse } 45 46 // LVAsString returns string representation of a given LValue 47 // if the LValue is a string or number, otherwise an empty string. 48 func LVAsString(v LValue) string { 49 switch sn := v.(type) { 50 case LString, LNumber: 51 return sn.String() 52 default: 53 return "" 54 } 55 } 56 57 // LVCanConvToString returns true if a given LValue is a string or number 58 // otherwise false. 59 func LVCanConvToString(v LValue) bool { 60 switch v.(type) { 61 case LString, LNumber: 62 return true 63 default: 64 return false 65 } 66 } 67 68 // LVAsNumber tries to convert a given LValue to a number. 69 func LVAsNumber(v LValue) LNumber { 70 switch lv := v.(type) { 71 case LNumber: 72 return lv 73 case LString: 74 if num, err := parseNumber(string(lv)); err == nil { 75 return num 76 } 77 } 78 return LNumber(0) 79 } 80 81 type LNilType struct{} 82 83 func (nl *LNilType) String() string { return "nil" } 84 func (nl *LNilType) Type() LValueType { return LTNil } 85 func (nl *LNilType) assertFloat64() (float64, bool) { return 0, false } 86 func (nl *LNilType) assertString() (string, bool) { return "", false } 87 func (nl *LNilType) assertFunction() (*LFunction, bool) { return nil, false } 88 89 var LNil = LValue(&LNilType{}) 90 91 type LBool bool 92 93 func (bl LBool) String() string { 94 if bool(bl) { 95 return "true" 96 } 97 return "false" 98 } 99 func (bl LBool) Type() LValueType { return LTBool } 100 func (bl LBool) assertFloat64() (float64, bool) { return 0, false } 101 func (bl LBool) assertString() (string, bool) { return "", false } 102 func (bl LBool) assertFunction() (*LFunction, bool) { return nil, false } 103 104 var LTrue = LBool(true) 105 var LFalse = LBool(false) 106 107 type LString string 108 109 func (st LString) String() string { return string(st) } 110 func (st LString) Type() LValueType { return LTString } 111 func (st LString) assertFloat64() (float64, bool) { return 0, false } 112 func (st LString) assertString() (string, bool) { return string(st), true } 113 func (st LString) assertFunction() (*LFunction, bool) { return nil, false } 114 115 // fmt.Formatter interface 116 func (st LString) Format(f fmt.State, c rune) { 117 switch c { 118 case 'd', 'i': 119 if nm, err := parseNumber(string(st)); err != nil { 120 defaultFormat(nm, f, 'd') 121 } else { 122 defaultFormat(string(st), f, 's') 123 } 124 default: 125 defaultFormat(string(st), f, c) 126 } 127 } 128 129 func (nm LNumber) String() string { 130 if isInteger(nm) { 131 return fmt.Sprint(int64(nm)) 132 } 133 return fmt.Sprint(float64(nm)) 134 } 135 136 func (nm LNumber) Type() LValueType { return LTNumber } 137 func (nm LNumber) assertFloat64() (float64, bool) { return float64(nm), true } 138 func (nm LNumber) assertString() (string, bool) { return "", false } 139 func (nm LNumber) assertFunction() (*LFunction, bool) { return nil, false } 140 141 // fmt.Formatter interface 142 func (nm LNumber) Format(f fmt.State, c rune) { 143 switch c { 144 case 'q', 's': 145 defaultFormat(nm.String(), f, c) 146 case 'b', 'c', 'd', 'o', 'x', 'X', 'U': 147 defaultFormat(int64(nm), f, c) 148 case 'e', 'E', 'f', 'F', 'g', 'G': 149 defaultFormat(float64(nm), f, c) 150 case 'i': 151 defaultFormat(int64(nm), f, 'd') 152 default: 153 if isInteger(nm) { 154 defaultFormat(int64(nm), f, c) 155 } else { 156 defaultFormat(float64(nm), f, c) 157 } 158 } 159 } 160 161 type LTable struct { 162 Metatable LValue 163 164 array []LValue 165 dict map[LValue]LValue 166 strdict map[string]LValue 167 keys []LValue 168 k2i map[LValue]int 169 } 170 171 func (tb *LTable) String() string { return fmt.Sprintf("table: %p", tb) } 172 func (tb *LTable) Type() LValueType { return LTTable } 173 func (tb *LTable) assertFloat64() (float64, bool) { return 0, false } 174 func (tb *LTable) assertString() (string, bool) { return "", false } 175 func (tb *LTable) assertFunction() (*LFunction, bool) { return nil, false } 176 177 type LFunction struct { 178 IsG bool 179 Env *LTable 180 Proto *FunctionProto 181 GFunction LGFunction 182 Upvalues []*Upvalue 183 } 184 type LGFunction func(*LState) int 185 186 func (fn *LFunction) String() string { return fmt.Sprintf("function: %p", fn) } 187 func (fn *LFunction) Type() LValueType { return LTFunction } 188 func (fn *LFunction) assertFloat64() (float64, bool) { return 0, false } 189 func (fn *LFunction) assertString() (string, bool) { return "", false } 190 func (fn *LFunction) assertFunction() (*LFunction, bool) { return fn, true } 191 192 type Global struct { 193 MainThread *LState 194 CurrentThread *LState 195 Registry *LTable 196 Global *LTable 197 198 builtinMts map[int]LValue 199 tempFiles []*os.File 200 gccount int32 201 } 202 203 type LState struct { 204 G *Global 205 Parent *LState 206 Env *LTable 207 Panic func(*LState) 208 Dead bool 209 Options Options 210 211 stop int32 212 reg *registry 213 stack *callFrameStack 214 alloc *allocator 215 currentFrame *callFrame 216 wrapped bool 217 uvcache *Upvalue 218 hasErrorFunc bool 219 mainLoop func(*LState, *callFrame) 220 ctx context.Context 221 } 222 223 func (ls *LState) String() string { return fmt.Sprintf("thread: %p", ls) } 224 func (ls *LState) Type() LValueType { return LTThread } 225 func (ls *LState) assertFloat64() (float64, bool) { return 0, false } 226 func (ls *LState) assertString() (string, bool) { return "", false } 227 func (ls *LState) assertFunction() (*LFunction, bool) { return nil, false } 228 229 type LUserData struct { 230 Value interface{} 231 Env *LTable 232 Metatable LValue 233 } 234 235 func (ud *LUserData) String() string { return fmt.Sprintf("userdata: %p", ud) } 236 func (ud *LUserData) Type() LValueType { return LTUserData } 237 func (ud *LUserData) assertFloat64() (float64, bool) { return 0, false } 238 func (ud *LUserData) assertString() (string, bool) { return "", false } 239 func (ud *LUserData) assertFunction() (*LFunction, bool) { return nil, false } 240 241 type LChannel chan LValue 242 243 func (ch LChannel) String() string { return fmt.Sprintf("channel: %p", ch) } 244 func (ch LChannel) Type() LValueType { return LTChannel } 245 func (ch LChannel) assertFloat64() (float64, bool) { return 0, false } 246 func (ch LChannel) assertString() (string, bool) { return "", false } 247 func (ch LChannel) assertFunction() (*LFunction, bool) { return nil, false }