diff --git a/.gitignore b/.gitignore index 09c6a39..2af31c2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -go-lang-lk \ No newline at end of file +go-lang-lk +*/*.lkc \ No newline at end of file diff --git a/binchunk/binary_chunk.go b/binchunk/binary_chunk.go index cc017c1..058b044 100644 --- a/binchunk/binary_chunk.go +++ b/binchunk/binary_chunk.go @@ -1,17 +1,12 @@ package binchunk import ( - "bytes" - "math" - "strconv" - "git.lolli.tech/lollipopkit/go-lang-lk/consts" jsoniter "github.com/json-iterator/go" ) var ( json = jsoniter.ConfigCompatibleWithStandardLibrary - VERSION, _ = strconv.ParseFloat(string(consts.VERSION), 64) ) const ( @@ -23,6 +18,13 @@ const ( TAG_LONG_STR = 0x14 ) +type binaryChunk struct { + Version string `json:"v"` + Sign string `json:"si"` + Hash string `json:"h"` + Proto *Prototype `json:"p"` +} + // function prototype type Prototype struct { Source string `json:"s"` // debug @@ -52,31 +54,22 @@ type LocVar struct { } func IsJsonChunk(data []byte) (bool, *Prototype) { - if len(data) < 9 { + var bin binaryChunk + err := json.Unmarshal(data, &bin) + if err != nil { return false, nil } - if !bytes.HasPrefix(data, []byte{'\x1b'}) { + if bin.Sign != consts.SIGNATURE || bin.Version != consts.VERSION { return false, nil } - if data[1] != byte(math.Float64bits(VERSION)) { - panic("version not match!") - } - data = data[9:] - var proto Prototype - err := json.Unmarshal(data, &proto) - return err == nil, &proto + return err == nil, bin.Proto } func (proto *Prototype) Dump() ([]byte, error) { - data, err := json.Marshal(proto) - if err != nil { - return nil, err + bin := &binaryChunk{ + Version: consts.VERSION, + Sign: consts.SIGNATURE, + Proto: proto, } - - v := math.Float64bits(VERSION) - by := []byte{'\x1b'} - by = append(by, byte(v)) - by = append(by, consts.SIGNATURE...) - data = append(by, data...) - return data, err + return json.Marshal(bin) } diff --git a/compiler/codegen/cg_block.go b/compiler/codegen/cg_block.go index 0ce5049..8639e0e 100644 --- a/compiler/codegen/cg_block.go +++ b/compiler/codegen/cg_block.go @@ -3,8 +3,8 @@ package codegen import . "git.lolli.tech/lollipopkit/go-lang-lk/compiler/ast" func cgBlock(fi *funcInfo, node *Block) { - for _, stat := range node.Stats { - cgStat(fi, stat) + for k := range node.Stats { + cgStat(fi, node.Stats[k]) } if node.RetExps != nil { @@ -36,12 +36,12 @@ func cgRetStat(fi *funcInfo, exps []Exp, lastLine int) { } multRet := isVarargOrFuncCall(exps[nExps-1]) - for i, exp := range exps { + for i := range exps { r := fi.allocReg() if i == nExps-1 && multRet { - cgExp(fi, exp, r, -1) + cgExp(fi, exps[i], r, -1) } else { - cgExp(fi, exp, r, 1) + cgExp(fi, exps[i], r, 1) } } fi.freeRegs(nExps) diff --git a/compiler/codegen/cg_exp.go b/compiler/codegen/cg_exp.go index 7a39fca..879aa11 100644 --- a/compiler/codegen/cg_exp.go +++ b/compiler/codegen/cg_exp.go @@ -67,8 +67,8 @@ func cgFuncDefExp(fi *funcInfo, node *FuncDefExp, a int) { subFI := newFuncInfo(fi, node) fi.subFuncs = append(fi.subFuncs, subFI) - for _, param := range node.ParList { - subFI.addLocVar(param, 0) + for i := range node.ParList { + subFI.addLocVar(node.ParList[i], 0) } cgBlock(subFI, node.Block) @@ -81,8 +81,8 @@ func cgFuncDefExp(fi *funcInfo, node *FuncDefExp, a int) { func cgTableConstructorExp(fi *funcInfo, node *TableConstructorExp, a int) { nArr := 0 - for _, keyExp := range node.KeyExps { - if keyExp == nil { + for i := range node.KeyExps { + if node.KeyExps[i] == nil { nArr++ } } @@ -93,10 +93,10 @@ func cgTableConstructorExp(fi *funcInfo, node *TableConstructorExp, a int) { fi.emitNewTable(node.Line, a, nArr, nExps-nArr) arrIdx := 0 - for i, keyExp := range node.KeyExps { + for i := range node.KeyExps { valExp := node.ValExps[i] - if keyExp == nil { + if node.KeyExps[i] == nil { arrIdx++ tmp := fi.allocReg() if i == nExps-1 && multRet { @@ -124,7 +124,7 @@ func cgTableConstructorExp(fi *funcInfo, node *TableConstructorExp, a int) { } b := fi.allocReg() - cgExp(fi, keyExp, b, 1) + cgExp(fi, node.KeyExps[i], b, 1) c := fi.allocReg() cgExp(fi, valExp, c, 1) fi.freeRegs(2) @@ -172,9 +172,9 @@ func cgBinopExp(fi *funcInfo, node *BinopExp, a int) { // r[a] := exp1 .. exp2 func cgConcatExp(fi *funcInfo, node *ConcatExp, a int) { - for _, subExp := range node.Exps { + for i := range node.Exps { a := fi.allocReg() - cgExp(fi, subExp, a, 1) + cgExp(fi, node.Exps[i], a, 1) } c := fi.usedRegs - 1 @@ -238,13 +238,13 @@ func prepFuncCall(fi *funcInfo, node *FuncCallExp, a int) int { fi.freeRegs(1) } } - for i, arg := range node.Args { + for i := range node.Args { tmp := fi.allocReg() - if i == nArgs-1 && isVarargOrFuncCall(arg) { + if i == nArgs-1 && isVarargOrFuncCall(node.Args[i]) { lastArgIsVarargOrFuncCall = true - cgExp(fi, arg, tmp, -1) + cgExp(fi, node.Args[i], tmp, -1) } else { - cgExp(fi, arg, tmp, 1) + cgExp(fi, node.Args[i], tmp, 1) } } fi.freeRegs(nArgs) diff --git a/compiler/codegen/cg_stat.go b/compiler/codegen/cg_stat.go index 7dd5247..6ce583e 100644 --- a/compiler/codegen/cg_stat.go +++ b/compiler/codegen/cg_stat.go @@ -85,16 +85,16 @@ func cgIfStat(fi *funcInfo, node *IfStat) { pcJmpToEnds := make([]int, len(node.Exps)) pcJmpToNextExp := -1 - for i, exp := range node.Exps { + for i := range node.Exps { if pcJmpToNextExp >= 0 { fi.fixSbx(pcJmpToNextExp, fi.pc()-pcJmpToNextExp) } oldRegs := fi.usedRegs - a, _ := expToOpArg(fi, exp, ARG_REG) + a, _ := expToOpArg(fi, node.Exps[i], ARG_REG) fi.usedRegs = oldRegs - line := lastLineOf(exp) + line := lastLineOf(node.Exps[i]) fi.emitTest(line, a, 0) pcJmpToNextExp = fi.emitJmp(line, 0, 0) @@ -110,8 +110,8 @@ func cgIfStat(fi *funcInfo, node *IfStat) { } } - for _, pc := range pcJmpToEnds { - fi.fixSbx(pc, fi.pc()-pc) + for i := range pcJmpToEnds { + fi.fixSbx(pcJmpToEnds[i], fi.pc()-pcJmpToEnds[i]) } } @@ -155,8 +155,8 @@ func cgForInStat(fi *funcInfo, node *ForInStat) { NameList: []string{forGeneratorVar, forStateVar, forControlVar}, ExpList: node.ExpList, }) - for _, name := range node.NameList { - fi.addLocVar(name, fi.pc()+2) + for i := range node.NameList { + fi.addLocVar(node.NameList[i], fi.pc()+2) } pcJmpToTFC := fi.emitJmp(node.LineOfDo, 0, 0) @@ -182,30 +182,30 @@ func cgLocalVarDeclStat(fi *funcInfo, node *LocalVarDeclStat) { oldRegs := fi.usedRegs if nExps == nNames { - for _, exp := range exps { + for i := range exps { a := fi.allocReg() - cgExp(fi, exp, a, 1) + cgExp(fi, exps[i], a, 1) } } else if nExps > nNames { - for i, exp := range exps { + for i := range exps { a := fi.allocReg() - if i == nExps-1 && isVarargOrFuncCall(exp) { - cgExp(fi, exp, a, 0) + if i == nExps-1 && isVarargOrFuncCall(exps[i]) { + cgExp(fi, exps[i], a, 0) } else { - cgExp(fi, exp, a, 1) + cgExp(fi, exps[i], a, 1) } } } else { // nNames > nExps multRet := false - for i, exp := range exps { + for i := range exps { a := fi.allocReg() - if i == nExps-1 && isVarargOrFuncCall(exp) { + if i == nExps-1 && isVarargOrFuncCall(exps[i]) { multRet = true n := nNames - nExps + 1 - cgExp(fi, exp, a, n) + cgExp(fi, exps[i], a, n) fi.allocRegs(n - 1) } else { - cgExp(fi, exp, a, 1) + cgExp(fi, exps[i], a, 1) } } if !multRet { @@ -217,8 +217,8 @@ func cgLocalVarDeclStat(fi *funcInfo, node *LocalVarDeclStat) { fi.usedRegs = oldRegs startPC := fi.pc() + 1 - for _, name := range node.NameList { - fi.addLocVar(name, startPC) + for i := range node.NameList { + fi.addLocVar(node.NameList[i], startPC) } } @@ -232,14 +232,14 @@ func cgAssignStat(fi *funcInfo, node *AssignStat) { vRegs := make([]int, nVars) oldRegs := fi.usedRegs - for i, exp := range node.VarList { - if taExp, ok := exp.(*TableAccessExp); ok { + for i := range node.VarList { + if taExp, ok := node.VarList[i].(*TableAccessExp); ok { tRegs[i] = fi.allocReg() cgExp(fi, taExp.PrefixExp, tRegs[i], 1) kRegs[i] = fi.allocReg() cgExp(fi, taExp.KeyExp, kRegs[i], 1) } else { - name := exp.(*NameExp).Name + name := node.VarList[i].(*NameExp).Name if fi.slotOfLocVar(name) < 0 && fi.indexOfUpval(name) < 0 { // global var kRegs[i] = -1 @@ -254,25 +254,25 @@ func cgAssignStat(fi *funcInfo, node *AssignStat) { } if nExps >= nVars { - for i, exp := range exps { + for i := range exps { a := fi.allocReg() - if i >= nVars && i == nExps-1 && isVarargOrFuncCall(exp) { - cgExp(fi, exp, a, 0) + if i >= nVars && i == nExps-1 && isVarargOrFuncCall(exps[i]) { + cgExp(fi, exps[i], a, 0) } else { - cgExp(fi, exp, a, 1) + cgExp(fi, exps[i], a, 1) } } } else { // nVars > nExps multRet := false - for i, exp := range exps { + for i := range exps { a := fi.allocReg() - if i == nExps-1 && isVarargOrFuncCall(exp) { + if i == nExps-1 && isVarargOrFuncCall(exps[i]) { multRet = true n := nVars - nExps + 1 - cgExp(fi, exp, a, n) + cgExp(fi, exps[i], a, n) fi.allocRegs(n - 1) } else { - cgExp(fi, exp, a, 1) + cgExp(fi, exps[i], a, 1) } } if !multRet { @@ -283,8 +283,8 @@ func cgAssignStat(fi *funcInfo, node *AssignStat) { } lastLine := node.LastLine - for i, exp := range node.VarList { - if nameExp, ok := exp.(*NameExp); ok { + for i := range node.VarList { + if nameExp, ok := node.VarList[i].(*NameExp); ok { varName := nameExp.Name if a := fi.slotOfLocVar(varName); a >= 0 { fi.emitMove(lastLine, a, vRegs[i]) diff --git a/compiler/codegen/fi2proto.go b/compiler/codegen/fi2proto.go index 7fff7d2..b2e79e8 100644 --- a/compiler/codegen/fi2proto.go +++ b/compiler/codegen/fi2proto.go @@ -32,27 +32,27 @@ func toProto(fi *funcInfo) *Prototype { func toProtos(fis []*funcInfo) []*Prototype { protos := make([]*Prototype, len(fis)) - for i, fi := range fis { - protos[i] = toProto(fi) + for i := range fis { + protos[i] = toProto(fis[i]) } return protos } func getConstants(fi *funcInfo) []interface{} { consts := make([]interface{}, len(fi.constants)) - for k, idx := range fi.constants { - consts[idx] = k + for k := range fi.constants { + consts[fi.constants[k]] = k } return consts } func getLocVars(fi *funcInfo) []LocVar { locVars := make([]LocVar, len(fi.locVars)) - for i, locVar := range fi.locVars { + for i := range fi.locVars { locVars[i] = LocVar{ - VarName: locVar.name, - StartPC: uint32(locVar.startPC), - EndPC: uint32(locVar.endPC), + VarName: fi.locVars[i].name, + StartPC: uint32(fi.locVars[i].startPC), + EndPC: uint32(fi.locVars[i].endPC), } } return locVars @@ -60,11 +60,11 @@ func getLocVars(fi *funcInfo) []LocVar { func getUpvalues(fi *funcInfo) []Upvalue { upvals := make([]Upvalue, len(fi.upvalues)) - for _, uv := range fi.upvalues { - if uv.locVarSlot >= 0 { // instack - upvals[uv.index] = Upvalue{1, byte(uv.locVarSlot)} + for i := range fi.upvalues { + if fi.upvalues[i].locVarSlot >= 0 { // instack + upvals[fi.upvalues[i].index] = Upvalue{1, byte(fi.upvalues[i].locVarSlot)} } else { - upvals[uv.index] = Upvalue{0, byte(uv.upvalIndex)} + upvals[fi.upvalues[i].index] = Upvalue{0, byte(fi.upvalues[i].upvalIndex)} } } return upvals @@ -72,8 +72,8 @@ func getUpvalues(fi *funcInfo) []Upvalue { func getUpvalueNames(fi *funcInfo) []string { names := make([]string, len(fi.upvalues)) - for name, uv := range fi.upvalues { - names[uv.index] = name + for name := range fi.upvalues { + names[fi.upvalues[name].index] = name } return names } diff --git a/compiler/codegen/func_info.go b/compiler/codegen/func_info.go index 9742bbe..560d807 100644 --- a/compiler/codegen/func_info.go +++ b/compiler/codegen/func_info.go @@ -142,17 +142,17 @@ func (self *funcInfo) exitScope(endPC int) { self.breaks = self.breaks[:len(self.breaks)-1] a := self.getJmpArgA() - for _, pc := range pendingBreakJmps { - sBx := self.pc() - pc + for i := range pendingBreakJmps { + sBx := self.pc() - pendingBreakJmps[i] i := (sBx+MAXARG_sBx)<<14 | a<<6 | OP_JMP - self.insts[pc] = uint32(i) + self.insts[pendingBreakJmps[i]] = uint32(i) } self.scopeLv-- - for _, locVar := range self.locNames { - if locVar.scopeLv > self.scopeLv { // out of scope - locVar.endPC = endPC - self.removeLocVar(locVar) + for i := range self.locNames { + if self.locNames[i].scopeLv > self.scopeLv { // out of scope + self.locNames[i].endPC = endPC + self.removeLocVar(self.locNames[i]) } } } @@ -234,9 +234,9 @@ func (self *funcInfo) closeOpenUpvals(line int) { func (self *funcInfo) getJmpArgA() int { hasCapturedLocVars := false minSlotOfLocVars := self.maxRegs - for _, locVar := range self.locNames { - if locVar.scopeLv == self.scopeLv { - for v := locVar; v != nil && v.scopeLv == self.scopeLv; v = v.prev { + for i := range self.locNames { + if self.locNames[i].scopeLv == self.scopeLv { + for v := self.locNames[i]; v != nil && v.scopeLv == self.scopeLv; v = v.prev { if v.captured { hasCapturedLocVars = true } diff --git a/compiler/compiler.go b/compiler/compiler.go index b09cabd..d723e8c 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -15,7 +15,7 @@ func Compile(chunk, chunkName string) *binchunk.Prototype { func setSource(proto *binchunk.Prototype, chunkName string) { proto.Source = chunkName - for _, f := range proto.Protos { - setSource(f, chunkName) + for k := range proto.Protos { + setSource(proto.Protos[k], chunkName) } } diff --git a/compiler/parser/parser.go b/compiler/parser/parser.go index 2cc7923..de30cd2 100644 --- a/compiler/parser/parser.go +++ b/compiler/parser/parser.go @@ -28,8 +28,8 @@ func Parse(chunk, chunkName string) *Block { } func beforeParse(chunk string) string { - for k, v := range replaceRules { - chunk = v.ReplaceAllString(chunk, k) + for k := range replaceRules { + chunk = replaceRules[k].ReplaceAllString(chunk, k) } return chunk } diff --git a/consts/lang.go b/consts/lang.go index ccc15f6..684608a 100644 --- a/consts/lang.go +++ b/consts/lang.go @@ -1,6 +1,6 @@ package consts var ( - VERSION = []byte(`0.1`) - SIGNATURE = []byte(`LANG_LK`) + VERSION = `0.0.1` + SIGNATURE = `LANG_LK` ) \ No newline at end of file diff --git a/main.go b/main.go index 4cb1b6c..8037b53 100644 --- a/main.go +++ b/main.go @@ -19,25 +19,47 @@ func main() { panic("no input file") } - if !*compile { - ls := state.New() - ls.OpenLibs() - ls.LoadFile(file) - ls.Call(0, -1) - } else { + compiledFile := strings.Replace(file, ".lk", ".lkc", 1) + compiledData, _ := ioutil.ReadFile(compiledFile) + + if !exist(compiledFile) || sourceChanged(file, compiledFile) { data, err := ioutil.ReadFile(file) if err != nil { panic(err) } bin := compiler.Compile(string(data), file) - f, err := os.Create(strings.Replace(file, ".lk", ".lkc", 1)) + f, err := os.Create(compiledFile) if err != nil { panic(err) } - data, err = bin.Dump() + compiledData, err = bin.Dump() if err != nil { panic(err) } - f.Write(data) + f.Write(compiledData) + } + + if !*compile { + ls := state.New() + ls.OpenLibs() + ls.Load(compiledData, file, "bt") + ls.Call(0, -1) + } +} + +func exist(path string) bool { + _, err := os.Stat(path) + return !os.IsNotExist(err) +} + +func sourceChanged(source, compiled string) bool { + s, err := os.Stat(source) + if err != nil { + panic(err) + } + c, err := os.Stat(compiled) + if err != nil { + panic(err) } + return s.ModTime().After(c.ModTime()) } diff --git a/state/api_vm.go b/state/api_vm.go index 0852e96..13b0b89 100644 --- a/state/api_vm.go +++ b/state/api_vm.go @@ -46,9 +46,9 @@ func (self *luaState) LoadProto(idx int) { closure := newLuaClosure(subProto) stack.push(closure) - for i, uvInfo := range subProto.Upvalues { - uvIdx := int(uvInfo.Idx) - if uvInfo.Instack == 1 { + for i := range subProto.Upvalues { + uvIdx := int(subProto.Upvalues[i].Idx) + if subProto.Upvalues[i].Instack == 1 { if stack.openuvs == nil { stack.openuvs = map[int]*upvalue{} } @@ -66,10 +66,10 @@ func (self *luaState) LoadProto(idx int) { } func (self *luaState) CloseUpvalues(a int) { - for i, openuv := range self.stack.openuvs { + for i := range self.stack.openuvs { if i >= a-1 { - val := *openuv.val - openuv.val = &val + val := *self.stack.openuvs[i].val + self.stack.openuvs[i].val = &val delete(self.stack.openuvs, i) } } diff --git a/state/auxlib.go b/state/auxlib.go index 404c3e0..b2585a3 100644 --- a/state/auxlib.go +++ b/state/auxlib.go @@ -286,8 +286,8 @@ func (self *luaState) OpenLibs() { "re": stdlib.OpenReLib, } - for name, fun := range libs { - self.RequireF(name, fun, true) + for name := range libs { + self.RequireF(name, libs[name], true) self.Pop(1) } } @@ -329,12 +329,12 @@ func (self *luaState) NewLibTable(l FuncReg) { // http://www.lua.org/manual/5.3/manual.html#luaL_setfuncs func (self *luaState) SetFuncs(l FuncReg, nup int) { self.CheckStack2(nup, "too many upvalues") - for name, fun := range l { /* fill the table with given functions */ + for name := range l { /* fill the table with given functions */ for i := 0; i < nup; i++ { /* copy upvalues to the top */ self.PushValue(-nup) } // r[-(nup+2)][name]=fun - self.PushGoClosure(fun, nup) /* closure with those upvalues */ + self.PushGoClosure(l[name], nup) /* closure with those upvalues */ self.SetField(-(nup + 2), name) } self.Pop(nup) /* remove upvalues */ diff --git a/state/lua_table.go b/state/lua_table.go index be0d9e4..179666f 100644 --- a/state/lua_table.go +++ b/state/lua_table.go @@ -135,14 +135,14 @@ func (self *luaTable) nextKey(key luaValue) luaValue { func (self *luaTable) initKeys() { self.keys = make(map[luaValue]luaValue) var key luaValue = nil - for i, v := range self.arr { - if v != nil { + for i := range self.arr { + if self.arr[i] != nil { self.keys[key] = int64(i + 1) key = int64(i + 1) } } - for k, v := range self._map { - if v != nil { + for k := range self._map { + if self._map[k] != nil { self.keys[key] = k key = k } diff --git a/state/lua_table.go.new b/state/lua_table.go.new new file mode 100644 index 0000000..7a095e3 --- /dev/null +++ b/state/lua_table.go.new @@ -0,0 +1,112 @@ +package state + +import ( + "fmt" + "math" + "sync" +) + +type kv struct { + key any + val any +} +type luaTable struct { + metatable *luaTable + list []kv + lock *sync.RWMutex +} + +func newLuaTable(nArr, nRec int) *luaTable { + t := &luaTable{ + list: make([]kv, 0), + lock: new(sync.RWMutex), + } + return t +} + +func (self *luaTable) hasMetafield(fieldName string) bool { + return self.metatable != nil && + self.metatable.get(fieldName) != nil +} + +func (self *luaTable) len() int { + self.lock.RLock() + defer self.lock.RUnlock() + return len(self.list) +} + +func (self *luaTable) get(key luaValue) luaValue { + self.lock.RLock() + defer self.lock.RUnlock() + switch key.(type) { + case nil: + return nil + case float64, float32, int, int64: + idx, ok := key.(int64) + if !ok { + panic(fmt.Sprintf("invalid index %v", key)) + } + if idx >= 1 && idx <= int64(len(self.list)) { + return self.list[idx-1] + } + default: + for _, kv := range self.list { + if kv.key == key { + return kv.val + } + } + } + return nil +} + +func (self *luaTable) put(key, val luaValue) { + if key == nil { + panic("table index is nil!") + } + if f, ok := key.(float64); ok && math.IsNaN(f) { + panic("table index is NaN!") + } + + delete := key == nil + + self.lock.Lock() + defer self.lock.Unlock() + switch key.(type) { + case float64, float32, int, int64: + idx, ok := key.(int64) + if !ok { + panic(fmt.Sprintf("invalid index %v", key)) + } + if idx >= 1 && idx <= int64(len(self.list)) { + if delete { + self.list = append(self.list[:idx-1], self.list[idx:]...) + } else { + self.list[idx-1] = kv{key, val} + } + } + default: + for i, item := range self.list { + if item.key == key { + if delete { + self.list = append(self.list[:i], self.list[i+1:]...) + } else { + self.list[i] = kv{key, val} + } + } + } + } +} + +func (self *luaTable) nextKey(key luaValue) luaValue { + self.lock.RLock() + defer self.lock.RUnlock() + for idx, item := range self.list { + if item.key == key { + if idx == len(self.list)-1 { + return nil + } + return self.list[idx+1].key + } + } + return nil +} diff --git a/stdlib/lib_basic.go b/stdlib/lib_basic.go index 79fefe6..b5c194d 100644 --- a/stdlib/lib_basic.go +++ b/stdlib/lib_basic.go @@ -62,8 +62,8 @@ func baseKV(ls LkState) int { keys = append(keys, k) } values := make([]any, 0, len(tb)) - for _, v := range tb { - values = append(values, v) + for k := range tb { + values = append(values, tb[k]) } pushList(ls, keys) pushList(ls, values) diff --git a/stdlib/lib_http.go b/stdlib/lib_http.go index 88a4ab3..c05ce2b 100644 --- a/stdlib/lib_http.go +++ b/stdlib/lib_http.go @@ -11,6 +11,8 @@ import ( jsoniter "github.com/json-iterator/go" ) +type luaMap map[string]any + var ( client = http.Client{} json = jsoniter.ConfigCompatibleWithStandardLibrary @@ -27,15 +29,16 @@ func OpenHttpLib(ls LkState) int { return 1 } -func httpDo(method, url string, headers map[string]any, body io.Reader) (int, string, error) { +func httpDo(method, url string, headers luaMap, body io.Reader) (int, string, error) { request, err := http.NewRequest(method, url, body) if err != nil { return 0, "", err } - request.Header.Set("user-agent", "lk-http/"+string(consts.VERSION)) - for k, v := range headers { - request.Header.Set(k, v.(string)) + request.Header.Set("user-agent", "lk-http/"+consts.VERSION) + // 仅遍历下标,性能更佳 + for k := range headers { + request.Header.Set(k, headers[k].(string)) } resp, err := client.Do(request) @@ -52,7 +55,7 @@ func httpDo(method, url string, headers map[string]any, body io.Reader) (int, st func httpGet(ls LkState) int { url := ls.CheckString(1) - headers := OptTable(ls, 2, map[string]any{}) + headers := OptTable(ls, 2, luaMap{}) code, data, err := httpDo("GET", url, headers, nil) if err != nil { ls.PushInteger(0) @@ -66,7 +69,7 @@ func httpGet(ls LkState) int { func httpPost(ls LkState) int { url := ls.CheckString(1) - headers := OptTable(ls, 2, map[string]any{}) + headers := OptTable(ls, 2, luaMap{}) bodyStr := ls.OptString(3, "") body := func() io.Reader { @@ -92,7 +95,7 @@ func httpPost(ls LkState) int { func httpReq(ls LkState) int { method := strings.ToUpper(ls.CheckString(1)) url := ls.CheckString(2) - headers := OptTable(ls, 3, map[string]any{}) + headers := OptTable(ls, 3, luaMap{}) bodyStr := ls.OptString(4, "") body := func() io.Reader { @@ -114,16 +117,16 @@ func httpReq(ls LkState) int { return 2 } -func genReqTable(r *http.Request) (map[string]any, error) { +func genReqTable(r *http.Request) (luaMap, error) { body, err := ioutil.ReadAll(r.Body) if err != nil { return nil, err } - headers := map[string]any{} - for k, v := range r.Header { - headers[k] = v + headers := luaMap{} + for k := range r.Header { + headers[k] = r.Header[k] } - return map[string]any{ + return luaMap{ "method": r.Method, "url": r.URL.String(), "headers": headers, diff --git a/stdlib/lib_os.go b/stdlib/lib_os.go index 366ebe6..a602237 100644 --- a/stdlib/lib_os.go +++ b/stdlib/lib_os.go @@ -48,8 +48,8 @@ func osDir(ls LkState) int { return 2 } filenames := make([]any, 0, len(files)) - for _, file := range files { - filenames = append(filenames, file.Name()) + for i := range files { + filenames = append(filenames, files[i].Name()) } pushList(ls, filenames) ls.PushNil() diff --git a/stdlib/lib_package.go b/stdlib/lib_package.go index 64e6b3e..c0d3fff 100644 --- a/stdlib/lib_package.go +++ b/stdlib/lib_package.go @@ -66,9 +66,9 @@ func createSearchersTable(ls LkState) { /* create 'searchers' table */ ls.CreateTable(len(searchers), 0) /* fill it with predefined searchers */ - for idx, searcher := range searchers { + for idx := range searchers { ls.PushValue(-2) /* set 'package' as upvalue for all searchers */ - ls.PushGoClosure(searcher, 1) + ls.PushGoClosure(searchers[idx], 1) ls.RawSetI(-2, int64(idx+1)) } ls.SetField(-2, "searchers") /* put it in field 'searchers' */ diff --git a/stdlib/lib_string.go b/stdlib/lib_string.go index 3ab16d6..94a6fab 100644 --- a/stdlib/lib_string.go +++ b/stdlib/lib_string.go @@ -238,13 +238,13 @@ func strFormat(ls LkState) int { argIdx := 1 arr := parseFmtStr(fmtStr) - for i, s := range arr { - if s[0] == '%' { - if s == "%%" { + for i := range arr { + if arr[i][0] == '%' { + if arr[i] == "%%" { arr[i] = "%" } else { argIdx += 1 - arr[i] = _fmtArg(s, ls, argIdx) + arr[i] = _fmtArg(arr[i], ls, argIdx) } } } diff --git a/stdlib/lib_utf8.go b/stdlib/lib_utf8.go index 133fb47..4e37d0f 100644 --- a/stdlib/lib_utf8.go +++ b/stdlib/lib_utf8.go @@ -161,8 +161,8 @@ func _encodeUtf8(codePoints []rune) string { buf := make([]byte, 6) str := make([]byte, 0, len(codePoints)) - for _, cp := range codePoints { - n := utf8.EncodeRune(buf, cp) + for i := range codePoints { + n := utf8.EncodeRune(buf, codePoints[i]) str = append(str, buf[0:n]...) } diff --git a/stdlib/utils.go b/stdlib/utils.go index 30b4a96..c60c9f2 100644 --- a/stdlib/utils.go +++ b/stdlib/utils.go @@ -33,8 +33,10 @@ func pushValue(ls LkState, item any) { return case reflect.Map: items := make(map[string]any) - for _, key := range v.MapKeys() { - items[key.String()] = v.MapIndex(key).Interface() + keys := v.MapKeys() + for idx := range keys { + key := &keys[idx] + items[(*key).String()] = v.MapIndex(*key).Interface() } pushTable(ls, items) return @@ -45,16 +47,16 @@ func pushValue(ls LkState, item any) { func pushList(ls LkState, items []any) { ls.CreateTable(len(items), 0) - for i, item := range items { - pushValue(ls, item) + for i := range items { + pushValue(ls, items[i]) ls.SetI(-2, int64(i+1)) } } func pushTable(ls LkState, items map[string]any) { ls.CreateTable(0, len(items)+1) - for k, v := range items { - pushValue(ls, v) + for k := range items { + pushValue(ls, items[k]) ls.SetField(-2, k) } } diff --git a/test/basic.lkc b/test/basic.lkc deleted file mode 100644 index c6351be..0000000 --- a/test/basic.lkc +++ /dev/null @@ -1 +0,0 @@ -LANG_LK{"s":"test/basic.lk","ld":0,"lld":0,"np":0,"iv":1,"ms":6,"c":[4194310,16449,16793636,44,64,2168504351,2147483678,16579,8388803,25165987,2147549214,2185314335,2147483678,16579,8388803,25165952,16793700,64,4292806,29474951,32961,16777380,16484,64,4292806,29474951,32961,16777380,16484,131137,8388892,2223046753,2147483678,16579,8388803,25165987,2147500062,164033,25165952,162,2147532830,4374662,196801,8388892,25182372,4374662,65729,49409,213313,33570980,8388646],"cs":["import","test/import",1,2,3,4,"test2","add2","abc\n",0,"","print","hello",3],"us":[{"is":1,"idx":0}],"ps":[{"s":"test/basic.lk","ld":3,"lld":3,"np":1,"iv":0,"ms":3,"c":[4194374,128,16793700,8388646],"cs":["print"],"us":[{"is":0,"idx":0}],"ps":[],"li":[3,3,3,3],"lvs":[{"vn":"e","spc":0,"epc":4}],"uns":["_ENV"]}],"li":[1,1,1,3,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,6,6,6,6,6,6,13,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,19,19,19,19,19,19],"lvs":[{"vn":"func","spc":4,"epc":51},{"vn":"long","spc":30,"epc":51}],"uns":["_ENV"]} \ No newline at end of file diff --git a/test/http/req.lkc b/test/http/req.lkc deleted file mode 100644 index 304cefe..0000000 --- a/test/http/req.lkc +++ /dev/null @@ -1 +0,0 @@ -LANG_LK{"s":"test/http/req.lk","ld":0,"lld":0,"np":0,"iv":1,"ms":9,"c":[4194374,12599303,32833,16523,49345,65793,25231498,82113,33603620,4292742,8388800,16793764,4194502,29474951,131265,147713,16715,49537,65985,50446666,82305,41992356,4292870,16777536,4358598,63095175,25166272,197121,25166244,16676,8388646],"cs":["http","post","http://httpbin.org/post","accept","application/json","{\"foo\": \"bar\"}","print","req","delete","http://httpbin.org/delete","json","get","json.foo"],"us":[{"is":1,"idx":0}],"ps":[],"li":[1,1,2,2,3,3,3,4,1,6,6,6,8,8,9,10,10,11,11,11,12,8,14,14,14,14,14,14,14,14,14],"lvs":[{"vn":"_","spc":9,"epc":31},{"vn":"resp","spc":9,"epc":0},{"vn":"code","spc":22,"epc":31},{"vn":"resp","spc":22,"epc":31}],"uns":["_ENV"]} \ No newline at end of file diff --git a/test/table.lk b/test/table.lk index 29b1d11..26bf9e6 100644 --- a/test/table.lk +++ b/test/table.lk @@ -1,4 +1,5 @@ shy tb = {5, 'd': 4, 'c': num('2')} +print(tb[1]) shy keys, vals = kv(tb) for i, k in keys {