From b5186cf530544f7e64e7a6c97f41dccdd2b01f83 Mon Sep 17 00:00:00 2001 From: renbou Date: Thu, 7 Jul 2022 02:50:37 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20replace=20manual=20type=20checking?= =?UTF-8?q?=20with=20VMFuncXParams=20VMFuncOneParam,=20VMFuncTwoParams,=20?= =?UTF-8?q?VMFuncThreeParams=20=D0=BF=D1=80=D0=B8=D0=BD=D0=B8=D0=BC=D0=B0?= =?UTF-8?q?=D1=8E=D1=82=20=D0=BD=D0=B5=D1=81=D0=BA=D0=BE=D0=BB=D1=8C=D0=BA?= =?UTF-8?q?=D0=BE=20=D0=B6=D0=B5=D0=BD=D0=B5=D1=80=D0=B8=D0=BA=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=BA=D0=BE=D1=82=D0=BE=D1=80=D1=8B=D0=B5=20=D1=83=D0=BA?= =?UTF-8?q?=D0=B0=D0=B7=D1=8B=D0=B2=D0=B0=D1=8E=D1=82=20=D0=BD=D0=B5=D0=BE?= =?UTF-8?q?=D0=B1=D1=85=D0=BE=D0=B4=D0=B8=D0=BC=D1=8B=D0=B5=20=D1=82=D0=B8?= =?UTF-8?q?=D0=BF=D1=8B=20=D0=B0=D1=80=D0=B3=D1=83=D0=BC=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/launch.json | 4 +- ast/expr.go | 12 +- bincode/binstmt/binstmt.go | 4 +- bincode/binvm.go | 14 +- core/core.go | 299 ++++++++++++++++------------------ core/coreboltdb.go | 14 +- core/corebool.go | 8 +- core/corechan.go | 12 +- core/coreclient.go | 6 +- core/coreconn.go | 6 +- core/coredecnum.go | 8 +- core/coreenv.go | 43 +++-- core/coreerrors.go | 43 +++++ core/corefile.go | 4 + core/corefunc.go | 55 ++++++- core/corehttp.go | 8 +- core/coreifaces.go | 44 ++--- core/coreint.go | 8 +- core/coremap.go | 14 +- core/coremetaobj.go | 18 +- core/corercon.go | 4 + core/coreserver.go | 6 +- core/coreservice.go | 4 +- core/coreslice.go | 23 ++- core/corestring.go | 10 +- core/coretable.go | 18 +- core/coretextdocument.go | 4 + core/coretime.go | 12 +- core/coretypes.go | 23 +-- core/corewaitgroup.go | 2 +- go.mod | 2 +- services/gonecsvc/gonecsvc.go | 5 +- test/core/string_test.gnc | 1 + 33 files changed, 432 insertions(+), 306 deletions(-) create mode 100644 test/core/string_test.gnc diff --git a/.vscode/launch.json b/.vscode/launch.json index 7ec8f6f..e6025ab 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,9 +10,9 @@ "request": "launch", "mode": "auto", "program": "${fileDirname}", - "args": ["core/slice_test.gnc"], + "args": [], "env": {}, - "cwd": "./test" + "cwd": "" } ] } diff --git a/ast/expr.go b/ast/expr.go index 35b4e2d..7589c0f 100644 --- a/ast/expr.go +++ b/ast/expr.go @@ -705,8 +705,12 @@ type AssocExpr struct { } func (x *AssocExpr) Simplify() Expr { - x.Lhs = x.Lhs.Simplify() - x.Rhs = x.Rhs.Simplify() + if x.Lhs != nil { + x.Lhs = x.Lhs.Simplify() + } + if x.Rhs != nil { + x.Rhs = x.Rhs.Simplify() + } return x } @@ -764,7 +768,7 @@ func (x *ConstExpr) Simplify() Expr { } func (e *ConstExpr) BinTo(bins *binstmt.BinStmts, reg int, lid *int, inStmt bool, maxreg *int) { - var v core.VMValuer + var v core.VMValue switch names.FastToLower(e.Value) { case "истина", "true": @@ -962,7 +966,7 @@ func (e *MakeArrayExpr) BinTo(bins *binstmt.BinStmts, reg int, lid *int, inStmt // хранит реальное значение, рассчитанное на этапе оптимизации AST type NativeExpr struct { ExprImpl - Value core.VMValuer + Value core.VMValue } func (x *NativeExpr) Simplify() Expr { diff --git a/bincode/binstmt/binstmt.go b/bincode/binstmt/binstmt.go index 1921f0c..3d85b11 100644 --- a/bincode/binstmt/binstmt.go +++ b/bincode/binstmt/binstmt.go @@ -222,7 +222,7 @@ type BinLOAD struct { BinStmtImpl Reg int - Val core.VMValuer + Val core.VMValue IsId bool } @@ -241,7 +241,7 @@ func (v BinLOAD) String() string { return fmt.Sprintf("LOAD r%d, %#v", v.Reg, v.Val) } -func NewBinLOAD(reg int, val core.VMValuer, isid bool, e pos.Pos) *BinLOAD { +func NewBinLOAD(reg int, val core.VMValue, isid bool, e pos.Pos) *BinLOAD { v := &BinLOAD{ Reg: reg, Val: val, diff --git a/bincode/binvm.go b/bincode/binvm.go index 9455fbb..3e0e0e3 100644 --- a/bincode/binvm.go +++ b/bincode/binvm.go @@ -77,7 +77,7 @@ func putRegs(sl core.VMSlice) { } // Run запускает код на исполнение, например, после загрузки из файла -func Run(stmts binstmt.BinCode, env *core.Env) (retval core.VMValuer, reterr error) { +func Run(stmts binstmt.BinCode, env *core.Env) (retval core.VMValue, reterr error) { defer func() { // если это не паника из кода языка // if os.Getenv("GONEC_DEBUG") == "" { @@ -120,7 +120,6 @@ func Run(stmts binstmt.BinCode, env *core.Env) (retval core.VMValuer, reterr err panic(err) } rets.Append(rv) - return nil } else { _, bins, err := ParseSrc(string(body)) if err != nil { @@ -137,7 +136,6 @@ func Run(stmts binstmt.BinCode, env *core.Env) (retval core.VMValuer, reterr err panic(err) } rets.Append(rv) - return nil } return nil } @@ -153,7 +151,7 @@ func Run(stmts binstmt.BinCode, env *core.Env) (retval core.VMValuer, reterr err } // RunWorker исполняет кусок кода, начиная с инструкции idx -func RunWorker(stmts binstmt.BinStmts, labels []int, numofregs int, env *core.Env, idx int) (retval core.VMValuer, reterr error) { +func RunWorker(stmts binstmt.BinStmts, labels []int, numofregs int, env *core.Env, idx int) (retval core.VMValue, reterr error) { defer func() { // если это не паника из кода языка // if os.Getenv("GONEC_DEBUG") == "" { @@ -344,7 +342,7 @@ func RunWorker(stmts binstmt.BinStmts, labels []int, numofregs int, env *core.En var err error // функцию на языке Гонец можно вызывать прямо с аргументами из слайса в регистре - var fgnc core.VMValuer + var fgnc core.VMValue var argsl core.VMSlice if s.Name == 0 { fgnc = registers[s.RegArgs] @@ -863,7 +861,7 @@ func RunWorker(stmts binstmt.BinStmts, labels []int, numofregs int, env *core.En } else { v = reflect.Zero(rt) } - if vv, ok := v.Interface().(core.VMValuer); ok { + if vv, ok := v.Interface().(core.VMValue); ok { invalidArgs := false if vobj, ok := vv.(core.VMMetaObject); ok { vobj.VMInit(vobj) @@ -956,7 +954,7 @@ func RunWorker(stmts binstmt.BinStmts, labels []int, numofregs int, env *core.En case *binstmt.BinINC: v := registers[s.Reg] - var x core.VMValuer + var x core.VMValue if vv, ok := v.(core.VMInt); ok { x = core.VMInt(int64(vv) + 1) } else if vv, ok := v.(core.VMDecNum); ok { @@ -966,7 +964,7 @@ func RunWorker(stmts binstmt.BinStmts, labels []int, numofregs int, env *core.En case *binstmt.BinDEC: v := registers[s.Reg] - var x core.VMValuer + var x core.VMValue if vv, ok := v.(core.VMInt); ok { x = core.VMInt(int64(vv) - 1) } else if vv, ok := v.(core.VMDecNum); ok { diff --git a/core/core.go b/core/core.go index aa26cf1..ea8a435 100644 --- a/core/core.go +++ b/core/core.go @@ -47,13 +47,10 @@ func LoadAllBuiltins(env *Env) { // Import общая стандартная бибилиотека func Import(env *Env) *Env { - env.DefineS("длина", VMFuncMustParams(1, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + env.DefineS("длина", VMFuncOneParam[VMIndexer](func(args VMSlice, rets *VMSlice, envout *(*Env)) error { *envout = env - if rv, ok := args[0].(VMIndexer); ok { - rets.Append(rv.Length()) - return nil - } - return VMErrorNeedLength + rets.Append(args[0].(VMIndexer).Length()) + return nil })) env.DefineS("диапазон", VMFunc(func(args VMSlice, rets *VMSlice, envout *(*Env)) error { @@ -111,23 +108,17 @@ func Import(env *Env) *Env { return nil })) - env.DefineS("прошловременис", VMFuncMustParams(1, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + env.DefineS("прошловременис", VMFuncOneParam[VMDateTimer](func(args VMSlice, rets *VMSlice, envout *(*Env)) error { *envout = env - if rv, ok := args[0].(VMDateTimer); ok { - rets.Append(Now().Sub(rv.Time())) - return nil - } - return VMErrorNeedDate + rets.Append(Now().Sub(args[0].(VMDateTimer).Time())) + return nil })) - env.DefineS("пауза", VMFuncMustParams(1, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + env.DefineS("пауза", VMFuncOneParam[VMNumberer](func(args VMSlice, rets *VMSlice, envout *(*Env)) error { *envout = env - if v, ok := args[0].(VMNumberer); ok { - sec1 := NewVMDecNumFromInt64(int64(VMSecond)) - time.Sleep(time.Duration(v.DecNum().Mul(sec1).Int())) - return nil - } - return VMErrorNeedSeconds + sec1 := NewVMDecNumFromInt64(int64(VMSecond)) + time.Sleep(time.Duration(args[0].(VMNumberer).DecNum().Mul(sec1).Int())) + return nil })) env.DefineS("длительностьнаносекунды", VMNanosecond) @@ -138,153 +129,137 @@ func Import(env *Env) *Env { env.DefineS("длительностьчаса", VMHour) env.DefineS("длительностьдня", VMDay) - env.DefineS("хэш", VMFuncMustParams(1, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + env.DefineS("хэш", VMFuncOneParam[VMHasher](func( + args VMSlice, rets *VMSlice, envout *(*Env), + ) error { *envout = env - if v, ok := args[0].(VMHasher); ok { - rets.Append(v.Hash()) - return nil - } - return VMErrorNeedHash + rets.Append(args[0].(VMHasher).Hash()) + return nil })) - env.DefineS("уникальныйидентификатор", VMFuncMustParams(0, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + env.DefineS("уникальныйидентификатор", VMFuncMustParams(0, func( + args VMSlice, rets *VMSlice, envout *(*Env), + ) error { *envout = env rets.Append(VMString(uuid.NewV1().String())) return nil })) - env.DefineS("получитьмассивизпула", VMFuncMustParams(0, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + env.DefineS("получитьмассивизпула", VMFuncMustParams(0, func( + args VMSlice, rets *VMSlice, envout *(*Env), + ) error { *envout = env rets.Append(GetGlobalVMSlice()) return nil })) - env.DefineS("вернутьмассиввпул", VMFuncMustParams(1, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + env.DefineS("вернутьмассиввпул", VMFuncOneParam[VMSlice](func( + args VMSlice, rets *VMSlice, envout *(*Env), + ) error { *envout = env - if v, ok := args[0].(VMSlice); ok { - PutGlobalVMSlice(v) - return nil - } - return VMErrorNeedMap + PutGlobalVMSlice(args[0].(VMSlice)) + return nil })) - env.DefineS("случайнаястрока", VMFuncMustParams(1, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + env.DefineS("случайнаястрока", VMFuncOneParam[VMInt](func( + args VMSlice, rets *VMSlice, envout *(*Env), + ) error { *envout = env - if v, ok := args[0].(VMInt); ok { - rets.Append(VMString(MustGenerateRandomString(int(v)))) - return nil - } - return VMErrorNeedInt + rets.Append(VMString(MustGenerateRandomString(int(args[0].(VMInt))))) + return nil })) - env.DefineS("нрег", VMFuncMustParams(1, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + env.DefineS("нрег", VMFuncOneParam[VMStringer](func( + args VMSlice, rets *VMSlice, envout *(*Env), + ) error { *envout = env - if v, ok := args[0].(VMStringer); ok { - rets.Append(VMString(strings.ToLower(string(v.String())))) - return nil - } - return VMErrorNeedString + rets.Append(VMString(strings.ToLower(string(args[0].(VMStringer).String())))) + return nil })) - env.DefineS("врег", VMFuncMustParams(1, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + env.DefineS("врег", VMFuncOneParam[VMStringer](func( + args VMSlice, rets *VMSlice, envout *(*Env), + ) error { *envout = env - if v, ok := args[0].(VMStringer); ok { - rets.Append(VMString(strings.ToUpper(string(v.String())))) - return nil - } - return VMErrorNeedString + rets.Append(VMString(strings.ToUpper(string(args[0].(VMStringer).String())))) + return nil })) - env.DefineS("стрсодержит", VMFuncMustParams(2, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + env.DefineS("стрсодержит", VMFuncTwoParams[VMStringer, VMStringer](func( + args VMSlice, rets *VMSlice, envout *(*Env), + ) error { *envout = env - v1, ok1 := args[0].(VMStringer) - v2, ok2 := args[1].(VMStringer) - if ok1 && ok2 { - rets.Append(VMBool(strings.Contains(string(v1.String()), string(v2.String())))) - return nil - } - return VMErrorNeedString + rets.Append(VMBool(strings.Contains( + string(args[0].(VMStringer).String()), + string(args[1].(VMStringer).String())))) + return nil })) - env.DefineS("стрсодержитлюбой", VMFuncMustParams(2, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + env.DefineS("стрсодержитлюбой", VMFuncTwoParams[VMStringer, VMStringer](func( + args VMSlice, rets *VMSlice, envout *(*Env), + ) error { *envout = env - v1, ok1 := args[0].(VMStringer) - v2, ok2 := args[1].(VMStringer) - if ok1 && ok2 { - rets.Append(VMBool(strings.ContainsAny(string(v1.String()), string(v2.String())))) - return nil - } - return VMErrorNeedString + rets.Append(VMBool(strings.ContainsAny( + string(args[0].(VMStringer).String()), + string(args[1].(VMStringer).String())))) + return nil })) - env.DefineS("стрколичество", VMFuncMustParams(2, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + env.DefineS("стрколичество", VMFuncTwoParams[VMStringer, VMStringer](func( + args VMSlice, rets *VMSlice, envout *(*Env), + ) error { *envout = env - v1, ok1 := args[0].(VMStringer) - v2, ok2 := args[1].(VMStringer) - if ok1 && ok2 { - rets.Append(VMInt(strings.Count(string(v1.String()), string(v2.String())))) - return nil - } - return VMErrorNeedString + rets.Append(VMInt(strings.Count( + string(args[0].(VMStringer).String()), + string(args[1].(VMStringer).String())))) + return nil })) - env.DefineS("стрнайти", VMFuncMustParams(2, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + env.DefineS("стрнайти", VMFuncTwoParams[VMStringer, VMStringer](func( + args VMSlice, rets *VMSlice, envout *(*Env), + ) error { *envout = env - v1, ok1 := args[0].(VMStringer) - v2, ok2 := args[1].(VMStringer) - if ok1 && ok2 { - rets.Append(VMInt(strings.Index(string(v1.String()), string(v2.String())))) - return nil - } - return VMErrorNeedString + rets.Append(VMInt(strings.Index( + string(args[0].(VMStringer).String()), + string(args[1].(VMStringer).String())))) + return nil })) - env.DefineS("стрнайтилюбой", VMFuncMustParams(2, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + env.DefineS("стрнайтилюбой", VMFuncTwoParams[VMStringer, VMStringer](func( + args VMSlice, rets *VMSlice, envout *(*Env), + ) error { *envout = env - v1, ok1 := args[0].(VMStringer) - v2, ok2 := args[1].(VMStringer) - if ok1 && ok2 { - rets.Append(VMInt(strings.IndexAny(string(v1.String()), string(v2.String())))) - return nil - } - return VMErrorNeedString + rets.Append(VMInt(strings.IndexAny( + string(args[0].(VMStringer).String()), + string(args[1].(VMStringer).String())))) + return nil })) - env.DefineS("стрнайтипоследний", VMFuncMustParams(2, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + env.DefineS("стрнайтипоследний", VMFuncTwoParams[VMStringer, VMStringer](func( + args VMSlice, rets *VMSlice, envout *(*Env), + ) error { *envout = env - v1, ok1 := args[0].(VMStringer) - v2, ok2 := args[1].(VMStringer) - if ok1 && ok2 { - rets.Append(VMInt(strings.LastIndex(string(v1.String()), string(v2.String())))) - return nil - } - return VMErrorNeedString + rets.Append(VMInt(strings.LastIndex( + string(args[0].(VMStringer).String()), + string(args[1].(VMStringer).String())))) + return nil })) - env.DefineS("стрзаменить", VMFuncMustParams(3, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + env.DefineS("стрзаменить", VMFuncThreeParams[VMStringer, VMStringer, VMStringer](func( + args VMSlice, rets *VMSlice, envout *(*Env), + ) error { *envout = env - v1, ok1 := args[0].(VMStringer) - v2, ok2 := args[1].(VMStringer) - v3, ok3 := args[2].(VMStringer) - if ok1 && ok2 && ok3 { - rets.Append(VMString(strings.Replace(string(v1.String()), string(v2.String()), string(v3.String()), -1))) - return nil - } - return VMErrorNeedString + rets.Append(VMString(strings.Replace( + string(args[0].(VMStringer).String()), + string(args[1].(VMStringer).String()), + string(args[2].(VMStringer).String()), -1))) + return nil })) - env.DefineS("окр", VMFuncMustParams(2, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + env.DefineS("окр", VMFuncTwoParams[VMDecNum, VMInt](func(args VMSlice, rets *VMSlice, envout *(*Env)) error { *envout = env - v1, ok1 := args[0].(VMDecNum) - if !ok1 { - return VMErrorNeedDecNum - } - v2, ok2 := args[1].(VMInt) - if !ok2 { - return VMErrorNeedInt - } - - rets.Append(VMDecNum{num: v1.num.RoundWithMode(int32(v2), decnum.RoundHalfUp)}) + rets.Append(VMDecNum{num: args[0].(VMDecNum).num.RoundWithMode( + int32(args[1].(VMInt)), decnum.RoundHalfUp)}) return nil })) @@ -301,18 +276,17 @@ func Import(env *Env) *Env { return VMErrorNeedString })) - env.DefineS("кодсимвола", VMFuncMustParams(1, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + env.DefineS("кодсимвола", VMFuncOneParam[VMStringer](func( + args VMSlice, rets *VMSlice, envout *(*Env), + ) error { *envout = env - if v, ok := args[0].(VMStringer); ok { - s := v.String() - if len(s) == 0 { - rets.Append(VMInt(0)) - } else { - rets.Append(VMInt([]rune(s)[0])) - } - return nil + s := args[0].(VMStringer).String() + if len(s) == 0 { + rets.Append(VMInt(0)) + } else { + rets.Append(VMInt([]rune(s)[0])) } - return VMErrorNeedString + return nil })) env.DefineS("типзнч", VMFuncMustParams(1, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { @@ -355,45 +329,42 @@ func Import(env *Env) *Env { return nil })) - env.DefineS("переменнаяокружения", VMFuncMustParams(1, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + env.DefineS("переменнаяокружения", VMFuncOneParam[VMString](func(args VMSlice, rets *VMSlice, envout *(*Env)) error { *envout = env - if v, ok := args[0].(VMString); ok { - val, setted := os.LookupEnv(string(v)) - rets.Append(VMString(val)) - rets.Append(VMBool(setted)) - return nil - } - return VMErrorNeedSeconds + val, ok := os.LookupEnv(string(args[0].(VMString))) + rets.Append(VMString(val)) + rets.Append(VMBool(ok)) + return nil })) // при изменении состава типов не забывать изменять их и в lexer.go - env.DefineTypeS("целоечисло", ReflectVMInt) - env.DefineTypeS("число", ReflectVMDecNum) - env.DefineTypeS("булево", ReflectVMBool) - env.DefineTypeS("строка", ReflectVMString) - env.DefineTypeS("массив", ReflectVMSlice) - env.DefineTypeS("структура", ReflectVMStringMap) - env.DefineTypeS("дата", ReflectVMTime) - env.DefineTypeS("длительность", ReflectVMTimeDuration) - env.DefineTypeS("функция", ReflectVMFunc) - - env.DefineTypeS("группаожидания", ReflectVMWaitGroup) - env.DefineTypeS("файловаябазаданных", ReflectVMBoltDB) - - env.DefineTypeStruct("сервер", &VMServer{}) - env.DefineTypeStruct("клиент", &VMClient{}) - - env.DefineTypeStruct("сервермайнкрафт", &RconClient{}) - env.DefineTypeStruct("текстовыйдокумент", &TextDocument{}) - env.DefineTypeStruct("файл", &File{}) - - env.DefineTypeStruct("таблицазначений", &VMTable{}) - env.DefineTypeStruct("колонкатаблицызначений", &VMTableColumn{}) - env.DefineTypeStruct("коллекцияколоноктаблицызначений", &VMTableColumns{}) - env.DefineTypeStruct("строкатаблицызначений", &VMTableLine{}) + env.DefineTypeS(ReflectVMInt) + env.DefineTypeS(ReflectVMDecNum) + env.DefineTypeS(ReflectVMBool) + env.DefineTypeS(ReflectVMString) + env.DefineTypeS(ReflectVMSlice) + env.DefineTypeS(ReflectVMStringMap) + env.DefineTypeS(ReflectVMTime) + env.DefineTypeS(ReflectVMTimeDuration) + env.DefineTypeS(ReflectVMFunc) + + env.DefineTypeS(ReflectVMWaitGroup) + env.DefineTypeS(ReflectVMBoltDB) + + env.DefineTypeStruct(&VMServer{}) + env.DefineTypeStruct(&VMClient{}) + + env.DefineTypeStruct(&RconClient{}) + env.DefineTypeStruct(&TextDocument{}) + env.DefineTypeStruct(&File{}) + + env.DefineTypeStruct(&VMTable{}) + env.DefineTypeStruct(&VMTableColumn{}) + env.DefineTypeStruct(&VMTableColumns{}) + env.DefineTypeStruct(&VMTableLine{}) ////////////////// - env.DefineTypeStruct("__функциональнаяструктуратест__", &TttStructTest{}) + env.DefineTypeStruct(&TttStructTest{}) env.DefineS("__дамп__", VMFunc(func(args VMSlice, rets *VMSlice, envout *(*Env)) error { *envout = env @@ -414,6 +385,10 @@ type TttStructTest struct { ПолеСтрока VMString } +func (tst *TttStructTest) VMTypeString() string { + return "__ФункциональнаяСтруктураТест__" +} + func (tst *TttStructTest) VMRegister() { tst.VMRegisterMethod("ВСтроку", tst.ВСтроку) tst.VMRegisterField("ПолеЦелоеЧисло", &tst.ПолеЦелоеЧисло) diff --git a/core/coreboltdb.go b/core/coreboltdb.go index a3d079a..88eefbf 100644 --- a/core/coreboltdb.go +++ b/core/coreboltdb.go @@ -19,7 +19,7 @@ type VMBoltDB struct { var ReflectVMBoltDB = reflect.TypeOf(VMBoltDB{}) -func (x *VMBoltDB) vmval() {} +func (x *VMBoltDB) VMTypeString() string { return "ФайловаяБазаДанных" } func (x *VMBoltDB) Interface() interface{} { return x @@ -106,7 +106,9 @@ type VMBoltTransaction struct { writable bool } -func (x *VMBoltTransaction) vmval() {} +func (x *VMBoltTransaction) VMTypeString() string { + return "ТранзакцияФайловойБазыДанных" +} func (x *VMBoltTransaction) Interface() interface{} { return x @@ -233,7 +235,9 @@ type VMBoltTable struct { b *bolt.Bucket } -func (x *VMBoltTable) vmval() {} +func (x *VMBoltTable) VMTypeString() string { + return "ТаблицаФайловойБазыДанных" +} func (x *VMBoltTable) Interface() interface{} { return x @@ -252,7 +256,7 @@ func (x *VMBoltTable) Set(k string, v VMBinaryTyper) error { return x.b.Put([]byte(k), append(i, ii...)) } -func parseBoltValue(sl []byte) (VMValuer, error) { +func parseBoltValue(sl []byte) (VMValue, error) { if len(sl) < 1 { return nil, VMErrorWrongDBValue } @@ -268,7 +272,7 @@ func parseBoltValue(sl []byte) (VMValuer, error) { return vv, nil } -func (x *VMBoltTable) Get(k string) (VMValuer, bool, error) { +func (x *VMBoltTable) Get(k string) (VMValue, bool, error) { sl := x.b.Get([]byte(k)) if sl == nil { return VMNil, false, nil diff --git a/core/corebool.go b/core/corebool.go index a703a72..7418023 100644 --- a/core/corebool.go +++ b/core/corebool.go @@ -13,7 +13,7 @@ type VMBool bool var ReflectVMBool = reflect.TypeOf(VMBool(true)) -func (x VMBool) vmval() {} +func (x VMBool) VMTypeString() string { return "Булево" } func (x VMBool) Interface() interface{} { return bool(x) @@ -86,7 +86,7 @@ func ParseVMBool(s string) (VMBool, error) { return false, VMErrorNotConverted } -func (x VMBool) EvalUnOp(op rune) (VMValuer, error) { +func (x VMBool) EvalUnOp(op rune) (VMValue, error) { switch op { // case '-': // case '^': @@ -96,7 +96,7 @@ func (x VMBool) EvalUnOp(op rune) (VMValuer, error) { return VMNil, VMErrorUnknownOperation } -func (x VMBool) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) { +func (x VMBool) EvalBinOp(op VMOperation, y VMOperationer) (VMValue, error) { switch op { case ADD: return VMNil, VMErrorIncorrectOperation @@ -154,7 +154,7 @@ func (x VMBool) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) { return VMNil, VMErrorUnknownOperation } -func (x VMBool) ConvertToType(nt reflect.Type) (VMValuer, error) { +func (x VMBool) ConvertToType(nt reflect.Type) (VMValue, error) { switch nt { case ReflectVMBool: return x, nil diff --git a/core/corechan.go b/core/corechan.go index 6b4ff8e..310b080 100644 --- a/core/corechan.go +++ b/core/corechan.go @@ -5,24 +5,24 @@ import ( ) // VMChan - канал для передачи любого типа вирт. машины -type VMChan chan VMValuer +type VMChan chan VMValue -func (x VMChan) vmval() {} +func (x VMChan) VMTypeString() string { return "Канал" } func (x VMChan) Interface() interface{} { return x } -func (x VMChan) Send(v VMValuer) { +func (x VMChan) Send(v VMValue) { x <- v } -func (x VMChan) Recv() (VMValuer, bool) { +func (x VMChan) Recv() (VMValue, bool) { rv, ok := <-x return rv, ok } -func (x VMChan) TrySend(v VMValuer) (ok bool) { +func (x VMChan) TrySend(v VMValue) (ok bool) { select { case x <- v: ok = true @@ -32,7 +32,7 @@ func (x VMChan) TrySend(v VMValuer) (ok bool) { return } -func (x VMChan) TryRecv() (v VMValuer, ok bool, notready bool) { +func (x VMChan) TryRecv() (v VMValue, ok bool, notready bool) { select { case v, ok = <-x: notready = false diff --git a/core/coreclient.go b/core/coreclient.go index eba1557..d4c03dd 100644 --- a/core/coreclient.go +++ b/core/coreclient.go @@ -13,6 +13,10 @@ type VMClient struct { conn *VMConn // клиент tcp, каждому соединению присваивается GUID } +func (x *VMClient) VMTypeString() string { + return "Клиент" +} + func (x *VMClient) String() string { return fmt.Sprintf("Клиент %s %s", x.protocol, x.addr) } @@ -21,7 +25,7 @@ func (x *VMClient) IsOnline() bool { return x.conn != nil && !x.conn.closed } -func (x *VMClient) Open(proto, addr string, handler VMFunc, data VMValuer, closeOnExitHandler bool) error { +func (x *VMClient) Open(proto, addr string, handler VMFunc, data VMValue, closeOnExitHandler bool) error { switch proto { case "tcp", "tcpzip", "tcptls", "http", "https": diff --git a/core/coreconn.go b/core/coreconn.go index adcde87..e4653c4 100644 --- a/core/coreconn.go +++ b/core/coreconn.go @@ -18,7 +18,7 @@ import ( "github.com/shinanca/gonec/names" ) -func NewVMConn(data VMValuer) *VMConn { +func NewVMConn(data VMValue) *VMConn { return &VMConn{ id: -1, closed: false, @@ -44,11 +44,11 @@ type VMConn struct { id int closed bool uid string - data VMValuer + data VMValue gzip bool } -func (c *VMConn) vmval() {} +func (c *VMConn) VMTypeString() string { return "Соединение" } func (c *VMConn) Interface() interface{} { return c.conn diff --git a/core/coredecnum.go b/core/coredecnum.go index b35c250..750599b 100644 --- a/core/coredecnum.go +++ b/core/coredecnum.go @@ -22,7 +22,7 @@ var ( VMDecNumNegOne = NewVMDecNumFromInt64(-1) ) -func (x VMDecNum) vmval() {} +func (x VMDecNum) VMTypeString() string { return "Число" } func (x VMDecNum) Interface() interface{} { return x.num @@ -186,7 +186,7 @@ func NewVMDecNumFromInt64(x int64) VMDecNum { return VMDecNum{num: decnum.FromInt64(x)} } -func (x VMDecNum) EvalUnOp(op rune) (VMValuer, error) { +func (x VMDecNum) EvalUnOp(op rune) (VMValue, error) { switch op { case '-': return VMDecNum{num: x.num.Neg()}, nil @@ -197,7 +197,7 @@ func (x VMDecNum) EvalUnOp(op rune) (VMValuer, error) { } } -func (x VMDecNum) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) { +func (x VMDecNum) EvalBinOp(op VMOperation, y VMOperationer) (VMValue, error) { switch op { case ADD: switch yy := y.(type) { @@ -315,7 +315,7 @@ func (x VMDecNum) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) { return VMNil, VMErrorUnknownOperation } -func (x VMDecNum) ConvertToType(nt reflect.Type) (VMValuer, error) { +func (x VMDecNum) ConvertToType(nt reflect.Type) (VMValue, error) { switch nt { case ReflectVMDecNum: return x, nil diff --git a/core/coreenv.go b/core/coreenv.go index 1f3ba20..24d9e7f 100644 --- a/core/coreenv.go +++ b/core/coreenv.go @@ -2,6 +2,7 @@ package core import ( "encoding/gob" + "errors" "fmt" "io" "os" @@ -48,14 +49,14 @@ func NewVals() *Vals { return &v } -func (v *Vals) Get(name int) (VMValuer, bool) { +func (v *Vals) Get(name int) (VMValue, bool) { if i, ok := v.idx[name]; ok { return v.vals[i], v.vals[i] != nil } return nil, false } -func (v *Vals) Set(name int, val VMValuer) { +func (v *Vals) Set(name int, val VMValue) { if i, ok := v.idx[name]; ok { v.vals[i] = val } else { @@ -87,12 +88,13 @@ type Env struct { stdout io.Writer sid string lastid int - lastval VMValuer + lastval VMValue builtsLoaded bool Valid bool } -func (e *Env) vmval() {} // нужно для того, чтобы *Env можно было сохранять в переменные VMValuer +// нужно для того, чтобы *Env можно было сохранять в переменные VMValue +func (e *Env) VMTypeString() string { return "Окружение" } // NewEnv creates new global scope. // !!!не забывать вызывать core.LoadAllBuiltins(m)!!! @@ -261,7 +263,7 @@ func (e *Env) Type(k int) (reflect.Type, error) { // Get returns value which specified symbol. It goes to upper scope until // found or returns error. -func (e *Env) Get(k int) (VMValuer, error) { +func (e *Env) Get(k int) (VMValue, error) { for ee := e; ee != nil; ee = ee.parent { ee.RLock() if ee.lastid == k { @@ -287,7 +289,7 @@ func (e *Env) Get(k int) (VMValuer, error) { // Set modifies value which specified as symbol. It goes to upper scope until // found or returns error. -func (e *Env) Set(k int, v VMValuer) error { +func (e *Env) Set(k int, v VMValue) error { for ee := e; ee != nil; ee = ee.parent { ee.Lock() if _, ok := ee.env.Get(k); ok { @@ -303,7 +305,7 @@ func (e *Env) Set(k int, v VMValuer) error { } // DefineGlobal defines symbol in global scope. -func (e *Env) DefineGlobal(k int, v VMValuer) error { +func (e *Env) DefineGlobal(k int, v VMValue) error { for ee := e; ee != nil; ee = ee.parent { if ee.parent == nil { return ee.Define(k, v) @@ -325,18 +327,33 @@ func (e *Env) DefineType(k int, t reflect.Type) error { return fmt.Errorf("Отсутствует глобальный контекст!") } -func (e *Env) DefineTypeS(k string, t reflect.Type) error { - return e.DefineType(names.UniqueNames.Set(k), t) +func (e *Env) defineTypeHelper(v reflect.Value) error { + value := v + if v.Kind() == reflect.Struct { + value = reflect.New(v.Type()) + value.Elem().Set(v) + } + + ret := value.MethodByName("VMTypeString").Call([]reflect.Value{}) + if len(ret) != 1 || ret[0].Kind() != reflect.String { + return errors.New("VMTypeString должен возвращать строку") + } + return e.DefineType(names.UniqueNames.Set(names.FastToLower(ret[0].String())), v.Type()) +} + +// DefineTypeS регистрирует системный тип +func (e *Env) DefineTypeS(t reflect.Type) error { + return e.defineTypeHelper(reflect.New(t).Elem()) } // DefineTypeStruct регистрирует системную функциональную структуру, переданную в виде указателя! -func (e *Env) DefineTypeStruct(k string, t interface{}) error { +func (e *Env) DefineTypeStruct(t interface{}) error { gob.Register(t) - return e.DefineType(names.UniqueNames.Set(k), reflect.Indirect(reflect.ValueOf(t)).Type()) + return e.defineTypeHelper(reflect.Indirect(reflect.ValueOf(t))) } // Define defines symbol in current scope. -func (e *Env) Define(k int, v VMValuer) error { +func (e *Env) Define(k int, v VMValue) error { e.Lock() e.env.Set(k, v) e.lastid = k @@ -347,7 +364,7 @@ func (e *Env) Define(k int, v VMValuer) error { return nil } -func (e *Env) DefineS(k string, v VMValuer) error { +func (e *Env) DefineS(k string, v VMValue) error { return e.Define(names.UniqueNames.Set(k), v) } diff --git a/core/coreerrors.go b/core/coreerrors.go index d718f9a..c48caa9 100644 --- a/core/coreerrors.go +++ b/core/coreerrors.go @@ -3,6 +3,7 @@ package core import ( "errors" "fmt" + "reflect" ) var ( @@ -63,3 +64,45 @@ var ( func VMErrorNeedArgs(n int) error { return fmt.Errorf("Неверное количество параметров (требуется %d)", n) } + +var argIndexStrs = [3]string{"Первым", "Вторым", "Третьим"} + +func interfaceType[V any]() reflect.Type { + return reflect.TypeOf((*V)(nil)).Elem() +} + +func typeString[V VMValue]() string { + var v V + if any(v) == nil { + // an interface would initialize to nil + vtype := reflect.TypeOf(&v).Elem() + if vtype.Implements(interfaceType[VMStringer]()) { + return "значение, приводимое к Строке" + } else if vtype.Implements(interfaceType[VMNumberer]()) { + return "значение, приводимое к Числу" + } else if vtype.Implements(interfaceType[VMDateTimer]()) { + return "значение, приводимое к Дате" + } else if vtype.Implements(interfaceType[VMIndexer]()) { + return "значение, имеющее длину" + } else if vtype.Implements(interfaceType[VMHasher]()) { + return "хешируемое значение" + } else if vtype.Implements(interfaceType[VMValue]()) { + return "значение любого типа Гонца" + } + panic("Не известно строковое представление типа") + } + return "значение типа " + v.VMTypeString() +} + +func VMErrorNeedArgType[V VMValue](i, n int) error { + if i >= n { + panic("VMErrorNeedArgType: i < n") + } + indStr, typeStr := argIndexStrs[i], typeString[V]() + + if n == 1 { + return fmt.Errorf("Требуется %s", typeStr) + } else { + return fmt.Errorf("%s параметром требуется %s", indStr, typeStr) + } +} diff --git a/core/corefile.go b/core/corefile.go index 188292d..4074d75 100644 --- a/core/corefile.go +++ b/core/corefile.go @@ -13,6 +13,10 @@ type File struct { name string } +func (f *File) VMTypeString() string { + return "Файл" +} + func (f *File) wrapError(err error) error { if os.IsNotExist(err) { return fmt.Errorf("Файла '%s' не существует", f.name) diff --git a/core/corefunc.go b/core/corefunc.go index b3e0b6a..b7d6c34 100644 --- a/core/corefunc.go +++ b/core/corefunc.go @@ -16,7 +16,7 @@ type VMFunc func(args VMSlice, rets *VMSlice, envout *(*Env)) error var ReflectVMFunc = reflect.TypeOf(VMFunc(nil)) -func (f VMFunc) vmval() {} +func (f VMFunc) VMTypeString() string { return "Функция" } func (f VMFunc) Interface() interface{} { return f @@ -36,6 +36,7 @@ type ( ) func VMFuncMustParams(n int, f VMMethod) VMFunc { + needArgsErr := VMErrorNeedArgs(n) return VMFunc( func(args VMSlice, rets *VMSlice, envout *(*Env)) error { if len(args) != n { @@ -43,9 +44,59 @@ func VMFuncMustParams(n int, f VMMethod) VMFunc { case 0: return VMErrorNoNeedArgs default: - return VMErrorNeedArgs(n) + return needArgsErr } } return f(args, rets, envout) }) } + +func paramCheckHelper[V VMValue](args VMSlice, i, n int, errs []error) error { + if _, ok := args[i].(V); !ok { + return errs[i] + } + return nil +} + +func VMFuncOneParam[V1 VMValue](f VMMethod) VMFunc { + errs := []error{VMErrorNeedArgType[V1](0, 1)} + return VMFuncMustParams(1, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + if err := paramCheckHelper[V1](args, 0, 1, errs); err != nil { + return err + } + return f(args, rets, envout) + }) +} + +func VMFuncTwoParams[V1, V2 VMValue](f VMMethod) VMFunc { + errs := []error{ + VMErrorNeedArgType[V1](0, 2), + VMErrorNeedArgType[V2](1, 2), + } + return VMFuncMustParams(2, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + if err := paramCheckHelper[V1](args, 0, 2, errs); err != nil { + return err + } else if err := paramCheckHelper[V2](args, 1, 2, errs); err != nil { + return err + } + return f(args, rets, envout) + }) +} + +func VMFuncThreeParams[V1, V2, V3 VMValue](f VMMethod) VMFunc { + errs := []error{ + VMErrorNeedArgType[V1](0, 3), + VMErrorNeedArgType[V2](1, 3), + VMErrorNeedArgType[V3](2, 3), + } + return VMFuncMustParams(3, func(args VMSlice, rets *VMSlice, envout *(*Env)) error { + if err := paramCheckHelper[V1](args, 0, 3, errs); err != nil { + return err + } else if err := paramCheckHelper[V2](args, 1, 3, errs); err != nil { + return err + } else if err := paramCheckHelper[V3](args, 2, 3, errs); err != nil { + return err + } + return f(args, rets, envout) + }) +} diff --git a/core/corehttp.go b/core/corehttp.go index dd0740c..60f0930 100644 --- a/core/corehttp.go +++ b/core/corehttp.go @@ -11,11 +11,11 @@ import ( // VMHttpRequest запрос к http серверу type VMHttpRequest struct { r *http.Request - data VMValuer + data VMValue body []byte } -func (x *VMHttpRequest) vmval() {} +func (x *VMHttpRequest) VMTypeString() string { return "HttpЗапрос" } func (x *VMHttpRequest) Interface() interface{} { return x.r @@ -239,10 +239,10 @@ type VMHttpResponse struct { r *http.Response w http.ResponseWriter body []byte - data VMValuer + data VMValue } -func (x *VMHttpResponse) vmval() {} +func (x *VMHttpResponse) VMTypeString() string { return "HttpОтвет" } func (x *VMHttpResponse) Interface() interface{} { return x.r diff --git a/core/coreifaces.go b/core/coreifaces.go index c78bf23..a37a2e7 100644 --- a/core/coreifaces.go +++ b/core/coreifaces.go @@ -7,61 +7,61 @@ import ( // иерархия базовых типов вирт. машины type ( - // VMValuer корневой тип всех значений, доступных вирт. машине - VMValuer interface { - vmval() + // VMValue корневой тип всех значений, доступных вирт. машине + VMValue interface { + VMTypeString() string } // VMInterfacer корневой тип всех значений, // которые могут преобразовываться в значения для функций на языке Го в родные типы Го VMInterfacer interface { - VMValuer + VMValue Interface() interface{} // в типах Го, может возвращать в т.ч. nil } // VMFromGoParser может парсить из значений на языке Го VMFromGoParser interface { - VMValuer + VMValue ParseGoType(interface{}) // используется для указателей, т.к. парсит в их значения } // VMOperationer может выполнить операцию с другим значением, операцию сравнения или математическую VMOperationer interface { - VMValuer - EvalBinOp(VMOperation, VMOperationer) (VMValuer, error) // возвращает результат выражения с другим значением + VMValue + EvalBinOp(VMOperation, VMOperationer) (VMValue, error) // возвращает результат выражения с другим значением } // VMUnarer может выполнить унарную операцию над свои значением VMUnarer interface { - VMValuer - EvalUnOp(rune) (VMValuer, error) // возвращает результат выражения с другим значением + VMValue + EvalUnOp(rune) (VMValue, error) // возвращает результат выражения с другим значением } // VMConverter может конвертироваться в тип reflect.Type VMConverter interface { - VMValuer - ConvertToType(t reflect.Type) (VMValuer, error) + VMValue + ConvertToType(t reflect.Type) (VMValue, error) } // VMChaner реализует поведение канала VMChaner interface { VMInterfacer - Send(VMValuer) - Recv() (VMValuer, bool) - TrySend(VMValuer) bool - TryRecv() (VMValuer, bool, bool) + Send(VMValue) + Recv() (VMValue, bool) + TrySend(VMValue) bool + TryRecv() (VMValue, bool, bool) } // VMIndexer имеет длину и значение по индексу VMIndexer interface { VMInterfacer Length() VMInt - IndexVal(VMValuer) VMValuer + IndexVal(VMValue) VMValue } // VMBinaryTyper может сериализовываться в бинарные данные внутри слайсов и структур VMBinaryTyper interface { - VMValuer + VMValue encoding.BinaryMarshaler BinaryType() VMBinaryType } @@ -145,24 +145,24 @@ type ( // то будет использован для инстанцирования объекта VMRegisterConstructor(VMConstructor) VMRegisterMethod(string, VMMethod) // реализовано в VMMetaObj - VMRegisterField(string, VMValuer) // реализовано в VMMetaObj + VMRegisterField(string, VMValue) // реализовано в VMMetaObj VMIsField(int) bool // реализовано в VMMetaObj - VMGetField(int) VMValuer // реализовано в VMMetaObj - VMSetField(int, VMValuer) // реализовано в VMMetaObj + VMGetField(int) VMValue // реализовано в VMMetaObj + VMSetField(int, VMValue) // реализовано в VMMetaObj VMGetMethod(int) (VMFunc, bool) // реализовано в VMMetaObj VMGetConstructor() VMConstructor // реализовано в VMMetaObj } // VMMethodImplementer реализует только методы, доступные в языке Гонец VMMethodImplementer interface { - VMValuer + VMValue MethodMember(int) (VMFunc, bool) // возвращает метод в нужном формате } // VMServicer определяет микросервис, который может регистрироваться в главном менеджере сервисов VMServicer interface { - VMValuer + VMValue Header() VMServiceHeader Start() error // запускает горутину, и если не стартовал, возвращает ошибку HealthCheck() error // если не живой, то возвращает ошибку diff --git a/core/coreint.go b/core/coreint.go index e9817d9..ae4c4e5 100644 --- a/core/coreint.go +++ b/core/coreint.go @@ -16,7 +16,7 @@ type VMInt int64 var ReflectVMInt = reflect.TypeOf(VMInt(0)) -func (x VMInt) vmval() {} +func (x VMInt) VMTypeString() string { return "ЦелоеЧисло" } func (x VMInt) Interface() interface{} { return int64(x) @@ -113,7 +113,7 @@ func ParseVMInt(s string) (VMInt, error) { return VMInt(i64), nil } -func (x VMInt) EvalUnOp(op rune) (VMValuer, error) { +func (x VMInt) EvalUnOp(op rune) (VMValue, error) { switch op { case '-': return VMInt(-int64(x)), nil @@ -126,7 +126,7 @@ func (x VMInt) EvalUnOp(op rune) (VMValuer, error) { } } -func (x VMInt) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) { +func (x VMInt) EvalBinOp(op VMOperation, y VMOperationer) (VMValue, error) { switch op { case ADD: switch yy := y.(type) { @@ -259,7 +259,7 @@ func (x VMInt) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) { return VMNil, VMErrorUnknownOperation } -func (x VMInt) ConvertToType(nt reflect.Type) (VMValuer, error) { +func (x VMInt) ConvertToType(nt reflect.Type) (VMValue, error) { switch nt { case ReflectVMInt: return x, nil diff --git a/core/coremap.go b/core/coremap.go index a7b73dc..89ec439 100644 --- a/core/coremap.go +++ b/core/coremap.go @@ -10,11 +10,11 @@ import ( "github.com/shinanca/gonec/names" ) -type VMStringMap map[string]VMValuer +type VMStringMap map[string]VMValue var ReflectVMStringMap = reflect.TypeOf(make(VMStringMap, 0)) -func (x VMStringMap) vmval() {} +func (x VMStringMap) VMTypeString() string { return "Структура" } func (x VMStringMap) Interface() interface{} { return x @@ -28,14 +28,14 @@ func (x VMStringMap) Length() VMInt { return VMInt(len(x)) } -func (x VMStringMap) IndexVal(i VMValuer) VMValuer { +func (x VMStringMap) IndexVal(i VMValue) VMValue { if ii, ok := i.(VMStringer); ok { return x[ii.String()] } panic("Индекс должен быть строкой") } -func (x VMStringMap) Index(i VMValuer) VMValuer { +func (x VMStringMap) Index(i VMValue) VMValue { if s, ok := i.(VMString); ok { return x[string(s)] } @@ -128,7 +128,7 @@ func (x VMStringMap) Скопировать(args VMSlice, rets *VMSlice, envout return nil } -func (x VMStringMap) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) { +func (x VMStringMap) EvalBinOp(op VMOperation, y VMOperationer) (VMValue, error) { switch op { case ADD: // новые добавляются, а существующие обновляются @@ -266,7 +266,7 @@ func (x VMStringMap) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error return VMNil, VMErrorUnknownOperation } -func (x VMStringMap) ConvertToType(nt reflect.Type) (VMValuer, error) { +func (x VMStringMap) ConvertToType(nt reflect.Type) (VMValue, error) { // fmt.Println(nt) switch nt { @@ -311,7 +311,7 @@ func (x VMStringMap) ConvertToType(nt reflect.Type) (VMValuer, error) { } } } - if vv, ok := rs.Interface().(VMValuer); ok { + if vv, ok := rs.Interface().(VMValue); ok { if vobj, ok := vv.(VMMetaObject); ok { vobj.VMInit(vobj) vobj.VMRegister() diff --git a/core/coremetaobj.go b/core/coremetaobj.go index 2f4b68b..586d23b 100644 --- a/core/coremetaobj.go +++ b/core/coremetaobj.go @@ -16,13 +16,15 @@ import ( // например, Set и set - в вирт. машине будут считаться одинаковыми, будет использоваться последнее по индексу type VMMetaObj struct { vmMetaCacheM map[int]VMFunc - vmMetaCacheF map[int]VMValuer + vmMetaCacheF map[int]VMValue vmMetaConstructor VMConstructor vmOriginal VMMetaObject } -func (v *VMMetaObj) vmval() {} +func (v *VMMetaObj) VMTypeString() string { + return "Объект" +} func (v *VMMetaObj) VMInit(m VMMetaObject) { // исходная структура @@ -66,9 +68,9 @@ func (v *VMMetaObj) VMRegisterMethod(name string, m VMMethod) { }(m) } -func (v *VMMetaObj) VMRegisterField(name string, m VMValuer) { +func (v *VMMetaObj) VMRegisterField(name string, m VMValue) { if v.vmMetaCacheF == nil { - v.vmMetaCacheF = make(map[int]VMValuer) + v.vmMetaCacheF = make(map[int]VMValue) } switch m.(type) { case *VMInt, *VMString, *VMBool, @@ -87,7 +89,7 @@ func (v *VMMetaObj) VMIsField(name int) bool { return ok } -func (v *VMMetaObj) VMGetField(name int) VMValuer { +func (v *VMMetaObj) VMGetField(name int) VMValue { if r, ok := v.vmMetaCacheF[name]; ok { switch rv := r.(type) { case *VMInt: @@ -113,7 +115,7 @@ func (v *VMMetaObj) VMGetField(name int) VMValuer { panic("Невозможно получить значение поля") } -func (v *VMMetaObj) VMSetField(name int, val VMValuer) { +func (v *VMMetaObj) VMSetField(name int, val VMValue) { if r, ok := v.vmMetaCacheF[name]; ok { switch rv := r.(type) { case *VMInt: @@ -162,7 +164,7 @@ func (v *VMMetaObj) VMGetConstructor() VMConstructor { return v.vmMetaConstructor } -func (v *VMMetaObj) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) { +func (v *VMMetaObj) EvalBinOp(op VMOperation, y VMOperationer) (VMValue, error) { switch op { case ADD: return VMNil, VMErrorIncorrectOperation @@ -214,7 +216,7 @@ func (v *VMMetaObj) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) return VMNil, VMErrorUnknownOperation } -func (v *VMMetaObj) ConvertToType(nt reflect.Type) (VMValuer, error) { +func (v *VMMetaObj) ConvertToType(nt reflect.Type) (VMValue, error) { switch nt { case ReflectVMString: // сериализуем в json diff --git a/core/corercon.go b/core/corercon.go index 5e7534a..433af35 100644 --- a/core/corercon.go +++ b/core/corercon.go @@ -15,6 +15,10 @@ type RconClient struct { conn *mcrcon.MCConn } +func (x *RconClient) VMTypeString() string { + return "СерверМайнкрафт" +} + func (x *RconClient) String() string { return fmt.Sprintf("СерверМайнкрафт %s %s", x.password, x.addr) } diff --git a/core/coreserver.go b/core/coreserver.go index 3b9e826..0c466d5 100644 --- a/core/coreserver.go +++ b/core/coreserver.go @@ -29,6 +29,10 @@ type VMServer struct { maxconn int } +func (x *VMServer) VMTypeString() string { + return "Сервер" +} + func (x *VMServer) String() string { return fmt.Sprintf("Сервер %s %s", x.protocol, x.addr) } @@ -53,7 +57,7 @@ func (x *VMServer) healthSender() { } } -func (x *VMServer) Open(proto, addr string, maxconn int, handler VMFunc, data VMValuer, vsmHandlers VMStringMap) (err error) { +func (x *VMServer) Open(proto, addr string, maxconn int, handler VMFunc, data VMValue, vsmHandlers VMStringMap) (err error) { // запускаем сервер if x.lnr != nil || x.srv != nil { return VMErrorServerNowOnline diff --git a/core/coreservice.go b/core/coreservice.go index b0e4ec4..1029bdb 100644 --- a/core/coreservice.go +++ b/core/coreservice.go @@ -44,7 +44,9 @@ type VMServiceBus struct { done chan bool } -func (x *VMServiceBus) vmval() {} +func (x *VMServiceBus) VMTypeString() string { + return "МенеджерСервисов" +} func (x *VMServiceBus) Interface() interface{} { return x diff --git a/core/coreslice.go b/core/coreslice.go index 777aa9f..1021c26 100644 --- a/core/coreslice.go +++ b/core/coreslice.go @@ -36,11 +36,11 @@ func PutGlobalVMSlice(sl VMSlice) { } } -type VMSlice []VMValuer +type VMSlice []VMValue var ReflectVMSlice = reflect.TypeOf(make(VMSlice, 0)) -func (x VMSlice) vmval() {} +func (x VMSlice) VMTypeString() string { return "Массив" } func (x VMSlice) Interface() interface{} { return x @@ -62,7 +62,7 @@ func (x VMSlice) Args() []interface{} { return ai } -func (x *VMSlice) Append(a ...VMValuer) { +func (x *VMSlice) Append(a ...VMValue) { *x = append(*x, a...) } @@ -70,7 +70,7 @@ func (x VMSlice) Length() VMInt { return VMInt(len(x)) } -func (x VMSlice) IndexVal(i VMValuer) VMValuer { +func (x VMSlice) IndexVal(i VMValue) VMValue { if ii, ok := i.(VMInt); ok { return x[int(ii)] } @@ -108,7 +108,7 @@ func (x VMSlice) MethodMember(name int) (VMFunc, bool) { case "найтисорт": return VMFuncMustParams(1, x.НайтиСорт), true case "вставить": - return VMFuncMustParams(2, (&x).Вставить), true + return VMFuncTwoParams[VMInt, VMValue]((&x).Вставить), true case "удалить": return VMFuncMustParams(1, (&x).Удалить), true case "скопироватьуникальные": @@ -164,10 +164,7 @@ func (x VMSlice) НайтиСорт(args VMSlice, rets *VMSlice, envout *(*Env)) // Индекс может быть равен длине, тогда вставка происходит в последний элемент. // Обычно используется в связке с НайтиСорт, т.к. позволяет вставлять значения с сохранением сортировки по возрастанию func (x *VMSlice) Вставить(args VMSlice, rets *VMSlice, envout *(*Env)) error { - p, ok := args[0].(VMInt) - if !ok { - return VMErrorNeedInt - } + p := args[0].(VMInt) if int(p) < 0 || int(p) > len(*x) { return VMErrorIndexOutOfBoundary } @@ -237,7 +234,7 @@ func (x VMSlice) Скопировать(args VMSlice, rets *VMSlice, envout *(*E func (x VMSlice) СкопироватьУникальные(args VMSlice, rets *VMSlice, envout *(*Env)) error { // VMSlice { rv := make(VMSlice, len(x)) - seen := make(map[VMValuer]bool) + seen := make(map[VMValue]bool) for i, v := range x { if _, ok := seen[v]; ok { continue @@ -257,14 +254,14 @@ func (x VMSlice) СкопироватьУникальные(args VMSlice, rets * return nil } -func (x VMSlice) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) { +func (x VMSlice) EvalBinOp(op VMOperation, y VMOperationer) (VMValue, error) { switch op { case ADD: switch yy := y.(type) { case VMSlice: // добавляем второй слайс в конец первого return append(x, yy...), nil - case VMValuer: + case VMValue: return append(x, yy), nil } return append(x, y), nil @@ -437,7 +434,7 @@ func (x VMSlice) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) { return VMNil, VMErrorUnknownOperation } -func (x VMSlice) ConvertToType(nt reflect.Type) (VMValuer, error) { +func (x VMSlice) ConvertToType(nt reflect.Type) (VMValue, error) { switch nt { case ReflectVMString: // сериализуем в json diff --git a/core/corestring.go b/core/corestring.go index 9f17871..9ab5ceb 100644 --- a/core/corestring.go +++ b/core/corestring.go @@ -19,7 +19,7 @@ type VMString string var ReflectVMString = reflect.TypeOf(VMString("")) -func (x VMString) vmval() {} +func (x VMString) VMTypeString() string { return "Строка" } func (x VMString) Interface() interface{} { return string(x) @@ -33,7 +33,7 @@ func (x VMString) Length() VMInt { return VMInt(utf8.RuneCountInString(string(x))) } -func (x VMString) IndexVal(i VMValuer) VMValuer { +func (x VMString) IndexVal(i VMValue) VMValue { if ii, ok := i.(VMInt); ok { return VMString(string([]rune(string(x))[int(ii)])) } @@ -158,7 +158,7 @@ func (x VMString) StringMap() VMStringMap { return rm } -func (x VMString) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) { +func (x VMString) EvalBinOp(op VMOperation, y VMOperationer) (VMValue, error) { switch op { case ADD: switch yy := y.(type) { @@ -238,7 +238,7 @@ func (x VMString) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) { return VMNil, VMErrorUnknownOperation } -func (x VMString) ConvertToType(nt reflect.Type) (VMValuer, error) { +func (x VMString) ConvertToType(nt reflect.Type) (VMValue, error) { switch nt { case ReflectVMString: return x, nil @@ -263,7 +263,7 @@ func (x VMString) ConvertToType(nt reflect.Type) (VMValuer, error) { if err := json.Unmarshal([]byte(x), rm); err != nil { return VMNil, err } - if rv, ok := rm.(VMValuer); ok { + if rv, ok := rm.(VMValue); ok { if vobj, ok := rv.(VMMetaObject); ok { vobj.VMInit(vobj) vobj.VMRegister() diff --git a/core/coretable.go b/core/coretable.go index f6cde80..bce3d12 100644 --- a/core/coretable.go +++ b/core/coretable.go @@ -18,6 +18,10 @@ func NewVMTableColumn(vtcs *VMTableColumns) *VMTableColumn { return vtc } +func (vtc *VMTableColumn) VMTypeString() string { + return "КолонкаТаблицыЗначений" +} + func (vtc *VMTableColumn) VMRegister() { // vt.VMRegisterField("ПолеСтрока", &vt.ПолеСтрока) // vt.VMRegisterMethod("Имя", vt.Имя) @@ -39,6 +43,10 @@ func NewVMTableColumns(vt *VMTable) *VMTableColumns { return vtcs } +func (vtcs *VMTableColumns) VMTypeString() string { + return "КоллекцияКолонокТаблицыЗначений" +} + func (vtcs *VMTableColumns) VMRegister() { vtcs.cols = make([]*VMTableColumn, 0, 8) // vt.VMRegisterField("ПолеСтрока", &vt.ПолеСтрока) @@ -61,6 +69,10 @@ func NewVMTableLine(vt *VMTable) *VMTableLine { return vtl } +func (vtl *VMTableLine) VMTypeString() string { + return "СтрокаТаблицыЗначений" +} + func (vtl *VMTableLine) VMRegister() { // vt.VMRegisterField("ПолеСтрока", &vt.ПолеСтрока) // vt.VMRegisterMethod("Имя", vt.Имя) @@ -73,6 +85,10 @@ type VMTable struct { lines []*VMTableLine } +func (vt *VMTable) VMTypeString() string { + return "ТаблицаЗначений" +} + func (vt *VMTable) VMRegister() { vt.cols = NewVMTableColumns(vt) @@ -95,7 +111,7 @@ func (vt *VMTable) Length() VMInt { return VMInt(len(vt.lines)) } -func (vt *VMTable) IndexVal(idx VMValuer) VMValuer { +func (vt *VMTable) IndexVal(idx VMValue) VMValue { if i, ok := idx.(VMInt); ok { return vt.lines[int(i)] } diff --git a/core/coretextdocument.go b/core/coretextdocument.go index e8cc41c..d2725bc 100644 --- a/core/coretextdocument.go +++ b/core/coretextdocument.go @@ -21,6 +21,10 @@ type TextDocument struct { separator string } +func (t *TextDocument) VMTypeString() string { + return "ТекстовыйДокумент" +} + func (t *TextDocument) String() string { return strings.Join(t.lines, t.separator) } diff --git a/core/coretime.go b/core/coretime.go index 7a6f798..4f5e30c 100644 --- a/core/coretime.go +++ b/core/coretime.go @@ -28,7 +28,7 @@ type VMTimeDuration time.Duration var ReflectVMTimeDuration = reflect.TypeOf(VMTimeDuration(0)) -func (v VMTimeDuration) vmval() {} +func (v VMTimeDuration) VMTypeString() string { return "Длительность" } func (v VMTimeDuration) Interface() interface{} { return time.Duration(v) @@ -157,7 +157,7 @@ func fmtInt(buf []byte, v uint64) int { } // EvalBinOp сравнивает два значения или выполняет бинарную операцию -func (x VMTimeDuration) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) { +func (x VMTimeDuration) EvalBinOp(op VMOperation, y VMOperationer) (VMValue, error) { switch op { case ADD: switch yy := y.(type) { @@ -249,7 +249,7 @@ func (x VMTimeDuration) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, er return VMNil, VMErrorUnknownOperation } -func (x VMTimeDuration) ConvertToType(nt reflect.Type) (VMValuer, error) { +func (x VMTimeDuration) ConvertToType(nt reflect.Type) (VMValue, error) { switch nt { case ReflectVMString: return VMString(x.String()), nil @@ -329,7 +329,7 @@ func Now() VMTime { return VMTime(time.Now()) } -func (t VMTime) vmval() {} +func (t VMTime) VMTypeString() string { return "Дата" } func (t VMTime) Interface() interface{} { return time.Time(t) @@ -1028,7 +1028,7 @@ func (t VMTime) ВЛокации(args VMSlice, rets *VMSlice, envout *(*Env)) er } // EvalBinOp сравнивает два значения или выполняет бинарную операцию -func (x VMTime) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) { +func (x VMTime) EvalBinOp(op VMOperation, y VMOperationer) (VMValue, error) { switch op { case ADD: switch yy := y.(type) { @@ -1104,7 +1104,7 @@ func (x VMTime) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) { return VMNil, VMErrorUnknownOperation } -func (x VMTime) ConvertToType(nt reflect.Type) (VMValuer, error) { +func (x VMTime) ConvertToType(nt reflect.Type) (VMValue, error) { switch nt { case ReflectVMString: // сериализуем в json diff --git a/core/coretypes.go b/core/coretypes.go index 2271543..f16960f 100644 --- a/core/coretypes.go +++ b/core/coretypes.go @@ -80,11 +80,6 @@ var OperMapR = map[VMOperation]string{ SHR: ">>", // >> } -// VMValueStruct используется для встраивания в структуры других пакетов для обеспечения возможности соответствия VMValuer интерфейсу -type VMValueStruct struct{} - -func (x VMValueStruct) vmval() {} - type VMBinaryType byte const ( @@ -101,7 +96,7 @@ const ( VMNULL ) -func (x VMBinaryType) ParseBinary(data []byte) (VMValuer, error) { +func (x VMBinaryType) ParseBinary(data []byte) (VMValue, error) { switch x { case VMBOOL: var v VMBool @@ -147,7 +142,7 @@ func (x VMBinaryType) ParseBinary(data []byte) (VMValuer, error) { type VMNilType struct{} -func (x VMNilType) vmval() {} +func (x VMNilType) VMTypeString() string { return "Неопределенность" } func (x VMNilType) String() string { return "Неопределено" } func (x VMNilType) Interface() interface{} { return nil } func (x VMNilType) ParseGoType(v interface{}) { @@ -170,7 +165,7 @@ func (x VMNilType) BinaryType() VMBinaryType { var VMNil = VMNilType{} // EvalBinOp сравнивает два значения или выполняет бинарную операцию -func (x VMNilType) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) { +func (x VMNilType) EvalBinOp(op VMOperation, y VMOperationer) (VMValue, error) { switch op { case ADD: return VMNil, VMErrorIncorrectOperation @@ -259,7 +254,7 @@ func (x *VMNilType) UnmarshalJSON(data []byte) error { type VMNullType struct{} -func (x VMNullType) vmval() {} +func (x VMNullType) VMTypeString() string { return "Null" } func (x VMNullType) null() {} func (x VMNullType) String() string { return "NULL" } func (x VMNullType) Interface() interface{} { return x } @@ -270,7 +265,7 @@ func (x VMNullType) BinaryType() VMBinaryType { var VMNullVar = VMNullType{} // EvalBinOp сравнивает два значения или выполняет бинарную операцию -func (x VMNullType) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) { +func (x VMNullType) EvalBinOp(op VMOperation, y VMOperationer) (VMValue, error) { switch op { case ADD: return VMNil, VMErrorIncorrectOperation @@ -423,7 +418,7 @@ func ReflectToVMValue(rv reflect.Value) VMInterfacer { panic(VMErrorNotConverted) } -func VMValuerFromJSON(s string) (VMValuer, error) { +func VMValuerFromJSON(s string) (VMValue, error) { var i64 int64 var err error if strings.HasPrefix(s, "0x") { @@ -502,11 +497,11 @@ func VMStringMapFromJson(x string) (VMStringMap, error) { return rvms, nil } -func EqualVMValues(v1, v2 VMValuer) bool { +func EqualVMValues(v1, v2 VMValue) bool { return BoolOperVMValues(v1, v2, EQL) } -func BoolOperVMValues(v1, v2 VMValuer, op VMOperation) bool { +func BoolOperVMValues(v1, v2 VMValue, op VMOperation) bool { if xop, ok := v1.(VMOperationer); ok { if yop, ok := v2.(VMOperationer); ok { cmp, err := xop.EvalBinOp(op, yop) @@ -520,7 +515,7 @@ func BoolOperVMValues(v1, v2 VMValuer, op VMOperation) bool { return false } -func SortLessVMValues(v1, v2 VMValuer) bool { +func SortLessVMValues(v1, v2 VMValue) bool { // числа if vi, ok := v1.(VMInt); ok { if vj, ok := v2.(VMInt); ok { diff --git a/core/corewaitgroup.go b/core/corewaitgroup.go index ff97798..d217539 100644 --- a/core/corewaitgroup.go +++ b/core/corewaitgroup.go @@ -14,7 +14,7 @@ type VMWaitGroup struct { var ReflectVMWaitGroup = reflect.TypeOf(VMWaitGroup{}) -func (x *VMWaitGroup) vmval() {} +func (x *VMWaitGroup) VMTypeString() string { return "ГруппаОжидания" } func (x *VMWaitGroup) Interface() interface{} { return x diff --git a/go.mod b/go.mod index 4d0756b..95d9c7a 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/shinanca/gonec -go 1.17 +go 1.18 require ( github.com/Kelwing/mc-rcon v0.0.0-20220214194105-bec8dcbccc3f diff --git a/services/gonecsvc/gonecsvc.go b/services/gonecsvc/gonecsvc.go index 9d50b0e..224c74d 100644 --- a/services/gonecsvc/gonecsvc.go +++ b/services/gonecsvc/gonecsvc.go @@ -31,7 +31,6 @@ func NewGonecInterpreter(header core.VMServiceHeader, args []string, tmode bool) } type VMGonecInterpreterService struct { - core.VMValueStruct hdr core.VMServiceHeader fsArgs []string testingMode bool @@ -42,7 +41,9 @@ type VMGonecInterpreterService struct { lasterr error } -func (x *VMGonecInterpreterService) vmval() {} +func (x *VMGonecInterpreterService) VMTypeString() string { + return "ИнтерпретаторГонца" +} func (x *VMGonecInterpreterService) Header() core.VMServiceHeader { return x.hdr diff --git a/test/core/string_test.gnc b/test/core/string_test.gnc new file mode 100644 index 0000000..747facc --- /dev/null +++ b/test/core/string_test.gnc @@ -0,0 +1 @@ +Сообщить("абоба")