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 Dict_keys(vm *gelo.VM, args *gelo.List, ac uint) gelo.Word { if ac != 1 { gelo.ArgumentError(vm, "dict.keys", "dictionary", args) } d, list := vm.API.DictOrElse(args.Value), extensions.ListBuilder() for k, _ := range d.Map() { list.Push(gelo.StrToSym(k)) } return list.List() }
func Re_matches(vm *gelo.VM, args *gelo.List, ac uint) gelo.Word { if ac != 2 { gelo.ArgumentError(vm, "matches", "regexp string", args) } r := ReOrElse(vm, args.Value) s := args.Next.Value.Ser().Bytes() list := extensions.ListBuilder() for _, v := range r.FindSubmatch(s) { list.Push(gelo.BytesToSym(v)) } return list.List() }
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 Case_of(vm *gelo.VM, args *gelo.List, ac uint) gelo.Word { Args := _cases_parser(vm, args) key := Args["value"] arguments := gelo.AsList(key) cases, ok := vm.API.PartialEval(vm.API.QuoteOrElse(Args["cases"])) if !ok || cases.Next == nil && cases.Value == nil { gelo.SyntaxError(vm, "Expected:", _cases_parser, "{[value+ => resultant\n]+ [otherwise result]?} Got:", args) } //Give val a name, specified by var, in clauses of the cases block //XXX This disallows us from making tail calls if name, there := Args["var"]; there { if d, there := vm.Ns.DepthOf(name); there && d == 0 { defer vm.Ns.Set(0, name, vm.Ns.LookupOrElse(name)) } else { defer vm.Ns.Del(name) } vm.Ns.Set(0, name, key) } //run val through cmd before comparing if cmd, there := Args["cmd"]; there { key = vm.API.InvokeCmdOrElse(cmd, arguments) } //Parse lines for ; cases != nil; cases = cases.Next { //if last line, see if it's the otherwise clause if cases.Next == nil { item := cases.Value.(*gelo.List) s, ok := item.Value.(gelo.Symbol) if ok && gelo.StrEqualsSym("otherwise", s) { if item.Next == nil || item.Next.Next != nil { _cases_synerr() } return _case_eval(vm, item.Next.Value, arguments) } } item := cases.Value.(*gelo.List) //line is too short if item.Next == nil || item.Next.Next == nil { _cases_synerr() } //Parse a single line list := extensions.ListBuilder() var resultant gelo.Word for ; item != nil; item = item.Next { if item.Next == nil { //ultimate cell resultant = item.Value } else if item.Next.Next == nil { //penultimate cell s, ok := item.Value.(gelo.Symbol) if ok && gelo.StrEqualsSym("=>", s) { continue } _cases_synerr() } else { list.Push(item.Value) } } //see if key matches any of the items we found on this line for head := list.List(); head != nil; head = head.Next { if key.Equals(head.Value) { return _case_eval(vm, resultant, arguments) } } } return gelo.Null //no match, no otherwise }
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()) }) }