func (pp *__arg_parserparser) _parse_alt(first _arg_parser) _arg_parser { switch pp.ch { //make sure next is kosher case _alt, _cseq, _eot, _eoi, _star, _plus, _maybe: gelo.SyntaxError("Illegal prefix:", pp.spec[pp.pos]) } head := &_alt_parser{first, nil} tail := head for { if p := pp._parse1(true); p != nil { tail.next = &_alt_parser{p, nil} tail = tail.next } else { //_eoi return head } switch pp.ch { default: gelo.SyntaxError("Unexpected token", string(pp.spec), string(pp.spec[pp.pos-1])) case _alt: pp._next() switch pp.ch { //make sure next is kosher case _alt, _cseq, _eot, _star, _plus, _maybe: gelo.SyntaxError("Illegal prefix:", pp.spec[pp.pos-1]) case _eoi: gelo.SyntaxError("Input ends after |") } case _cseq, _eot: return head } pp._next() } panic("parse alt in impossible state") //Issue 65 }
func (pp *__arg_parserparser) _parse1(inalt bool) _arg_parser { var p _arg_parser for ; pp.ch == _eot; pp._next() { } //spin past whitespace switch pp.ch { //parse prefix default: gelo.SyntaxError("Unexpected token", string(pp.spec[pp.pos])) case _eoi: return nil case _lit: pp._next() str := pp._parse_string() if len(str) == 0 { gelo.SyntaxError("No literal after '") } pp.s[str] = true p = _lit_parser(str) case _char: //len >= 1, no need for check like above p = _var_parser(pp._parse_string()) case _oseq: p = pp._parse_seq(false) } switch pp.ch { default: gelo.SyntaxError("Unexpected token", string(pp.spec[pp.pos])) case _star, _plus, _maybe: switch pp.ch { case _star: p = &_star_parser{p} case _plus: p = &_plus_parser{p} case _maybe: p = &_maybe_parser{p} } pp._next() switch pp.ch { case _char, _oseq, _star, _plus, _maybe, _lit: gelo.SyntaxError("Unexpected token after postfix operator") } case _alt: if !inalt { pp._next() p = pp._parse_alt(p) } case _eot, _eoi, _cseq: //nothing more to do } return p }
func SyntaxError(vm *gelo.VM, args *gelo.List, ac uint) gelo.Word { if ac == 0 { gelo.ArgumentError(vm, "SyntaxError", "error-msg+", "") } //TODO should get a line-no, etc to allow creation of good error message gelo.SyntaxError(args) panic("Issue 65") }
func (pp *__arg_parserparser) _next() { pp.pos++ if pp.ch == _eoi || pp.pos >= len(pp.spec) { pp.ch = _eoi return } ch := pp.spec[pp.pos] if int(ch) < 32 { gelo.SyntaxError("Illegal character in argument parser specification") } switch ch { case '\\': pp._next() //This is severly broken, what was I thinking? if pp.ch == _eoi { gelo.SyntaxError("Attempted to escape end of input") } if pp.ch != _char { pp.ch = _char } case ' ': pp.ch = _eot case '\'': pp.ch = _lit case '*': pp.ch = _star case '+': pp.ch = _plus case '?': pp.ch = _maybe case '|': pp.ch = _alt case '[': pp.ch = _oseq case ']': pp.ch = _cseq default: pp.ch = _char } if pp.ch == _char { pp.buf.WriteByte(ch) } }
func ReCon(vm *gelo.VM, args *gelo.List, ac uint) gelo.Word { if ac != 1 { gelo.ArgumentError(vm, "Re", "specification", args) } spec := vm.API.LiteralOrElse(args.Value) rex, err := regexp.Compile(string(spec)) if err != nil { gelo.SyntaxError(vm, err.Error()) } return &Regexp{rex} }
func (pp *__arg_parserparser) _parse_seq(top bool) *_seq_parser { var p _arg_parser var head, tail *_seq_parser for { pp._next() if p = pp._parse1(false); p != nil { if head != nil { tail.next = &_seq_parser{p, nil} tail = tail.next } else { head = &_seq_parser{p, nil} tail = head } } switch pp.ch { case _cseq: if top { gelo.SyntaxError("] before [ in argument specification") } if head == nil { gelo.SyntaxError("Empty argument specification") } pp._next() //step over ] return head //postfix handled in _parse1 case _eoi: if !top { gelo.SyntaxError("[ without ] in argument specification") } if head == nil { gelo.SyntaxError("[] empty sequence in argument specification") } return head } } panic("argument parser parser in impossible state") //Issue 65 }
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 _cases_synerr() { gelo.SyntaxError("Patterns needs to be:", "\"value+ => resultant\", where value may be a command") }