From eb57c6727f45826363b2fc39df67cff1123b89c2 Mon Sep 17 00:00:00 2001 From: "peng.li24" <734991033@qq.com> Date: Sun, 16 Aug 2026 04:48:48 +0000 Subject: [PATCH 1/4] =?UTF-8?q?refactor:=20rwir=20=E5=91=BD=E5=90=8D?= =?UTF-8?q?=E7=A9=BA=E9=97=B4=20/rwir=20=E2=86=92=20/lib?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude --- deepx-design | 2 +- keytree/const.go | 2 -- keytree/sys.go | 5 +++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/deepx-design b/deepx-design index f520f377..45b76a70 160000 --- a/deepx-design +++ b/deepx-design @@ -1 +1 @@ -Subproject commit f520f377aeef0b95ad16880b438d03d15dbdbb9e +Subproject commit 45b76a7030a944164377c2624a0075b559032404 diff --git a/keytree/const.go b/keytree/const.go index 6f2b7392..afd87f5f 100644 --- a/keytree/const.go +++ b/keytree/const.go @@ -26,8 +26,6 @@ const ( SegMsg = "msg" // 终态附加描述 SegSeq = "seq" // vtid 自增序列 - SegRwir = "rwir" // /rwir - ) var ( diff --git a/keytree/sys.go b/keytree/sys.go index 49a39491..a5a67f62 100644 --- a/keytree/sys.go +++ b/keytree/sys.go @@ -1,10 +1,11 @@ package keytree -const RwirRoot = PathSegSep + SegRwir +// RwirRoot rwir 签名统一落在 /lib 下(与 rwfunc 同根,靠 kind 区分)。 +const RwirRoot = LibRoot func Rwir(opcode string) string { return RwirRoot + PathSegSep + opcode } -// RwirRuntime 返回 /rwir/{runtime}/{opcode}。{runtime} 反射自可执行文件名。 +// RwirRuntime 返回 /lib/{runtime}/{opcode}。{runtime} 反射自可执行文件名。 func RwirRuntime(runtime, opcode string) string { return RwirRoot + PathSegSep + runtime + PathSegSep + opcode } From 298ef2215845e9d8b5d1cc2302a81a8da6a7c553 Mon Sep 17 00:00:00 2001 From: "peng.li24" <734991033@qq.com> Date: Sun, 16 Aug 2026 04:48:48 +0000 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20=E6=95=B0=E5=80=BC=20op=20=E6=8C=89?= =?UTF-8?q?=20kind=20=E7=89=B9=E5=8C=96=EF=BC=88registerKinds=20+=20lower.?= =?UTF-8?q?Specialize=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude --- layout/layout.go | 3 +- lower/infer.go | 45 ++++++++++++++++-- lower/specialize.go | 71 ++++++++++++++++++++++++++++ parser/parser.go | 4 +- rwir/builtin/arith.go | 10 ++-- rwir/builtin/bit.go | 12 ++--- rwir/builtin/cmp.go | 12 ++--- rwir/builtin/coerce.go | 12 ++--- rwir/builtin/math.go | 86 +++++++++++++++++++++++++++++++-- rwir/builtin/num.go | 105 +++++++++++++++++++++++++++++++++++++++++ symbol/symbol.go | 2 +- 11 files changed, 327 insertions(+), 35 deletions(-) create mode 100644 lower/specialize.go create mode 100644 rwir/builtin/num.go diff --git a/layout/layout.go b/layout/layout.go index c3a52c02..d6504958 100644 --- a/layout/layout.go +++ b/layout/layout.go @@ -350,6 +350,7 @@ func countDirectInsts(body []ast.Stmt) int32 { // ... func WriteFunc(kv kvspace.KVSpace, pkg string, fn *ast.Func) { typeMap := lower.InferTypes(fn) + lower.Specialize(fn, typeMap) funcDir := keytree.LibFunc(pkg, fn.Sig.Name) kv.DelTree(funcDir) kvspace.MkIndexRecursive(kv, funcDir+"/") @@ -376,7 +377,7 @@ func WriteFunc(kv kvspace.KVSpace, pkg string, fn *ast.Func) { WriteBody(kv, pkg, fn.Sig.Name, fn.Body, typeMap, 1) // 指令从 [1,0] 开始 } -// WriteRwirDecl 将用户声明的 rwir(读写码,无体)写入 /rwir/,kind=rwir。 +// WriteRwirDecl 将用户声明的 rwir(读写码,无体)写入 /lib/,kind=rwir。 func WriteRwirDecl(kv kvspace.KVSpace, decl *ast.RwirDecl) { opcode := decl.Sig.Name if decl.Pkg != "" { diff --git a/lower/infer.go b/lower/infer.go index 02e6af86..f581221a 100644 --- a/lower/infer.go +++ b/lower/infer.go @@ -79,6 +79,14 @@ func inferInst(inst *ast.Instruction, tm map[string]string) { if inst.Expr == nil || len(inst.Writes) == 0 { return } + // 记录显式声明的写类型(如 a:[]int64 → tm[a]="[]int64") + for j, w := range inst.Writes { + if j < len(inst.WriteTypes) && inst.WriteTypes[j] != "" { + if _, exists := tm[w]; !exists { + tm[w] = inst.WriteTypes[j] + } + } + } // 快速路径:叶节点字面量直接从 Lit 字段获取类型,无需 Flat() → slotType() 字符串重解析。 if inst.Expr.IsLeaf() && inst.Expr.Lit != ast.LitNone { if inferred := litToType(inst.Expr.Lit); inferred != "" { @@ -155,12 +163,43 @@ func inferOpType(opcode string, reads []string, tm map[string]string) string { switch opcode { case "kvhas": return "bool" - case "kvlen": + case "kvlen", "len", "string.len", "string.ord", "string.cmp", "string.find": + return "int64" + case "string.char", "string.set", "string.slice", "string.concat": + return "char/utf32" + case "random.int63": + return "int64" + case "random.intn", "random.uint64": + return "uint64" + case "pow", "sqrt", "exp", "log": + return "float64" + case "sign": return "int64" - case "kvat": - // at 的返回类型取决于存储的值,无法静态推断 + case "abs", "neg", "max", "min": + if len(reads) > 0 { + return slotType(reads[0], tm) + } + return "" + case "kvat", "at": + // 从数组首散 key 成员(base.0)或紧凑数组声明([]T)推断元素类型 + if len(reads) > 0 { + if t := tm[reads[0]+".0"]; t != "" { + return t + } + if t := tm[reads[0]]; strings.HasPrefix(t, "[]") { + return t[2:] + } + } return "" case "set": + // set(base, k, v) -> base:记录数组首元素类型(供 kvat 推断元素类型) + if len(reads) >= 3 { + if t := slotType(reads[2], tm); t != "" { + if _, exists := tm[reads[0]+".0"]; !exists { + tm[reads[0]+".0"] = t + } + } + } // set 回写原值,类型同 base if len(reads) > 0 { return slotType(reads[0], tm) diff --git a/lower/specialize.go b/lower/specialize.go new file mode 100644 index 00000000..98a55f38 --- /dev/null +++ b/lower/specialize.go @@ -0,0 +1,71 @@ +package lower + +import ( + "kvlang/ast" + "kvlang/rwir/builtin" + "kvlang/symbol" +) + +// Specialize 将多态数值 op(add/+、eq/== 等)按读参类型特化为 /lib/{kind}/{op}。 +// 选项 A:同 kind 保 kind,混型取更宽(int 按位宽、float 比 int 宽)。 +func Specialize(fn *ast.Func, tm map[string]string) { + specializeBody(fn.Body, tm) +} + +func specializeBody(body []ast.Stmt, tm map[string]string) { + for _, st := range body { + switch s := st.(type) { + case *ast.Instruction: + specializeInst(s, tm) + case *ast.ScopeStmt: + specializeBody(s.Body, tm) + case *ast.IfStmt: + if s.Cond != nil { + specializeInst(s.Cond, tm) + } + specializeBody(s.Then, tm) + specializeBody(s.Else, tm) + case *ast.WhileStmt: + if s.Cond != nil { + specializeInst(s.Cond, tm) + } + specializeBody(s.Body, tm) + case *ast.ForStmt: + specializeBody(s.Body, tm) + } + } +} + +func specializeInst(inst *ast.Instruction, tm map[string]string) { + if inst.Expr == nil || inst.Expr.IsLeaf() { + return + } + opcode := inst.Expr.Op + word := symbol.Lookup(opcode).Word + if word == "" { + word = opcode + } + if !builtin.NumOp(word) { + return + } + kind := "" + for _, arg := range inst.Expr.Args { + t := slotType(arg.Val, tm) + if !builtin.IsNumKind(t) { + continue + } + if kind == "" { + kind = t + } else { + kind = builtin.WiderNumKind(kind, t) + } + } + if kind == "" { + return + } + kind = builtin.OpKind(word, kind) + if kind == "" { + return + } + inst.Expr.Op = kind + "." + word +} diff --git a/parser/parser.go b/parser/parser.go index 77a1dc36..7111437c 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -282,7 +282,7 @@ var validKinds = map[string]bool{ "uint8": true, "uint16": true, "uint32": true, "uint64": true, "float32": true, "float64": true, "bool": true, "char/utf32": true, "char/utf8": true, "char/ascii": true, - "num": true, "any": true, + "any": true, } // validKindexp 校验类型表达式(kindexp):前缀修饰符序列 + 基础 kind。 @@ -337,7 +337,7 @@ func (p *parser) checkParamTypes(sig *ast.FuncSig) { if kind == "string" || kind == "bytes" { return "unknown type — use char/utf32 instead" } - return "unknown type — valid: int8/16/32/64, uint8/16/32/64, float32/64, bool, char/utf32, num, any, []T, [N]T, *T" + return "unknown type — valid: int8/16/32/64, uint8/16/32/64, float32/64, bool, char/utf32, any, []T, [N]T, *T" } for _, param := range sig.Params { if !validKindexp(param.Type) { diff --git a/rwir/builtin/arith.go b/rwir/builtin/arith.go index dc620070..e850242d 100644 --- a/rwir/builtin/arith.go +++ b/rwir/builtin/arith.go @@ -9,11 +9,11 @@ import ( ) func init() { - registerWord("add", "rwir add(A:num, B:num) -> (C:num)", arith{f: func(a, b float64) float64 { return a + b }, fi: func(a, b int64) int64 { return a + b }, concat: true}) - registerWord("sub", "rwir sub(A:num, B:num) -> (C:num)", arith{f: func(a, b float64) float64 { return a - b }, fi: func(a, b int64) int64 { return a - b }, unary: true}) - registerWord("mul", "rwir mul(A:num, B:num) -> (C:num)", arith{f: func(a, b float64) float64 { return a * b }, fi: func(a, b int64) int64 { return a * b }}) - registerWord("div", "rwir div(A:num, B:num) -> (C:num)", div{}) - registerWord("mod", "rwir mod(A:int64, B:int64) -> (C:int64)", mod{}) + registerKinds("add", 2, "", numKinds, arith{f: func(a, b float64) float64 { return a + b }, fi: func(a, b int64) int64 { return a + b }, concat: true}) + registerKinds("sub", 2, "", numKinds, arith{f: func(a, b float64) float64 { return a - b }, fi: func(a, b int64) int64 { return a - b }, unary: true}) + registerKinds("mul", 2, "", numKinds, arith{f: func(a, b float64) float64 { return a * b }, fi: func(a, b int64) int64 { return a * b }}) + registerKinds("div", 2, "", numKinds, div{}) + registerKinds("mod", 2, "", allIntKinds, mod{}) } type arith struct{ f func(float64, float64) float64; fi func(int64, int64) int64; unary, concat bool } diff --git a/rwir/builtin/bit.go b/rwir/builtin/bit.go index 815830e0..3007a1e7 100644 --- a/rwir/builtin/bit.go +++ b/rwir/builtin/bit.go @@ -9,11 +9,11 @@ import ( ) func init() { - registerWord("bitand", "rwir bitand(A:int64, B:int64) -> (C:int64)", bit{f: func(a, b int64) int64 { return a & b }}) - registerWord("bitor", "rwir bitor(A:int64, B:int64) -> (C:int64)", bit{f: func(a, b int64) int64 { return a | b }}) - registerWord("bitxor", "rwir bitxor(A:int64, B:int64) -> (C:int64)", bit{f: func(a, b int64) int64 { return a ^ b }}) - registerWord("shl", "rwir shl(A:int64, B:int64) -> (C:int64)", bit{f: func(a, b int64) int64 { return a << uint64(b) }}) - registerWord("shr", "rwir shr(A:int64, B:int64) -> (C:int64)", bit{f: func(a, b int64) int64 { return a >> uint64(b) }}) + registerKinds("bitand", 2, "", []string{"int64", "uint64"}, bit{f: func(a, b int64) int64 { return a & b }}) + registerKinds("bitor", 2, "", []string{"int64", "uint64"}, bit{f: func(a, b int64) int64 { return a | b }}) + registerKinds("bitxor", 2, "", []string{"int64", "uint64"}, bit{f: func(a, b int64) int64 { return a ^ b }}) + registerKinds("shl", 2, "", []string{"int64", "uint64"}, bit{f: func(a, b int64) int64 { return a << uint64(b) }}) + registerKinds("shr", 2, "", []string{"int64", "uint64"}, bit{f: func(a, b int64) int64 { return a >> uint64(b) }}) } type bit struct{ f func(int64, int64) int64 } @@ -30,5 +30,5 @@ func evalBinaryInt(inputs []kvspace.XValue, fn func(int64, int64) int64) (kvspac } // 位运算仅整数(五语言一致:C/Rust/Go/JS 均禁止浮点位运算,Python & 是 set intersection) if err := requireInt(inputs[0], inputs[1]); err != nil { return kvspace.None{}, err } - return kvspace.NewInt64(fn(asInt64(inputs[0]), asInt64(inputs[1]))), nil + return narrowInt(inputs[0].Kind(), inputs[1].Kind(), fn(asInt64(inputs[0]), asInt64(inputs[1]))), nil } diff --git a/rwir/builtin/cmp.go b/rwir/builtin/cmp.go index 74d030df..4570b429 100644 --- a/rwir/builtin/cmp.go +++ b/rwir/builtin/cmp.go @@ -11,13 +11,13 @@ import ( func init() { eqCmp := cmp{f: func(a, b float64) bool { return a == b }, p: func(c int) bool { return c == 0 }, s: func(a, b string) bool { return a == b }, allowNull: true} - registerWord("eq", "rwir eq(A:num, B:num) -> (C:bool)", eqCmp) + registerKinds("eq", 2, "bool", numKinds, eqCmp) neqCmp := cmp{f: func(a, b float64) bool { return a != b }, p: func(c int) bool { return c != 0 }, s: func(a, b string) bool { return a != b }, allowNull: true} - registerWord("neq", "rwir neq(A:num, B:num) -> (C:bool)", neqCmp) - registerWord("lt", "rwir lt(A:num, B:num) -> (C:bool)", cmp{f: func(a, b float64) bool { return a < b }, p: func(c int) bool { return c < 0 }, s: func(a, b string) bool { return a < b }}) - registerWord("gt", "rwir gt(A:num, B:num) -> (C:bool)", cmp{f: func(a, b float64) bool { return a > b }, p: func(c int) bool { return c > 0 }, s: func(a, b string) bool { return a > b }}) - registerWord("le", "rwir le(A:num, B:num) -> (C:bool)", cmp{f: func(a, b float64) bool { return a <= b }, p: func(c int) bool { return c <= 0 }, s: func(a, b string) bool { return a <= b }}) - registerWord("ge", "rwir ge(A:num, B:num) -> (C:bool)", cmp{f: func(a, b float64) bool { return a >= b }, p: func(c int) bool { return c >= 0 }, s: func(a, b string) bool { return a >= b }}) + registerKinds("neq", 2, "bool", numKinds, neqCmp) + registerKinds("lt", 2, "bool", numKinds, cmp{f: func(a, b float64) bool { return a < b }, p: func(c int) bool { return c < 0 }, s: func(a, b string) bool { return a < b }}) + registerKinds("gt", 2, "bool", numKinds, cmp{f: func(a, b float64) bool { return a > b }, p: func(c int) bool { return c > 0 }, s: func(a, b string) bool { return a > b }}) + registerKinds("le", 2, "bool", numKinds, cmp{f: func(a, b float64) bool { return a <= b }, p: func(c int) bool { return c <= 0 }, s: func(a, b string) bool { return a <= b }}) + registerKinds("ge", 2, "bool", numKinds, cmp{f: func(a, b float64) bool { return a >= b }, p: func(c int) bool { return c >= 0 }, s: func(a, b string) bool { return a >= b }}) } type cmp struct { diff --git a/rwir/builtin/coerce.go b/rwir/builtin/coerce.go index af2760f6..b2904470 100644 --- a/rwir/builtin/coerce.go +++ b/rwir/builtin/coerce.go @@ -180,7 +180,7 @@ func isUnsignedKind(k string) bool { return false } -func intKindWidth(k string) int { +func IntKindWidth(k string) int { switch k { case "int8", "uint8": return 8 @@ -194,8 +194,8 @@ func intKindWidth(k string) int { return 0 } -func widerIntKind(ak, bk string) string { - aw, bw := intKindWidth(ak), intKindWidth(bk) +func WiderIntKind(ak, bk string) string { + aw, bw := IntKindWidth(ak), IntKindWidth(bk) au, bu := isUnsignedKind(ak), isUnsignedKind(bk) if au && bu { if aw >= bw { @@ -225,7 +225,7 @@ func widerIntKind(ak, bk string) string { } } -func widerFloatKind(ak, bk string) string { +func WiderFloatKind(ak, bk string) string { if ak == "float64" || bk == "float64" { return "float64" } @@ -236,7 +236,7 @@ func widerFloatKind(ak, bk string) string { } func narrowInt(ak, bk string, v int64) kvspace.XValue { - kind := widerIntKind(ak, bk) + kind := WiderIntKind(ak, bk) switch kind { case "int8": return kvspace.NewInt8(int8(v)) @@ -260,7 +260,7 @@ func narrowInt(ak, bk string, v int64) kvspace.XValue { } func narrowFloat(ak, bk string, v float64) kvspace.XValue { - if widerFloatKind(ak, bk) == "float32" { + if WiderFloatKind(ak, bk) == "float32" { return kvspace.NewFloat32(float32(v)) } return kvspace.NewFloat64(v) diff --git a/rwir/builtin/math.go b/rwir/builtin/math.go index f5e7884e..fa90405b 100644 --- a/rwir/builtin/math.go +++ b/rwir/builtin/math.go @@ -10,11 +10,15 @@ import ( ) func init() { - Register("math.pow", "rwir math.pow(A:num, B:num) -> (C:float64)", mOp{kind: "pow"}) - registerWord("math.sqrt", "rwir math.sqrt(A:num) -> (C:float64)", mOp{kind: "sqrt"}) - Register("math.exp", "rwir math.exp(A:num) -> (C:float64)", mOp{kind: "exp"}) - Register("math.log", "rwir math.log(A:num) -> (C:float64)", mOp{kind: "log"}) - Register("neg", "rwir neg(A:num) -> (C:num)", mOp{kind: "neg"}) + registerKinds("pow", 2, "float64", floatKinds, mOp{kind: "pow"}) + registerKinds("sqrt", 1, "float64", floatKinds, mOp{kind: "sqrt"}) + registerKinds("exp", 1, "float64", floatKinds, mOp{kind: "exp"}) + registerKinds("log", 1, "float64", floatKinds, mOp{kind: "log"}) + registerKinds("neg", 1, "", signedOrFloatKinds, mOp{kind: "neg"}) + registerKinds("abs", 1, "", signedOrFloatKinds, mOp{kind: "abs"}) + registerKinds("sign", 1, "int64", numKinds, mOp{kind: "sign"}) + registerKinds("max", 2, "", numKinds, mOp{kind: "max"}) + registerKinds("min", 2, "", numKinds, mOp{kind: "min"}) } type mOp struct{ kind string } @@ -33,10 +37,82 @@ func evalMath(kind string, inputs []kvspace.XValue) (kvspace.XValue, error) { case "neg": if err := requireUnary(inputs); err != nil { return kvspace.None{}, err } return evalNeg(inputs[0]) + case "abs": + if err := requireUnary(inputs); err != nil { return kvspace.None{}, err } + return evalAbs(inputs[0]) + case "sign": + if err := requireUnary(inputs); err != nil { return kvspace.None{}, err } + return evalSign(inputs[0]) + case "max": + return evalMaxMin(inputs, true) + case "min": + return evalMaxMin(inputs, false) default: return kvspace.None{}, fmt.Errorf("unknown math: %s", kind) } } +func evalAbs(v kvspace.XValue) (kvspace.XValue, error) { + if isIntKind(v.Kind()) { + iv := asInt64(v) + if iv < 0 { + iv = -iv + } + return narrowInt(v.Kind(), v.Kind(), iv), nil + } + if isFloatKind(v.Kind()) { + return narrowFloat(v.Kind(), v.Kind(), math.Abs(asFloat(v))), nil + } + return kvspace.None{}, fmt.Errorf("TypeError: abs requires numeric, got %s", v.Kind()) +} + +func evalSign(v kvspace.XValue) (kvspace.XValue, error) { + if isIntKind(v.Kind()) { + iv := asInt64(v) + switch { + case iv < 0: + return kvspace.NewInt64(-1), nil + case iv > 0: + return kvspace.NewInt64(1), nil + default: + return kvspace.NewInt64(0), nil + } + } + if isFloatKind(v.Kind()) { + fv := asFloat(v) + switch { + case fv < 0: + return kvspace.NewInt64(-1), nil + case fv > 0: + return kvspace.NewInt64(1), nil + default: + return kvspace.NewInt64(0), nil + } + } + return kvspace.None{}, fmt.Errorf("TypeError: sign requires numeric, got %s", v.Kind()) +} + +func evalMaxMin(inputs []kvspace.XValue, isMax bool) (kvspace.XValue, error) { + if err := requireBinary(inputs); err != nil { + return kvspace.None{}, err + } + a, b := inputs[0], inputs[1] + if isIntKind(a.Kind()) && isIntKind(b.Kind()) { + c := cmpInt(a, b) + if (isMax && c >= 0) || (!isMax && c <= 0) { + return narrowInt(a.Kind(), b.Kind(), asInt64(a)), nil + } + return narrowInt(a.Kind(), b.Kind(), asInt64(b)), nil + } + if isNumeric(a) && isNumeric(b) { + fa, fb := asFloat(a), asFloat(b) + if (isMax && fa >= fb) || (!isMax && fa <= fb) { + return narrowFloat(a.Kind(), b.Kind(), fa), nil + } + return narrowFloat(a.Kind(), b.Kind(), fb), nil + } + return kvspace.None{}, fmt.Errorf("TypeError: max/min requires numeric, got %s and %s", a.Kind(), b.Kind()) +} + func evalPow(inputs []kvspace.XValue) (kvspace.XValue, error) { if err := requireBinary(inputs); err != nil { return kvspace.None{}, err } if err := requireNumeric(inputs[0], inputs[1]); err != nil { return kvspace.None{}, err } diff --git a/rwir/builtin/num.go b/rwir/builtin/num.go new file mode 100644 index 00000000..551a14d4 --- /dev/null +++ b/rwir/builtin/num.go @@ -0,0 +1,105 @@ +package builtin + +import ( + "fmt" +) + +// 数值 kind 集合(按位宽升序)。 +var ( + signedIntKinds = []string{"int8", "int16", "int32", "int64"} + allIntKinds = []string{"int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64"} + floatKinds = []string{"float32", "float64"} + signedOrFloatKinds = []string{"int8", "int16", "int32", "int64", "float32", "float64"} + numKinds = []string{"int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float32", "float64"} +) + +// registerKinds 将 op 注册到指定 kind 集合,opcode = kind.op(如 int64.add、float64.sqrt)。 +// arity 1/2;ret 为返回类型(空串 = 与输入同 kind)。 +func registerKinds(op string, arity int, ret string, kinds []string, impl Rwir) { + for _, k := range kinds { + r := ret + if r == "" { + r = k + } + sig := fmt.Sprintf("rwir %s(A:%s) -> (C:%s)", op, k, r) + if arity == 2 { + sig = fmt.Sprintf("rwir %s(A:%s, B:%s) -> (C:%s)", op, k, k, r) + } + Register(k+"."+op, sig, impl) + } + // 裸 op + 字形回退:非数值输入(字符串/未知类型)走此路径 → TypeError 或拼接/比较 + r := ret + if r == "" { + r = "any" + } + sig := fmt.Sprintf("rwir %s(A:any) -> (C:%s)", op, r) + if arity == 2 { + sig = fmt.Sprintf("rwir %s(A:any, B:any) -> (C:%s)", op, r) + } + registerWord(op, sig, impl) +} + +// NumOp 判断 opcode 是否为多态数值 op(供 lower 特化)。 +func NumOp(opcode string) bool { + switch opcode { + case "add", "sub", "mul", "div", "neg", "mod", + "bitand", "bitor", "bitxor", "shl", "shr", + "eq", "neq", "lt", "le", "gt", "ge", + "pow", "sqrt", "exp", "log", + "abs", "sign", "max", "min": + return true + } + return false +} + +// IsNumKind 判断 kind 字符串是否为数值。 +func IsNumKind(k string) bool { return isIntKind(k) || isFloatKind(k) } + +// WiderNumKind 返回两个数值 kind 中更宽者(int 按位宽,float 比 int 宽,float64 比 float32 宽)。 +func WiderNumKind(ak, bk string) string { + if isIntKind(ak) && isIntKind(bk) { + return WiderIntKind(ak, bk) + } + if isFloatKind(ak) && isFloatKind(bk) { + return WiderFloatKind(ak, bk) + } + if isFloatKind(ak) { + return ak + } + return bk +} + +// OpKind 返回 op 在给定输入 kind 下的注册 kind("" 表示该 kind 无此 op)。 +// 规则:uint 无 neg/abs;float 无 mod;int/uint 无 pow/sqrt/exp/log(int 提升为 float64)。 +func OpKind(op, k string) string { + if !IsNumKind(k) { + return "" + } + switch op { + case "pow", "sqrt", "exp", "log": + if isFloatKind(k) { + return k + } + return "float64" + case "mod": + if isIntKind(k) { + return k + } + return "" + case "bitand", "bitor", "bitxor", "shl", "shr": + if isIntKind(k) { + if isUnsignedKind(k) { + return "uint64" + } + return "int64" + } + return "" + case "neg", "abs": + if isUnsignedKind(k) { + return "" + } + return k + default: + return k + } +} diff --git a/symbol/symbol.go b/symbol/symbol.go index 34b76ab6..a94d79d4 100644 --- a/symbol/symbol.go +++ b/symbol/symbol.go @@ -50,7 +50,7 @@ var byWord = map[string]Entry{ "or": {"or", []string{"||"}, 10, false, true, false}, "not": {"not", []string{"!"}, 0, false, true, true}, // ── 数学符号 ────────────────────────────────────────────────── - "math.sqrt": {"math.sqrt", []string{"√"}, 0, true, false, true}, + "sqrt": {"sqrt", []string{"√"}, 0, true, false, true}, // ── 位运算 ──────────────────────────────────────────────────── "bitand": {"bitand", []string{"&"}, 80, true, false, false}, From 5b78b40616f185326574e03431eb14e5a47c3174 Mon Sep 17 00:00:00 2001 From: "peng.li24" <734991033@qq.com> Date: Sun, 16 Aug 2026 04:48:49 +0000 Subject: [PATCH 3/4] =?UTF-8?q?test:=20=E5=90=8C=E6=AD=A5=20stdlib/tutoria?= =?UTF-8?q?l/error=5Fcases=20=E5=88=B0=20kind=20=E7=89=B9=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude --- stdlib/math.kv | 38 +------------------ tutorial/01-basics/arith.kv | 4 +- tutorial/01-basics/strict_types.kv | 12 +++--- .../error_cases/type_error/minmax_mixed.kv | 6 +-- .../error_cases/type_error/sqrt_string.kv | 2 +- tutorial/error_cases/value_error/log_range.kv | 2 +- 6 files changed, 14 insertions(+), 50 deletions(-) diff --git a/stdlib/math.kv b/stdlib/math.kv index 73e27fbb..9dda4f1c 100644 --- a/stdlib/math.kv +++ b/stdlib/math.kv @@ -1,41 +1,5 @@ lib math { /lib/math.Pi = 3.141592653589793 /lib/math.E = 2.718281828459045 - /lib/math.Tau = 6.283185307179586 - - rwfunc abs(x:num) -> (r:num) { - if (x < 0) { - -x -> r - } else { - x -> r - } - } - - rwfunc sign(x:num) -> (r:int64) { - if (x > 0) { - 1 -> r - } else { - if (x < 0) { - -1 -> r - } else { - 0 -> r - } - } - } - - rwfunc max(a:num, b:num) -> (r:num) { - if (a > b) { - a -> r - } else { - b -> r - } - } - - rwfunc min(a:num, b:num) -> (r:num) { - if (a < b) { - a -> r - } else { - b -> r - } - } + /lib/math.Tau = 6.283179586 } diff --git a/tutorial/01-basics/arith.kv b/tutorial/01-basics/arith.kv index 5e579d68..0db8cff0 100644 --- a/tutorial/01-basics/arith.kv +++ b/tutorial/01-basics/arith.kv @@ -30,10 +30,10 @@ rwfunc main() -> () { 10 % 3 -> mod_r println("mod:", mod_r) - pow_r <- math.pow(2, 5) + pow_r <- pow(2, 5) println("pow:", pow_r) - sqrt_r = math.sqrt(144) # = 等价于 <- + sqrt_r = sqrt(144) # = 等价于 <- println("sqrt:", sqrt_r) sqrt_r2 = √(144) # = 等价于 <- println("sqrt(√):", sqrt_r2) diff --git a/tutorial/01-basics/strict_types.kv b/tutorial/01-basics/strict_types.kv index dc256892..622cb93e 100644 --- a/tutorial/01-basics/strict_types.kv +++ b/tutorial/01-basics/strict_types.kv @@ -54,19 +54,19 @@ rwfunc main() -> () { println(j) # 数学函数 — 仅数字 - math.sqrt(64.0) -> k + sqrt(64.0) -> k √(64.0) -> k_m println(k_m) println(k) - math.abs(-3) -> l + abs(-3) -> l println(l) - math.pow(2, 3) -> m + pow(2, 3) -> m println(m) - math.log(math.exp(1.0)) -> n + log(exp(1.0)) -> n println(n) - # min/max — 全数字(math.max 嵌套 fold) - math.max(math.max(1, 3), 2) -> o + # min/max — 全数字(max 嵌套 fold) + max(max(1, 3), 2) -> o println(o) # 字符串拼接 diff --git a/tutorial/error_cases/type_error/minmax_mixed.kv b/tutorial/error_cases/type_error/minmax_mixed.kv index 33294b0d..f8fa3cc3 100644 --- a/tutorial/error_cases/type_error/minmax_mixed.kv +++ b/tutorial/error_cases/type_error/minmax_mixed.kv @@ -1,7 +1,7 @@ # expected -# TypeError: cannot compare int64 with char/utf32 -# 修复: min/max 现为 math.min/math.max rwfunc,混类型在 < 比较处 TypeError +# TypeError: max/min requires numeric, got int64 and char/utf32 +# 修复: min/max 现为 native 逐 kind op,混类型在运行时 TypeError rwfunc main() -> () { - math.min(int64(1), "a") -> x + min(int64(1), "a") -> x } main() diff --git a/tutorial/error_cases/type_error/sqrt_string.kv b/tutorial/error_cases/type_error/sqrt_string.kv index 7eb9c39b..2d398f10 100644 --- a/tutorial/error_cases/type_error/sqrt_string.kv +++ b/tutorial/error_cases/type_error/sqrt_string.kv @@ -2,7 +2,7 @@ # TypeError: expected numeric, got char/utf32 # 修复: todo-033 — sqrt/exp/log/sign 曾通过 asFloat default 将 "hello"→0.0 静默计算 rwfunc main() -> () { - math.sqrt("hello") -> x + sqrt("hello") -> x √("hello") -> x_m } main() diff --git a/tutorial/error_cases/value_error/log_range.kv b/tutorial/error_cases/value_error/log_range.kv index 0ce9182d..fd124bf9 100644 --- a/tutorial/error_cases/value_error/log_range.kv +++ b/tutorial/error_cases/value_error/log_range.kv @@ -1,3 +1,3 @@ # expected: # error: ValueError: log of non-positive number -math.log(-5) -> _ +log(-5) -> _ From 73ea9c39186a5b6dda1748aef84b3676037c6f0b Mon Sep 17 00:00:00 2001 From: "peng.li24" <734991033@qq.com> Date: Sun, 16 Aug 2026 04:48:49 +0000 Subject: [PATCH 4/4] =?UTF-8?q?chore:=20=E6=96=B0=E5=A2=9E=20issue=20?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude --- .github/ISSUE_TEMPLATE/issue.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/issue.md diff --git a/.github/ISSUE_TEMPLATE/issue.md b/.github/ISSUE_TEMPLATE/issue.md new file mode 100644 index 00000000..27f84f04 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/issue.md @@ -0,0 +1,25 @@ +--- +name: 通用 issue +about: 提交一个 kvlang issue(标题格式:类别/子类/题目) +title: "类别/子类/题目" +labels: [] +--- + + + + + +## 背景 + +## 需求描述 + +## 预期结果 + +## 方案简述