Skip to content

Commit

Permalink
feat: 增加了一种load回调; 增加内置函数typeId和Computed.compute
Browse files Browse the repository at this point in the history
  • Loading branch information
fy0 committed Jul 19, 2024
1 parent 345cdd7 commit 313e972
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 8 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ https://sealdice.github.io/dicescript/
## TODO

* 骰点运算 - 自定义算符
* computed 的repr格式无法读入

## 开发

Expand Down
6 changes: 6 additions & 0 deletions builtin_functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ func funcRepr(ctx *Context, this *VMValue, params []*VMValue) *VMValue {
return NewStrVal(params[0].ToRepr())
}

func funcTypeId(ctx *Context, this *VMValue, params []*VMValue) *VMValue {
return NewIntVal(IntType(params[0].TypeId))
}

func funcLoad(ctx *Context, this *VMValue, params []*VMValue) *VMValue {
v := params[0]
if v.TypeId != VMTypeString {
Expand Down Expand Up @@ -186,11 +190,13 @@ var builtinValues = map[string]*VMValue{

"repr": nnf(&ndf{"repr", []string{"value"}, nil, nil, funcRepr}),
"load": nnf(&ndf{"load", []string{"value"}, nil, nil, nil}),

// TODO: roll()

// 要不要进行权限隔绝?
"dir": nnf(&ndf{"dir", []string{"value"}, nil, nil, funcDir}),
// "help": nnf(&ndf{"help", []string{"value"}, nil, nil, funcHelp}),
"typeId": nnf(&ndf{"typeId", []string{"value"}, nil, nil, funcTypeId}),
}

func _init() bool {
Expand Down
8 changes: 8 additions & 0 deletions builtin_functions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,11 @@ func TestNativeFunctionLoad(t *testing.T) {
assert.True(t, valueEqual(vm.Ret, builtinValues["load"]))
}
}

func TestNativeFunctionTypeId(t *testing.T) {
vm := NewVM()
err := vm.Run("typeId(1)")
if assert.NoError(t, err) {
assert.True(t, valueEqual(vm.Ret, ni(IntType(VMTypeInt))))
}
}
36 changes: 30 additions & 6 deletions rollvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ func (ctx *Context) evaluate() {
}
stackPush(ret)
} else {
ctx.Error = errors.New("类型错误: 无法调用,必须是一个函数")
ctx.Error = fmt.Errorf("类型错误: [%s]无法被调用,必须是一个函数", funcObj.ToString())
}

case typeItemGet:
Expand Down Expand Up @@ -717,27 +717,51 @@ func (ctx *Context) evaluate() {
case typeLoadName, typeLoadNameRaw, typeLoadNameWithDetail:
name := code.Value.(string)
var val *VMValue
if typeLoadNameWithDetail == code.T {

withDetail := typeLoadNameWithDetail == code.T
if withDetail {
detail := &details[len(details)-1]
detail.Tag = "load"
detail.Text = ""

val = ctx.LoadNameWithDetail(name, typeLoadNameRaw == code.T, true, detail)
detail.Ret = val
val = ctx.LoadNameWithDetail(name, true, true, detail)
} else {
val = ctx.LoadName(name, typeLoadNameRaw == code.T, true)
val = ctx.LoadName(name, true, true)
}
if ctx.Error != nil {
return
}

// computed 回调
if ctx.Config.HookFuncValueLoadOverwriteBeforeComputed != nil {
val = ctx.Config.HookFuncValueLoadOverwriteBeforeComputed(ctx, name, val)
}

// 计算真实结果
isRaw := typeLoadNameRaw == code.T
if !isRaw && val.TypeId == VMTypeComputedValue {
detail := &details[len(details)-1]
val = val.ComputedExecute(ctx, detail)
if ctx.Error != nil {
return
}
}

// 追加计算结果到detail
if withDetail {
detail := &details[len(details)-1]
detail.Ret = val
}

if ctx.Config.HookFuncValueLoadOverwrite != nil {
if len(details) > 0 {
oldRet := details[len(details)-1].Ret
val = ctx.Config.HookFuncValueLoadOverwrite(ctx, name, val, &details[len(details)-1])
if oldRet == details[len(details)-1].Ret {
// 如果ret发生变化才修改,顺便修改detail中的结果为最终结果
details[len(details)-1].Ret = val
}
} else {
val = ctx.Config.HookFuncValueLoadOverwrite(ctx, name, val, &BufferSpan{})
}
}
stackPush(val)
Expand Down
12 changes: 12 additions & 0 deletions rollvm_callback_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,15 @@ func TestGlobalValueLoadOverwrite(t *testing.T) {
assert.Equal(t, vm.Ret.TypeId, VMTypeNativeFunction)
}
}

func TestHookFuncValueLoadOverwrite(t *testing.T) {
vm := NewVM()
vm.Config.HookFuncValueLoadOverwrite = func(ctx *Context, name string, curVal *VMValue, detail *BufferSpan) *VMValue {
return ni(123)
}

err := vm.Run("测试")
if assert.NoError(t, err) {
assert.True(t, valueEqual(vm.Ret, ni(123)))
}
}
2 changes: 1 addition & 1 deletion rollvm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1028,7 +1028,7 @@ func TestDiceCocExpr(t *testing.T) {
err = vm.Run("b")
if assert.NoError(t, err) {
assert.Equal(t, "", vm.RestInput)
assert.True(t, vm.Ret.MustReadInt() > 1)
assert.True(t, vm.Ret.MustReadInt() >= 1)
}

err = vm.Run("b技能") // rab技能,这种不予修改,由指令那边做支持
Expand Down
2 changes: 2 additions & 0 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ type RollConfig struct {
HookFuncValueStore func(ctx *Context, name string, v *VMValue) (overwrite *VMValue, solved bool)
// 如果overwrite不为nil,将结束值加载并使用overwrite值。如果为nil,将以newName为key进行加载
HookFuncValueLoad func(ctx *Context, name string) (newName string, overwrite *VMValue)
// 读取后回调(返回值将覆盖之前读到的值。如果之前未读取到值curVal将为nil,这个回调处于computed计算之前)
HookFuncValueLoadOverwriteBeforeComputed func(ctx *Context, name string, curVal *VMValue) *VMValue
// 读取后回调(返回值将覆盖之前读到的值。如果之前未读取到值curVal将为nil)
HookFuncValueLoadOverwrite func(ctx *Context, name string, curVal *VMValue, detail *BufferSpan) *VMValue

Expand Down
16 changes: 16 additions & 0 deletions types_methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import (
"math/rand"
)

func funcComputedCompute(ctx *Context, this *VMValue, params []*VMValue) *VMValue {
return this.ComputedExecute(ctx, nil)
}

func funcArrayKeepLow(ctx *Context, this *VMValue, params []*VMValue) *VMValue {
isAllInt, ret := this.ArrayFuncKeepLow(ctx, params[0].MustReadInt())
if isAllInt {
Expand Down Expand Up @@ -142,6 +146,9 @@ func funcDictLen(ctx *Context, this *VMValue, params []*VMValue) *VMValue {
}

var builtinProto = map[VMValueType]*VMDictValue{
VMTypeComputedValue: NewDictValWithArrayMust(
NewStrVal("compute"), nnf(&ndf{"Computed.compute", []string{}, nil, nil, nil}),
),
VMTypeArray: NewDictValWithArrayMust(
NewStrVal("kh"), nnf(&ndf{"Array.kh", []string{"num"}, []*VMValue{NewIntVal(1)}, nil, funcArrayKeepHigh}),
NewStrVal("kl"), nnf(&ndf{"Array.kl", []string{"num"}, []*VMValue{NewIntVal(1)}, nil, funcArrayKeepLow}),
Expand Down Expand Up @@ -185,3 +192,12 @@ func getBindMethod(v *VMValue, funcDef *VMValue) *VMValue {
}
return nil
}

func _init2() bool {
// 因循环引用问题无法在上面声明
funcCompute := nnf(&ndf{"Computed.compute", []string{}, nil, nil, funcComputedCompute})
builtinProto[VMTypeComputedValue].Store("compute", funcCompute)
return false
}

var _ = _init2()
14 changes: 13 additions & 1 deletion types_methods_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
package dicescript

import (
"github.com/stretchr/testify/assert"
"testing"

"github.com/stretchr/testify/assert"
)

func TestTypesMethodComputedCompute(t *testing.T) {
_attrs := &ValueMap{}
_attrs.Store("x", ni(1))
c := NewComputedValRaw(&ComputedData{Expr: "this.x + 10", Attrs: _attrs})

vm := NewVM()
ret := funcComputedCompute(vm, c, nil)

assert.Equal(t, ret.ToString(), "11")
}

func TestTypesMethodArraySum(t *testing.T) {
d := NewArrayVal(ni(1), nf(2.2), ni(3))
v := funcArraySum(nil, d, nil)
Expand Down

0 comments on commit 313e972

Please sign in to comment.