package muesli import "fmt" import "log" import "runtime" import "strings" import "sort" type LogTracer struct { } func (t LogTracer) Trace(vm VM, ast Ast, val ... Value) bool { log.Printf("Trace: %s -> %v", ast.String(), val) return false } type FmtTracer struct { } func (t FmtTracer) Trace(vm VM, ast Ast, args ... Value) bool { arg := args[0] rest := args[1:len(args)] fmt.Printf("Trace: %s: %v -> ", ast.String(), arg) for _, v := range rest { fmt.Printf("%v, ", v) } fmt.Printf("<-\n ") return false } func printf(vm *VM, args ...Value) []Value { var format string rest, err := ParseArgs(args, &format) if err != nil { return Fail(err) } extra := ListFromList(rest) fmt.Printf(format, extra...) return None() } func println(vm *VM, args ...Value) []Value { var msg string _, err := ParseArgs(args, &msg) if err != nil { return Fail(err) } else { fmt.Println(msg) } return None() } func p(vm *VM, args ...Value) []Value { for _, arg := range args { fmt.Printf("%v\n", arg) } return None() } func trace(vm *VM, args ...Value) []Value { var b bool = true fmt.Printf("command trace: %v\n", args) _, err := ParseArgs(args, &b) if err != nil { fmt.Printf("Error: %s\n", err.Error()) return Fail(err) } fmt.Printf("command trace: bool: %v\n", b) if b { vm.Tracer = FmtTracer{} } else { vm.Tracer = nil } return Ok(BoolValue(b)) } func sumi(vm *VM, args ...Value) []Value { slice, err := ParseArgsToIntSlice(args) if err != nil { fmt.Printf("Error: %s\n", err.Error()) return Fail(err) } res := int(0) for _, val := range slice { res += val } return IntOk(res) } func sumf(vm *VM, args ...Value) []Value { slice, err := ParseArgsToFloat64Slice(args) if err != nil { fmt.Printf("Error: %s\n", err.Error()) return Fail(err) } res := float64(0) for _, val := range slice { res += val } return FloatOk(res) } func addi(vm *VM, args ...Value) []Value { var v1, v2 int _, err := ParseArgs(args, &v1, &v2) if err != nil { return Fail(err) } return IntOk(v1 + v2) } func addf(vm *VM, args ...Value) []Value { var v1, v2 float64 _, err := ParseArgs(args, &v1, &v2) if err != nil { return Fail(err) } return FloatOk(v1 + v2) } func subi(vm *VM, args ...Value) []Value { var v1, v2 int _, err := ParseArgs(args, &v1, &v2) if err != nil { return Fail(err) } return IntOk(v1 - v2) } func subf(vm *VM, args ...Value) []Value { var v1, v2 float64 _, err := ParseArgs(args, &v1, &v2) if err != nil { return Fail(err) } return FloatOk(v1 - v2) } func muli(vm *VM, args ...Value) []Value { var v1, v2 int _, err := ParseArgs(args, &v1, &v2) if err != nil { return Fail(err) } return IntOk(v1 * v2) } func mulf(vm *VM, args ...Value) []Value { var v1, v2 float64 _, err := ParseArgs(args, &v1, &v2) if err != nil { return Fail(err) } return FloatOk(v1 * v2) } func divi(vm *VM, args ...Value) []Value { var v1, v2 int _, err := ParseArgs(args, &v1, &v2) if err != nil { return Fail(err) } return IntOk(v1 / v2) } func divf(vm *VM, args ...Value) []Value { var v1, v2 float64 _, err := ParseArgs(args, &v1, &v2) if err != nil { return Fail(err) } return FloatOk(v1 / v2) } func val(vm *VM, args ...Value) []Value { if len(args) < 1 { return []Value{NewErrorValuef("val requres at least one argument.")} } return args } func to(vm *VM, args ...Value) []Value { var name string rest, err := ParseArgs(args, &name) if err != nil { return Fail(err) } if len(rest) < 1 { return Fail(NewErrorValuef("Need at least 2 arguments: %v", args)) } last := rest[len(rest)-1] block, isBlock := last.(*BlockValue) if ! isBlock { return Fail(NewErrorValuef("Not a block: %v", last)) } param := rest[0:len(rest)-1] defpars := []*Parameter{} for i := 1 ; i < len(param) ; i += 2 { par := &Parameter{} name := param[i-1] typ := param[i] var ok bool if par.Name, ok = name.(WordValue); !ok { return Fail(NewErrorValuef("Not a word value: %v", name)) } if par.Type, ok = typ.(TypeValue); !ok { return Fail(NewErrorValuef("Not a type value: %v", typ)) } defpars = append(defpars, par) } return Ok(vm.RegisterDefined(name, defpars, block)) } func cover(vm *VM, args ...Value) []Value { var name, target string rest, err := ParseArgs(args, &name, &target) if err != nil { return Fail(err) } types := []TypeValue{} for i, arg := range rest { if typ, ok := arg.(TypeValue) ; ok { types = append(types, typ) } else { return Fail(NewErrorValuef("Argument %d: not a type: %v %s", i+2, arg, arg.String())) } } err = vm.AddOverload(name, target, types...) if err != nil { return Fail(err) } return Ok() } func types(vm *VM, args ...Value) []Value { result := []Value{} for i, arg := range args { typ := arg.Type() result = append(result, typ) fmt.Printf("Type %d: %s\n", i, typ.String()) } return Ok(NewListValue(result...)) } func set(vm *VM, val ...Value) []Value { if len(val) < 2 { return Fail(fmt.Errorf("set needs at least 2 arguments: received %v", val)) } target := val[0].String() value := val[1] if target == "(" || target == "$" { if len(val) < 3 { return Fail(fmt.Errorf("indirect get needs results: received %v", val)) } target = val[1].String() value = val[2] } vm.Register(target, value) return Ok(value) } func get(vm *VM, val ...Value) []Value { if len(val) < 1 { return Fail(fmt.Errorf("get needs at least 1 argument")) } target := val[0].String() if target == "(" || target == "$" { if len(val) < 2 { return Fail(fmt.Errorf("indirect get needs results: received %v", val)) } target = val[1].String() } return Ok(vm.Lookup(target)) } func help(vm *VM, val ...Value) [] Value { if len(val) < 1 { fmt.Printf("help will display help on the callable\n\nThe following commands are available:\n") helpers := vm.DefinedHelpers() sort.SliceStable(helpers, func(i, j int) bool { return helpers[i].HelperName() < helpers[j].HelperName() }) for _, helper := range helpers { fl := strings.SplitN(helper.Help(),"\n", 2) fmt.Printf("%s %s: \n", helper.HelperName(), fl[0]) } return Ok() } targetName := val[0].String() target := vm.Lookup(targetName) if target == nil { fmt.Printf("help: %s not found.\n", targetName) } if helper, isHelper := target.(Helper) ; isHelper { help := helper.Help() fmt.Printf("%s: %s.\n", targetName, help) return Ok(StringValue(help)) } return Ok() } func explain(vm *VM, val ...Value) [] Value { var target, help string _, err := ParseArgs(val, &target, &help) if err != nil { return Fail(err) } err = vm.SetHelp(target, help) if err != nil { return Fail(err) } return Ok(StringValue(help)) } func exit(vm *VM, val ...Value) [] Value { var code int _, err := ParseArgs(val, &code) if err != nil { runtime.Goexit() } vm.ExitStatus = code runtime.Goexit() return Ok() } func (vm *VM) RegisterBuiltins() { vm.RegisterBuiltinWithHelp("addi", addi, `[Int Int] -> Int: adds two integers together`) vm.RegisterBuiltinWithHelp("addf", addf, `[Int Int] -> Int: adds two floats together`) vm.RegisterBuiltin("cover", cover) vm.RegisterBuiltin("sumi", sumi) vm.RegisterBuiltin("sumf", sumf) vm.RegisterBuiltin("subi", subi) vm.RegisterBuiltin("subf", subf) vm.RegisterBuiltin("divi", divi) vm.RegisterBuiltin("divf", divf) vm.RegisterBuiltin("muli", muli) vm.RegisterBuiltin("mulf", mulf) err := vm.AddOverload("mul", "mulf", FloatTypeValue, FloatTypeValue) if err != nil { fmt.Printf("Errror registering overload: %s", err) } err = vm.AddOverload("mul", "muli", IntTypeValue, IntTypeValue) if err != nil { fmt.Printf("Errror registering overload: %s", err) } err = vm.AddOverload("mul", "mulf", FloatTypeValue, IntTypeValue) if err != nil { fmt.Printf("Errror registering overload: %s", err) } err = vm.AddOverload("mul", "mulf", IntTypeValue, FloatTypeValue) if err != nil { fmt.Printf("Errror registering overload: %s", err) } // vm.RegisterCover("add") vm.RegisterBuiltin("p", p) vm.RegisterBuiltin("println", println) vm.RegisterBuiltin("printf", printf) vm.RegisterBuiltin("trace", trace) vm.RegisterBuiltin("to", to) vm.RegisterBuiltin("types", types) vm.RegisterBuiltin("val", val) vm.RegisterBuiltin("set", set) vm.RegisterBuiltin("get", get) vm.RegisterBuiltin("help", help) vm.RegisterBuiltin("explain", explain) vm.RegisterBuiltin("exit", exit) vm.SetHelp("mul", " Num: Multiplies two numbers. Cover for muli and mulf.") }