//================================================================================ func TestStateStack(t *testing.T) { ts.LogAsserts("StateStack", t, func(tt *ts.T) { p0 := Bind(PushStateStack(555), func(c1 interface{}) Parser { return Bind(PushStateStack(556), func(c2 interface{}) Parser { return PushStateStack(557) }) }) p2 := SeqRight( SeqRight(p0, Bind(AnyChar, func(x interface{}) (p Parser) { if u8.Sur(x.(u8.Codepoint)) == "\n" { return PopStateStack() } else { return Return(nil) } })), GetState) tt.AssertEqual(parseStr(p2, "\naa"), PState{input: "aa", pos: 1, value: []interface{}{555, 556}, ok: true, user: []interface{}{555, 556}}) tt.AssertEqual(parseStr(p2, "abba"), PState{input: "bba", pos: 1, value: []interface{}{555, 556, 557}, ok: true, user: []interface{}{555, 556, 557}}) p3 := SeqRight(p0, Bind(AnyChar, func(x interface{}) (p Parser) { if u8.Sur(x.(u8.Codepoint)) == "\n" { return AlterTopStateStack(777) } else { return PeekStateStack() } })) tt.AssertEqual(parseStr(p3, "\nbc"), PState{input: "bc", pos: 1, ok: true, user: []interface{}{555, 556, 777}}) tt.AssertEqual(parseStr(p3, "abc"), PState{input: "bc", pos: 1, value: 557, ok: true, user: []interface{}{555, 556, 557}}) p4 := Bind(AnyChar, func(x interface{}) (p Parser) { if u8.Sur(x.(u8.Codepoint)) == "\n" { return AlterTopStateStack(777) } else { return PeekStateStack() } }) tt.AssertEqual(parseStr(p4, "\naa"), PState{input: "aa", pos: 1, error: "AlterTopStateStack doesn't handle zero-sized stacks."}) tt.AssertEqual(parseStr(p4, "abc"), PState{input: "bc", pos: 1, ok: true}) }) }
// Expect parses p and if it fails (regardless of input consumed) will replace // the error with the message "Expecting" m. This helps to produce more abstract // and accurate error messages. func Expect(p Parser, m u8.Text) Parser { return func(s PState) PState { st := p(s) if st.ok { return st } else { return st.clone(func(e *PState) { e.error = st.error + " Expecting " + u8.Sur(m...) }) } } }
// Ask parses p and if it fails consuming no input, will replace the error // with the message "Expecting" m. This helps to produce more abstract and // accurate error messages. Same functionality as <?> in Clojure's kern. func Ask(p Parser, m u8.Text) Parser { return func(s PState) PState { st := p(s) if !st.ok && st.empty { return st.clone(func(e *PState) { e.error = st.error + " Expecting " + u8.Sur(m...) }) } else { return st } } }
func ExampleNoneOf() { p := kern.NoneOf(utf88.Text("xyz\n\t")) t := utf88.Text("abcde") r, ok := kern.ParseText(p, t) if ok { fmt.Printf("Result: %s\n", utf88.Sur(r.(utf88.Codepoint))) } else { fmt.Printf("Error: %v\n", r) } // Output: // Result: a }
func ExampleAsk() { letter := kern.Regexp(`\pL`) digit := kern.Regexp(`\p{Nd}`) p := kern.Ask(kern.Collect(digit, letter), utf88.Text("digit,letter")) t := utf88.Text(";efg") r, ok := kern.ParseText(p, t) if ok { fmt.Printf("Result: %s\n", utf88.Sur(r.(utf88.Codepoint))) } else { fmt.Printf("Error: %v\n", r) } // Output: // Error: Unexpected ; input. Expecting digit,letter }
// Satisfy succeeds if the next character satisfies the predicate pred, in which case // advances the position of the input stream. It may fail on an unexpected end of input. func Satisfy(pred func(u8.Codepoint) bool) Parser { return func(st PState) (so PState) { if log["Satisfy"] || (len(st.log) > 0 && st.log[len(st.log)-1] && loggingEnabled) { defer logFnBA("Satisfy", &st, &so) } if st.input == "" { so = st.clone(func(e *PState) { e.value = nil e.ok = false e.empty = true e.error = errUnexpEof }) return } c, _ := u8.DesurrogateFirstPoint([]rune(st.input)) if pred(c) { so = st.clone(func(e *PState) { e.input = st.input[u8.LenInBytes(c):] e.pos = st.pos + uint64(u8.LenInBytes(c)) e.value = c e.ok = true e.empty = false e.error = "" }) return } else { so = st.clone(func(e *PState) { e.value = nil e.ok = false e.empty = true e.error = makeUnexpInp(u8.Sur(c)) }) return } } }
// Symbol succeeds if the next Codepoint equals the given Codepoint, in which case it // increments the position of the input stream. It may fail on an unexpected end of input. func Symbol(t u8.Codepoint) Parser { sym := u8.Sur(t) return func(st PState) (so PState) { if log["Symbol"] || (len(st.log) > 0 && st.log[len(st.log)-1] && loggingEnabled) { defer logFnBA("Symbol", &st, &so) } if len(sym) == 0 { so = st.clone(func(e *PState) { e.value = nil e.ok = false e.empty = true e.error = errEmptyStr }) return } else if len(sym) > 1 && st.input[:len(sym)] == sym { so = st.clone(func(e *PState) { e.input = st.input[len(sym):] e.pos = st.pos + uint64(len(sym)) e.value = t e.ok = true e.empty = false e.error = "" }) return } else if len(sym) > 1 { so = st.clone(func(e *PState) { e.value = nil e.ok = false e.empty = true e.error = errInvalStr }) return } else if st.input == "" { so = st.clone(func(e *PState) { e.value = nil e.ok = false e.empty = true e.error = errUnexpEof }) return } else if st.input[:1] == sym { so = st.clone(func(e *PState) { e.input = st.input[1:] e.pos = st.pos + 1 e.value = t e.ok = true e.empty = false e.error = "" }) return } else { so = st.clone(func(e *PState) { e.value = nil e.ok = false e.empty = true e.error = makeUnexpInp(st.input[:1]) }) return } } }