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 andb(vm * VM, args ...Value) []Value { var v1, v2 bool _, err := ParseArgs(args, &v1, &v2) if err != nil { return Fail(err) } return BoolOk(v1 && v2) } func orb(vm * VM, args ...Value) []Value { var v1, v2 bool _, err := ParseArgs(args, &v1, &v2) if err != nil { return Fail(err) } return BoolOk(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 builtin_return(vm *VM, args ...Value) []Value { vm.Frame.returned = true vm.Frame.results = args 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) } // To must register one level up. return Ok(vm.RegisterDefined(name, defpars, block, 1)) } 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())) } } // Overload must be defined one scope up. err = vm.AddOverload(name, target, 1, 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.RegisterUp(target, value, 1) 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 fetchl(vm *VM, args ...Value) []Value { var index int var list *ListValue _, err := ParseArgs(args, &list, &index) if err != nil { return Fail(err) } return Ok(list.List[index]) } func storel(vm *VM, args ...Value) []Value { var index int var list *ListValue rest, err := ParseArgs(args, &list, &index) if err != nil { return Fail(err) } if len (rest) < 1 { return Fail(fmt.Errorf("fetch: need 3 arguments")) } list.List[index] = rest[0] return Ok(list.List[index]) } func fetchm(vm *VM, args ...Value) []Value { var index Value var hmap *MapValue _, err := ParseArgs(args, &hmap, &index) if err != nil { return Fail(err) } return Ok(hmap.Map[index]) } func storem(vm *VM, args ...Value) []Value { var index Value var hmap *MapValue rest, err := ParseArgs(args, &hmap, &index) if err != nil { return Fail(err) } if len (rest) < 1 { return Fail(fmt.Errorf("fetch: need 3 arguments")) } hmap.Map[index] = rest[0] return Ok(hmap.Map[index]) } func newmap(vm *VM, args ...Value) []Value { result := make(map[Value] Value) for i := 1; i < len(args) ; i+=2 { result[args[i-1]] = args[i] } return Ok(NewMapValue(result)) } 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.RegisterBuiltinWithHelp("andb", andb, `[Bool Bool] -> Bool: returns true if all it's arguments are true`) vm.RegisterBuiltin("cover", cover) vm.RegisterBuiltin("fetchl", fetchl) vm.RegisterBuiltin("fetchm", fetchm) 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("map", newmap) vm.RegisterBuiltin("muli", muli) vm.RegisterBuiltin("mulf", mulf) vm.RegisterBuiltinWithHelp("orb", orb, `[Bool Bool] -> Bool: returns true if on of it's arguments is true`) // vm.RegisterCover("add") vm.RegisterBuiltin("p", p) vm.RegisterBuiltin("println", println) vm.RegisterBuiltin("printf", printf) vm.RegisterBuiltin("storel", storel) vm.RegisterBuiltin("storem", storem) vm.RegisterBuiltin("trace", trace) vm.RegisterBuiltin("to", to) vm.RegisterBuiltin("types", types) vm.RegisterBuiltin("return", builtin_return) 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.AddOverloads("mul", Over("mulf", 0, FloatTypeValue, FloatTypeValue), Over("muli", 0, IntTypeValue, IntTypeValue), Over("mulf", 0, FloatTypeValue, IntTypeValue), Over("mulf", 0, FloatTypeValue, IntTypeValue)) vm.SetHelp("mul", " Num: Multiplies two numbers. Cover for muli and mulf.") vm.AddOverloads("fetch", Over("fetchl", 0, ListTypeValue, IntTypeValue), Over("fetchm", 0, MapTypeValue, AnyTypeValue), ) vm.SetHelp("fetch", " storage, index. Fetch value in storage at given index.") /* vm.AddOverloads("store", Over("storel", ListTypeValue, IntTypeValue, AnyTypeValue), Over("storem", MapTypeValue, AnyTypeValue, AnyTypeValue), ) vm.SetHelp("store", " storage, index, value. Store value in storage at given index.") */ }