func DictToCommand(vm *gelo.VM, args *gelo.List, ac uint) gelo.Word { if ac != 1 { gelo.ArgumentError(vm, "dict->command", "dictionary", args) } m := vm.API.DictOrElse(args.Value).Map() return gelo.Alien(func(vm *gelo.VM, args *gelo.List, ac uint) gelo.Word { if ac == 0 { gelo.ArgumentError(vm, "command generated by dict->command", "argument+", args) } name := args.Value.Ser().String() if v, ok := m[name]; ok { if args.Next != nil { return vm.API.TailInvokeCmd(v, args.Next) } else { return vm.API.TailInvokeWordOrReturn(v) } } else if args.Next != nil { gelo.RuntimeError(vm, name, "is not a valid subcommand") } else { gelo.RuntimeError(vm, name, "is not a valid subcommand or entry") } panic("command generated by dict->command in impossible state") //Issue 65 }) }
func MaybeArgumentParser(_ *gelo.VM, args *gelo.List, ac uint) gelo.Word { parser := extensions.MakeArgParser(_args_to_spec(args, ac)) return gelo.Alien(func(vm *gelo.VM, args *gelo.List, _ uint) gelo.Word { Args, ok := parser(args) if !ok { return gelo.NewList(gelo.False) } return gelo.NewList(gelo.True, gelo.NewDictFrom(Args)) }) }
func Compose(vm *gelo.VM, args *gelo.List, ac uint) gelo.Word { if ac == 0 { return gelo.Alien(Id) //defined in eval.go } else if ac == 1 { return vm.API.InvokableOrElse(args.Value) } //reverse and type check (as much as possible) builder := extensions.ListBuilder() defer builder.Destroy() for ; args != nil; args = args.Next { builder.PushFront(vm.API.InvokableOrElse(args.Value)) } fs := builder.List() return gelo.Alien(func(vm *gelo.VM, args *gelo.List, ac uint) gelo.Word { c := fs var ret gelo.Word = args for ; c.Next != nil; c = c.Next { ret = gelo.AsList(vm.API.InvokeCmdOrElse(c.Value, ret.(*gelo.List))) } return vm.API.TailInvokeCmd(c.Value, ret.(*gelo.List)) }) }
func NS_capture(vm *gelo.VM, args *gelo.List, ac uint) gelo.Word { if ac != 1 { gelo.ArgumentError(vm, "ns.capture", "code-quote", args) } cmd, dict := vm.API.QuoteOrElse(args.Value), vm.Ns.Locals(0) vm.API.Trace("current namespace captured") return gelo.Alien(func(vm *gelo.VM, args *gelo.List, _ uint) gelo.Word { vm.API.Trace("switching to captured namespace") vm.Ns.Fork(nil) defer vm.Ns.Unfork() vm.Ns.Inject(0, dict) //can't tail invoke because the ns would be unforked return vm.API.InvokeCmdOrElse(cmd, args) }) }
func MakeInvokable(vm *gelo.VM, args *gelo.List, ac uint) gelo.Word { if ac == 0 { return gelo.Noop } return args.MapOrApply(func(w gelo.Word) gelo.Word { i, ok := vm.API.IsInvokable(w) if !ok { return gelo.Alien( func(vm *gelo.VM, args *gelo.List, ac uint) gelo.Word { if ac != 0 { gelo.ArgumentError(vm, w.Ser(), "", args) } return w }) } return i }) }
func Cleave(vm *gelo.VM, args *gelo.List, ac uint) gelo.Word { if ac < 1 { gelo.ArgumentError(vm, "cleave", "cmds+", args) } builder := extensions.ListBuilder() defer builder.Destroy() for ; args != nil; args = args.Next { builder.Push(vm.API.InvokableOrElse(args.Value)) } list := builder.List() return gelo.Alien(func(vm *gelo.VM, args *gelo.List, ac uint) gelo.Word { builder := extensions.ListBuilder() for c := list; c != nil; c = c.Next { builder.Push(vm.API.InvokeCmdOrElse(c.Value, args)) } return builder.List() }) }
func Aggregate(items map[string]interface{}) gelo.Alien { Map := make(map[string]gelo.Word) for k, v := range items { Map[k] = gelo.Convert(v) } d := gelo.NewDictFrom(Map) return gelo.Alien(func(vm *gelo.VM, args *gelo.List, ac uint) gelo.Word { if ac == 0 { return d } item, there := Map[args.Value.Ser().String()] if !there { //XXX this error message could be comprehensible in theory //will fix itself when vm contains name, lineno, etc gelo.ArgumentError(vm, "<an aggregate>", "command args*", args.Next) } return vm.API.TailInvokeCmd(item, args.Next) }) }
func ArgumentParser(_ *gelo.VM, args *gelo.List, ac uint) gelo.Word { parser := extensions.MakeOrElseArgParser(_args_to_spec(args, ac)) return gelo.Alien(func(vm *gelo.VM, args *gelo.List, _ uint) gelo.Word { return gelo.NewDictFrom(parser(vm, args)) }) }
func Partial(vm *gelo.VM, args *gelo.List, ac uint) gelo.Word { //TODO all of the argument errors in this function could be more informative if ac < 2 { gelo.ArgumentError(vm, "partial", "command [args*|'*|'X]+", args) } cmd, args := vm.API.InvokableOrElse(args.Value), args.Next a_star := false var val gelo.Word var kind _partial_kind var ph, pt *_partial for ; args != nil; args = args.Next { kind, val = _pk_fill, nil if sym, ok := args.Value.(gelo.Symbol); ok { if gelo.StrEqualsSym("X", sym) { if a_star { gelo.ArgumentError(vm, "partial", "there will be no arguments left after *", args) } kind = _pk_hole } else if gelo.StrEqualsSym("*", sym) { if a_star { gelo.ArgumentError(vm, "partial", "only one * can be specfied", args) } kind, a_star = _pk_slurp, true } else { val = sym } } else { val = args.Value } if ph != nil { pt.next = &_partial{kind, val, nil} pt = pt.next } else { ph = &_partial{kind, val, nil} pt = ph } } pt = nil return gelo.Alien(func(vm *gelo.VM, args *gelo.List, ac uint) gelo.Word { real_args := extensions.ListBuilder(cmd) for pls := ph; pls != nil; pls = pls.next { switch pls.kind { case _pk_fill: real_args.Push(pls.item) case _pk_hole: if args == nil { gelo.ArgumentError(vm, "partial function", "requires at least one more argument", args) } real_args.Push(args.Value) args = args.Next case _pk_slurp: real_args.Extend(args.Copy().(*gelo.List)) args = nil } } if args != nil { gelo.ArgumentError(vm, "partial function", "got too many arguments", args) } return vm.API.InvokeOrElse(real_args.List()) }) }
func Dict_sub(vm *gelo.VM, args *gelo.List, ac uint) gelo.Word { if ac != 2 { gelo.ArgumentError(vm, "dict.sub", "dictionary1 dictionary2", args) } d1 := vm.API.DictOrElse(args.Value) d2 := vm.API.DictOrElse(args.Next.Value) for k, _ := range d2.Map() { if d1.StrHas(k) { d1.StrDel(k) } } return d1 } var _dict_commands = map[string]gelo.Alien{ "set!": gelo.Alien(Dict_setx), "set?": gelo.Alien(Dict_setp), "unset!": gelo.Alien(Dict_unsetx), "get": gelo.Alien(Dict_get), "get!": gelo.Alien(Dict_getx), "add": gelo.Alien(Dict_add), "sub": gelo.Alien(Dict_sub), "keys": gelo.Alien(Dict_keys), "values": gelo.Alien(Dict_values), "items": gelo.Alien(Dict_items), } func DictAggregate(vm *gelo.VM, args *gelo.List, ac uint) gelo.Word { if ac < 2 { gelo.ArgumentError(vm, "dict", "dictionary command args*", args) }