コード例 #1
0
ファイル: kern.go プロジェクト: gavingroovygrover/kern
// GetInputAndPosition gets the input stream and current position from a parser state.
func GetInputAndPosition(s PState) PState {
	return s.clone(func(e *PState) {
		e.value = InputAndPosition{inp: u8.Desur(s.input), pos: s.pos}
		e.ok = true
		e.empty = true
		e.error = ""
	})
}
コード例 #2
0
ファイル: kern.go プロジェクト: gavingroovygrover/kern
// GetInput gets the input stream from a parser state.
func GetInput(s PState) PState {
	return s.clone(func(e *PState) {
		e.value = u8.Desur(s.input)
		e.ok = true
		e.empty = true
		e.error = ""
	})
}
コード例 #3
0
ファイル: kern.go プロジェクト: gavingroovygrover/kern
// Tokens is like Token but accepts more than one Text. It will try each such choice in turn.
func Tokens(ts ...u8.Text) Parser {
	switch len(ts) {
	case 0:
		return Fail(u8.Desur(errNoAlts))
	case 1:
		return Token(ts[0])
	default:
		return Alt(Try(Token(ts[0])), Tokens(ts[1:]...))
	}
}
コード例 #4
0
ファイル: kern.go プロジェクト: gavingroovygrover/kern
// Flatten applies one or more parsers; flattens the result and
// converts it to text. Same functionality as <+> in Clojure's kern.
func Flatten(ps ...Parser) Parser {
	var f func(c interface{}) interface{}
	f = func(c interface{}) interface{} {
		s := ""
		for _, n := range c.([]interface{}) {
			if _, isText := n.(u8.Text); !isText {
				n = f(n)
			}
			s = s + u8.Surr(n.(u8.Text))
		}
		return u8.Desur(s)
	}
	switch len(ps) {
	case 0:
		return Fail(u8.Desur(errNoParser))
	case 1:
		return Apply(f, ps[0])
	default:
		return Apply(f, Collect(ps...))
	}
}
コード例 #5
0
ファイル: kern.go プロジェクト: gavingroovygrover/kern
// Skip applies one or more parsers and skips the result. That is, it returns
// a parser state record with a value of nil.
func Skip(ps ...Parser) Parser {
	switch len(ps) {
	case 0:
		return Fail(u8.Desur(errNoParser))
	case 1:
		return SeqRight(ps[0], Return(nil))
	case 2:
		return Bind(ps[0], func(_ interface{}) Parser {
			return Skip(ps[1])
		})
	default:
		return SeqRight(ps[0], Skip(ps[1:]...))
	}
}
コード例 #6
0
ファイル: kern.go プロジェクト: gavingroovygrover/kern
// SeqLeft parses each parser of ps in sequence; it keeps the first result and
// skips the rest.
// Same functionality as << in Clojure's kern.
func SeqLeft(ps ...Parser) Parser {
	switch len(ps) {
	case 0:
		return Fail(u8.Desur(errNoParser))
	case 1:
		return ps[0]
	case 2:
		return Bind(ps[0], func(x interface{}) Parser {
			return SeqRight(ps[1], Return(x))
		})
	default:
		return SeqLeft(ps[0], SeqLeft(ps[1:]...))
	}
}
コード例 #7
0
ファイル: kern.go プロジェクト: gavingroovygrover/kern
// Regexp succeeds if the next Character/s mathes the given regex string, in which case it
// advances the position of the input stream. It may fail on an unexpected end of input.
func Regexp(tok string) Parser {
	return func(st PState) (so PState) {
		if log["Regexp"] || (len(st.log) > 0 && st.log[len(st.log)-1] && loggingEnabled) {
			defer logFnBA("Regexp", &st, &so)
		}

		if len(tok) == 0 {
			so = st.clone(func(e *PState) {
				e.value = nil
				e.ok = false
				e.empty = true
				e.error = errEmptyStr
			})
			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 {
			r := regexp.MustCompile("^(?:" + tok + ")") //QUERY: change to \A ?
			loc := r.FindStringIndex(st.input)
			if loc != nil && loc[0] == 0 {
				so = st.clone(func(e *PState) {
					e.input = st.input[loc[1]:]
					e.pos = st.pos + uint64(loc[1])
					e.value = u8.Desur(st.input[0:loc[1]])
					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
			}
		}
	}
}
コード例 #8
0
ファイル: state_test.go プロジェクト: gavingroovygrover/kern
//================================================================================
func TestInputAndPosition(t *testing.T) {
	ts.LogAsserts("InputAndPosition", t, func(tt *ts.T) {
		letter := Regexp(`\pL`)
		p1 := Flatten(letter, letter, letter)

		tt.AssertEqual(parseStr(SeqRight(SetInput(u8.Desur("Hi!")), GetInput), "abcdefg"),
			PState{input: "Hi!", pos: 0, value: u8.Desur("Hi!"), empty: true, ok: true})
		tt.AssertEqual(parseStr(SeqRight(letter, GetInput), "abcdefg"),
			PState{input: "bcdefg", pos: 1, value: u8.Desur("bcdefg"), ok: true})

		tt.AssertEqual(parseStr(SeqRight(SetPosition(100), GetPosition), "abcdefg"),
			PState{input: "abcdefg", pos: 100, value: uint64(100), empty: true, ok: true})

		tt.AssertEqual(parseStr(SeqRight(SetInputAndPosition(InputAndPosition{u8.Desur("Hi there!"), 5}), GetInputAndPosition), "abcdefg"),
			PState{input: "Hi there!", pos: 5, value: InputAndPosition{u8.Desur("Hi there!"), 5}, empty: true, ok: true})

		tt.AssertEqual(parseStr(Collect(p1, SeqRight(SetInput(u8.Desur("XYZ")), p1)), "ABCDEFG"),
			PState{input: "", pos: 6, value: arrText("ABC", "XYZ"), ok: true}) //TODO: what should pos be?
		tt.AssertEqual(parseStr(Collect(p1, SeqRight(SetInput(u8.Desur("XYZ")), p1)), "ABC"),
			PState{input: "", pos: 6, value: arrText("ABC", "XYZ"), ok: true}) //TODO: ditto

		tt.AssertEqual(parseStr(Collect(p1), "ABC"),
			PState{input: "", pos: 3, value: arrText("ABC"), ok: true})

		p2 := SeqRight(Skip(SetInput(u8.Text("XY0")), SetPosition(0)), p1)
		tt.AssertEqual(parseStr(Collect(p1, p2), "ABC"),
			PState{input: "0", pos: 2, value: nil, error: makeUnexpInp("0")})

		p3 := SeqRight(Skip(SetInput(u8.Text("WXYZ")), SetPosition(0)), GetPosition)
		tt.AssertEqual(parseStr(SeqRight(p1, p3), "ABC"),
			PState{input: "WXYZ", pos: 0, value: uint64(0), ok: true})

		p4 := SeqRight(SetInput(u8.Text("XYZ")), GetInput)
		tt.AssertEqual(parseStr(SeqRight(p1, p4), "ABC"),
			PState{input: "XYZ", pos: 3, value: u8.Text("XYZ"), ok: true})

		tt.AssertEqual(parseStr(Collect(p1, SeqRight(SetInputAndPosition(InputAndPosition{u8.Desur("XYZ"), 2}), p1)), "ABCDEFG"), //posn changed from 3 to 2...
			PState{input: "", pos: 5, value: arrText("ABC", "XYZ"), ok: true}) //...so posn is 5 instead of 6

	})
}
コード例 #9
0
ファイル: kern.go プロジェクト: gavingroovygrover/kern
// Alt tries each parser in ps; if any fails without consuming any input, it tries the
// next one. It will stop and succeed if a parser succeeds; it will stop and fail
// if a parser fails consuming input; or it will try the next one if a parser fails
// without consuming input.
// Same functionality as <|> in Clojure's kern.
func Alt(ps ...Parser) Parser {
	switch len(ps) {
	case 0:
		return Fail(u8.Desur(errNoParser))
	case 1:
		return ps[0]
	case 2:
		p := ps[0]
		q := ps[1]
		return func(st PState) (so PState) {
			if log["Alt"] || (len(st.log) > 0 && st.log[len(st.log)-1] && loggingEnabled) {
				logFnIn("Alt", &st)
				defer logFnDe("Alt", &so)
			}
			s2 := p(st)
			if !s2.ok && s2.empty {
				s3 := q(st)
				if s3.ok {
					so = s3
					return
				} else {
					so = s3.clone(func(e *PState) {
						//QUERY: what about e.ok , etc?
						e.error = errNoAlts
					})
					return
				}
			} else {
				so = s2
				return
			}
		}

	default:
		return Alt(ps[0], Alt(ps[1:]...))
	}
}
コード例 #10
0
ファイル: kern.go プロジェクト: gavingroovygrover/kern
// NotFollowedBy succeeds only if p fails; consumes no input.
func NotFollowedBy(p Parser) Parser {
	return Try(Alt(Bind(Try(p), func(x interface{}) Parser {
		return Fail(u8.Desur(errParsFail))
	}),
		Return(nil)))
}