123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618 |
- package muesli
- import "runtime"
- import "strings"
- import "sort"
- type LogTracer struct {
- }
- func (t LogTracer) Trace(vm VM, fmt string, args ... interface{}) bool {
- args = append([]interface{}{vm.BackTrace()}, args...)
- vm.Log("TRACE", "builtin.go", 12, "%s: " + vm.BackTrace() + fmt, args...)
- return false
- }
- type FmtTracer struct {
- }
- func (t FmtTracer) Trace(vm VM, fm string, args ... interface{}) bool {
- args = append([]interface{}{vm.BackTrace()}, args...)
- vm.Printf("%s: " + fm + "\n", args...)
- 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)
- vm.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 {
- vm.Println(msg)
- }
- return None()
- }
- func p(vm *VM, args ...Value) []Value {
- for _, arg := range args {
- vm.Printf("%v\n", arg)
- }
- return None()
- }
- func trace(vm *VM, args ...Value) []Value {
- var b bool = true
- vm.Printf("command trace: %v\n", args)
- _, err := ParseArgs(args, &b)
- if err != nil {
- vm.Printf("Error: %s\n", err.Error())
- return Fail(err)
- }
- vm.Printf("command trace: bool: %v\n", b)
- if b {
- vm.Tracer = vm.Console // FmtTracer{}
- } else {
- vm.Tracer = nil
- }
- return Ok(BoolValue(b))
- }
- func sumi(vm *VM, args ...Value) []Value {
- slice, err := ParseArgsToIntSlice(args)
- if err != nil {
- vm.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 {
- vm.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
- ParseArgs(args, &v1, &v2)
- 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
- vm.Trace("Returning... %v", vm.Frame)
- 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 := args[1:len(args)-1]
- sign, err := NewSignatureWithNames(param...)
- if err != nil {
- return Fail(NewErrorValuef("Could not parse arguments: %v: %s", name, err))
- }
-
- // To must register one level up.
- return Ok(vm.RegisterDefined(name, sign, 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 _, arg := range args {
- typ := arg.Type()
- result = append(result, typ)
- }
- return Ok(NewListValue(result...))
- }
- func set(vm *VM, val ...Value) []Value {
- if len(val) < 2 {
- return Fail(vm.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(vm.Errorf("indirect get needs results: received %v", val))
- }
- target = val[1].String()
- value = val[2]
- }
- level := 1
- if len(val) > 2 {
- upval := val[2]
- if upval.Type() == IntType {
- upval.Convert(&level)
- } else if upval.String() == "top" {
- vm.RegisterTop(target, value)
- return Ok(value)
- }
- }
- vm.RegisterUp(target, value, level)
- return Ok(value)
- }
- func get(vm *VM, val ...Value) []Value {
- if len(val) < 1 {
- return Fail(vm.Errorf("get needs at least 1 argument"))
- }
- target := val[0].String()
- if target == "(" || target == "$" {
- if len(val) < 2 {
- return Fail(vm.Errorf("indirect get needs results: received %v", val))
- }
- target = val[1].String()
- }
- return Ok(vm.Lookup(target))
- }
- func addl(vm *VM, args ...Value) []Value {
- var value Value
- var list *ListValue
- _, err := ParseArgs(args, &list, &value)
- if err != nil {
- return Fail(err)
- }
- list.Append(value)
- return Ok(list)
- }
- func fetchl(vm *VM, args ...Value) []Value {
- var index int
- var list *ListValue
- _, err := ParseArgs(args, &list, &index)
- if err != nil {
- return Fail(err)
- }
- if (index < 0) || (index >= len(list.List)) {
- return Fail(vm.Errorf("index out of range: %d<->%d", index, len(list.List)))
- }
- 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(vm.Errorf("fetch: need 3 arguments"))
- }
- if (index < 0) || (index >= len(list.List)) {
- return Fail(vm.Errorf("index out of range: %d<->%d", index, len(list.List)))
- }
- 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(vm.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 {
- vm.Printf("help <callable> 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)
- vm.Printf("%s %s: \n", helper.HelperName(), fl[0])
- }
- return Ok()
- }
- targetName := val[0].String()
- target := vm.Lookup(targetName)
- if target == nil {
- vm.Printf("help: %s not found.\n", targetName)
- return Ok()
- }
-
- if helper, isHelper := target.(Helper) ; isHelper {
- if len(val) > 1 {
- helper.SetHelp(val[1].String())
- }
- help := helper.Help()
- if call, isCall := target.(Callable); isCall {
- vm.Printf("%s %s: %s.\n", targetName, call.Signature().String(), help)
- } else {
- vm.Printf("%s: %s.\n", targetName, help)
- }
- return Ok(StringValue(help))
- } else {
- vm.Printf("%s %s. No help available.\n", targetName, target.Type())
- }
- 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 comma(vm * VM, val ...Value) []Value {
- vm.Printf("Comma arguments: %v\n", val)
-
- if len(val) < 2 {
- return Fail(vm.Errorf("Need at least 2 arguments"))
- }
-
- target := val[0]
- command := val[1]
- val[1] = target
- val = val[1:]
-
- if call, isCall := command.(Callable); isCall {
- return vm.CallCallable(call, val...)
- } else if name, isName := command.(WordValue) ; isName {
- return vm.CallNamed(name.String(), val...)
- } else {
- return Fail(vm.Errorf("Not callable: %v", command))
- }
- }
- // Get an object field
- func of(vm * VM, val ... Value) []Value {
- var object Value
- var name string
- _, err := ParseArgs(val, &object, &name)
- if err != nil {
- return Fail(err)
- }
- target, ok := object.(Object)
- if !ok {
- return Fail(vm.Errorf("Target cannot be invoked: %s %v", name, object))
- }
- return Ok(target.Get(name))
- }
- // Set an object field
- func _make(vm * VM, val ... Value) []Value {
- var object Value
- var name string
- rest, err := ParseArgs(val, &object, &name)
- if err != nil {
- return Fail(err)
- }
- target, ok := object.(Object)
- if !ok {
- return Fail(vm.Errorf("Target cannot be invoked: %s %v", name, object))
- }
- return Ok(target.Set(name, rest[0]))
- }
- // Call an object method
- func call(vm * VM, val ... Value) []Value {
- var object Value
- var name string
- rest, err := ParseArgs(val, &object, &name)
- if err != nil {
- return Fail(err)
- }
- target, ok := object.(Object)
- if !ok {
- return Fail(vm.Errorf("Target cannot be invoked: %s %v", name, object))
- }
- return target.Invoke(name, rest...)
- }
- func (vm *VM) RegisterBuiltinTypes() {
- vm.RegisterTop("Int", IntType)
- vm.RegisterTop("Float", FloatType)
- vm.RegisterTop("String",StringType)
- vm.RegisterTop("Bool", BoolType)
- vm.RegisterTop("Word", WordType)
- vm.RegisterTop("Error", ErrorType)
- vm.RegisterTop("Type", TypeType)
- vm.RegisterTop("Empty", EmptyType)
- vm.RegisterTop("List", ListType)
- vm.RegisterTop("Map", MapType)
- vm.RegisterTop("Any", AnyType)
- vm.RegisterTop("ZeroType", ZeroType)
- }
- func (vm *VM) RegisterBuiltins() {
- vm.RegisterBuiltinTypes()
- vm.RegisterBuiltinWithHelp("addl", addl, "adds an element to a list").Takes(ListType, AnyType).Returns(ListType)
- vm.RegisterBuiltinWithHelp("addi", addi, `adds two integers together`).Takes(IntType, IntType).Returns(BoolType)
- vm.RegisterBuiltinWithHelp("addf", addf, `adds two floats together`).Takes(FloatType, FloatType).Returns(FloatType)
- vm.RegisterBuiltinWithHelp("andb", andb, `returns true if all it's arguments are true`).Takes(BoolType, BoolType).Returns(BoolType)
- vm.RegisterBuiltin(",", comma)
- vm.RegisterBuiltin("cover", cover)
- vm.RegisterBuiltin("fetchl", fetchl).Takes(ListType, IntType).Returns(AnyType)
- vm.RegisterBuiltin("fetchm", fetchm).Takes(MapType, AnyType).Returns(AnyType)
- vm.RegisterBuiltin("sumi", sumi).Takes(IntType, IntType).Returns(IntType)
- vm.RegisterBuiltin("sumf", sumf).Takes(FloatType, FloatType).Returns(FloatType)
- vm.RegisterBuiltin("subi", subi).Takes(IntType, IntType).Returns(IntType)
- vm.RegisterBuiltin("subf", subf).Takes(FloatType, FloatType).Returns(FloatType)
- vm.RegisterBuiltin("divi", divi).Takes(IntType, IntType).Returns(IntType)
- vm.RegisterBuiltin("divf", divf).Takes(FloatType, FloatType).Returns(FloatType)
- vm.RegisterBuiltin("map", newmap)
- vm.RegisterBuiltin("muli", muli).Takes(IntType, IntType).Returns(IntType)
- vm.RegisterBuiltin("mulf", mulf).Takes(FloatType, FloatType).Returns(FloatType)
- 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).Takes(ListType, IntType).Returns(AnyType)
- vm.RegisterBuiltin("storem", storem).Takes(MapType, AnyType).Returns(AnyType)
- 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, FloatType, FloatType),
- Over("muli", 0, IntType, IntType),
- Over("mulf", 0, FloatType, IntType),
- Over("mulf", 0, IntType, FloatType))
-
- vm.AddOverloads("add",
- Over("addf", 0, FloatType, FloatType),
- Over("addi", 0, IntType, IntType),
- Over("addf", 0, FloatType, IntType),
- Over("addf", 0, IntType, FloatType))
- vm.AddOverloads("div",
- Over("divf", 0, FloatType, FloatType),
- Over("divi", 0, IntType, IntType),
- Over("divf", 0, FloatType, IntType),
- Over("divf", 0, IntType, FloatType))
- vm.AddOverloads("sub",
- Over("subf", 0, FloatType, FloatType),
- Over("subi", 0, IntType, IntType),
- Over("subf", 0, FloatType, IntType),
- Over("subf", 0, IntType, FloatType))
- vm.RegisterBuiltinWithHelp("of", of, "Gets a field in an Object value").Takes(AnyType, StringType).Returns(AnyType)
- vm.RegisterBuiltinWithHelp("make", _make, "Sets a field in an Object value").Takes(AnyType, StringType, AnyType).Returns(AnyType)
- vm.RegisterBuiltinWithHelp("call", call, "Calls a method of an Object value").Takes(AnyType, StringType, AnyType).Returns(AnyType)
-
- vm.Alias("*", "mul")
- vm.Alias("+", "add")
- vm.Alias("/", "div")
- vm.Alias("-", "sub")
- vm.Alias("||", "orb")
- vm.Alias("&&", "andb")
- vm.Alias("'s", "of")
-
-
- vm.SetHelp("mul", " Num: Multiplies two numbers. Cover for muli and mulf.")
- vm.AddOverloads("fetch",
- Over("fetchl", 0, ListType, IntType),
- Over("fetchm", 0, MapType, AnyType),
- )
- vm.SetHelp("fetch", " storage, index. Fetch value in storage at given index.")
- /*
- vm.AddOverloads("store",
- Over("storel", ListType, IntType, AnyType),
- Over("storem", MapType, AnyType, AnyType),
- )
- vm.SetHelp("store", " storage, index, value. Store value in storage at given index.")
- */
- RegisterDoor(vm)
- }
|