package peg_test import ( "github.com/mudler/LocalAI/pkg/functions/peg" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) func extractTags(ast *peg.AstArena, result *peg.ParseResult) map[string]string { tags := make(map[string]string) ast.VisitResult(result, func(node *peg.AstNode) { if node.Tag != "" { tags[node.Tag] = node.Text } }) return tags } var _ = Describe("PEG Parser", func() { Context("LiteralParser", func() { It("succeeds on exact match", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Literal("hello") }) ctx := peg.NewParseContext("hello world", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.Start).To(Equal(0)) Expect(r.End).To(Equal(5)) }) It("fails on mismatch", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Literal("hello") }) ctx := peg.NewParseContext("world", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Fail)) }) It("returns NeedMoreInput in partial mode", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Literal("hello") }) ctx := peg.NewParseContext("hel", true) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.NeedMoreInput)) }) It("fails on partial input when not in partial mode", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Literal("hello") }) ctx := peg.NewParseContext("hel", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Fail)) }) }) Context("SequenceParser", func() { It("matches full sequence", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq(b.Literal("hello"), b.Literal(" "), b.Literal("world")) }) ctx := peg.NewParseContext("hello world", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(11)) }) It("fails midway", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq(b.Literal("hello"), b.Literal("X")) }) ctx := peg.NewParseContext("hello world", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Fail)) }) It("returns NeedMoreInput at boundary in partial mode", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq(b.Literal("hello"), b.Literal(" world")) }) ctx := peg.NewParseContext("hello wo", true) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.NeedMoreInput)) }) }) Context("ChoiceParser", func() { It("matches first alternative", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Choice(b.Literal("hello"), b.Literal("world")) }) ctx := peg.NewParseContext("hello", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(5)) }) It("matches second alternative", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Choice(b.Literal("hello"), b.Literal("world")) }) ctx := peg.NewParseContext("world", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(5)) }) It("fails when all alternatives fail", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Choice(b.Literal("hello"), b.Literal("world")) }) ctx := peg.NewParseContext("foo", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Fail)) }) }) Context("RepetitionParser", func() { It("handles zero or more matches", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.ZeroOrMore(b.Literal("ab")) }) ctx := peg.NewParseContext("ababab", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(6)) ctx2 := peg.NewParseContext("xyz", false) r2 := arena.Parse(ctx2) Expect(r2.Type).To(Equal(peg.Success)) Expect(r2.End).To(Equal(0)) }) It("handles one or more matches", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.OneOrMore(b.Literal("ab")) }) ctx := peg.NewParseContext("ababab", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(6)) ctx2 := peg.NewParseContext("xyz", false) r2 := arena.Parse(ctx2) Expect(r2.Type).To(Equal(peg.Fail)) }) It("handles optional matches", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq(b.Optional(b.Literal("hello")), b.Literal("world")) }) ctx := peg.NewParseContext("helloworld", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(10)) ctx2 := peg.NewParseContext("world", false) r2 := arena.Parse(ctx2) Expect(r2.Type).To(Equal(peg.Success)) Expect(r2.End).To(Equal(5)) }) It("respects bounded repetition", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Repeat(b.Literal("a"), 2, 4) }) ctx := peg.NewParseContext("aaaaa", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(4)) ctx2 := peg.NewParseContext("a", false) r2 := arena.Parse(ctx2) Expect(r2.Type).To(Equal(peg.Fail)) }) }) Context("Lookahead", func() { It("succeeds with positive lookahead", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq(b.Peek(b.Literal("hello")), b.Literal("hello")) }) ctx := peg.NewParseContext("hello", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(5)) }) It("fails with positive lookahead mismatch", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq(b.Peek(b.Literal("world")), b.Literal("hello")) }) ctx := peg.NewParseContext("hello", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Fail)) }) It("succeeds with negative lookahead", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq(b.Negate(b.Literal("world")), b.Literal("hello")) }) ctx := peg.NewParseContext("hello", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(5)) }) It("fails with negative lookahead match", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq(b.Negate(b.Literal("hello")), b.Literal("hello")) }) ctx := peg.NewParseContext("hello", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Fail)) }) }) Context("UntilParser", func() { It("consumes until single delimiter", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq(b.Until(""), b.Literal("")) }) ctx := peg.NewParseContext("content", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(12)) }) It("consumes until first of multiple delimiters", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.UntilOneOf("", "") }) ctx := peg.NewParseContext("contentmore", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(7)) }) It("consumes rest of input", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Rest() }) ctx := peg.NewParseContext("everything", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(10)) }) It("returns NeedMoreInput in partial mode", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Until("") }) ctx := peg.NewParseContext("content", true) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.NeedMoreInput)) }) }) Context("JSONParser", func() { It("parses objects", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.JSON() }) ctx := peg.NewParseContext(`{"key": "value", "num": 42}`, false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(27)) }) It("parses arrays", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.JSON() }) ctx := peg.NewParseContext(`[1, "two", true, null]`, false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(22)) }) It("parses strings with escapes", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.JSON() }) ctx := peg.NewParseContext(`"hello \"world\""`, false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(17)) }) It("parses numbers", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.JSON() }) ctx := peg.NewParseContext(`-123.45e10`, false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(10)) }) It("parses booleans", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.JSON() }) ctx := peg.NewParseContext(`true`, false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(4)) }) It("parses null", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.JSON() }) ctx := peg.NewParseContext(`null`, false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(4)) }) It("parses nested structures", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.JSON() }) input := `{"a": [1, {"b": true}], "c": null}` ctx := peg.NewParseContext(input, false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(len(input))) }) }) Context("Tag extraction", func() { It("extracts basic tags", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq( b.Tag("greeting", b.Until(" ")), b.Literal(" "), b.Tag("name", b.Rest()), ) }) ctx := peg.NewParseContext("Hello World", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) tags := extractTags(&ctx.Ast, &r) Expect(tags["greeting"]).To(Equal("Hello")) Expect(tags["name"]).To(Equal("World")) }) It("extracts structured tags", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq( b.Tag("header", b.Until("\n")), b.Literal("\n"), b.Tag("body", b.Rest()), ) }) ctx := peg.NewParseContext("Title\nBody content here", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) tags := extractTags(&ctx.Ast, &r) Expect(tags["header"]).To(Equal("Title")) Expect(tags["body"]).To(Equal("Body content here")) }) It("overwrites duplicate tags", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq( b.Tag("item", b.Until(",")), b.Literal(","), b.Tag("item", b.Rest()), ) }) ctx := peg.NewParseContext("first,second", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) tags := extractTags(&ctx.Ast, &r) Expect(tags["item"]).To(Equal("second")) }) It("returns empty map when no tags", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Rest() }) ctx := peg.NewParseContext("Hello", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) tags := extractTags(&ctx.Ast, &r) Expect(tags).To(HaveLen(0)) }) }) Context("Rule and Ref", func() { It("handles named rules", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { word := b.Rule("word", b.Chars("[a-z]", 1, -1)) return b.Seq(word, b.Literal(" "), word) }) ctx := peg.NewParseContext("hello world", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(11)) }) It("handles forward references", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { ref := b.Ref("greeting") b.Rule("greeting", b.Literal("hello")) return ref }) ctx := peg.NewParseContext("hello", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(5)) }) }) Context("AtomicParser", func() { It("suppresses partial AST nodes", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Atomic(b.Tag("test", b.Literal("hello world"))) }) ctx := peg.NewParseContext("hello", true) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.NeedMoreInput)) Expect(r.Nodes).To(HaveLen(0)) }) }) Context("Start and End parsers", func() { It("matches at start of input", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq(b.Start(), b.Literal("hello")) }) ctx := peg.NewParseContext("hello", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) }) It("matches at end of input", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq(b.Literal("hello"), b.End()) }) ctx := peg.NewParseContext("hello", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) ctx2 := peg.NewParseContext("hello world", false) r2 := arena.Parse(ctx2) Expect(r2.Type).To(Equal(peg.Fail)) }) }) Context("Partial parsing", func() { It("extracts tags during partial parse", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq( b.Tag("prefix", b.Until(":")), b.Literal(":"), b.Tag("value", b.Rest()), ) }) ctx := peg.NewParseContext("key:val", true) r := arena.Parse(ctx) Expect(r.Type).NotTo(Equal(peg.Fail)) tags := extractTags(&ctx.Ast, &r) Expect(tags["prefix"]).To(Equal("key")) }) }) Context("ParseAnywhere", func() { It("finds pattern in middle of input", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq( b.Choice(b.Literal("{"), b.Literal(":")), b.Space(), b.Literal("\""), b.Atomic(b.Literal("fun_name")), ) }) input := `This is a very long jinja template string... { "fun_name" : { "arg" : 1 }` found := false for i := 0; i < len(input); i++ { ctx := peg.NewParseContext(input, false) r := arena.ParseFrom(ctx, i) if r.Type == peg.Success { found = true break } } Expect(found).To(BeTrue()) }) It("fails when pattern is not found", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq( b.Choice(b.Literal("{"), b.Literal(":")), b.Space(), b.Literal("\""), b.Atomic(b.Literal("fun_name")), ) }) input := `This is a very long jinja template string... 1` found := false for i := 0; i < len(input); i++ { ctx := peg.NewParseContext(input, false) r := arena.ParseFrom(ctx, i) if r.Type == peg.Success { found = true break } } Expect(found).To(BeFalse()) }) }) Context("CharsParser", func() { It("matches lowercase letters", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Chars("[a-z]", 1, -1) }) ctx := peg.NewParseContext("hello123", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(5)) }) It("matches negated character class", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Chars("[^0-9]", 1, -1) }) ctx := peg.NewParseContext("hello123", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(5)) }) }) Context("JSONStringParser", func() { It("parses basic strings", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq(b.Literal("\""), b.JSONString(), b.Literal("\"")) }) ctx := peg.NewParseContext(`"hello world"`, false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(13)) }) It("parses strings with escapes", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq(b.Literal("\""), b.JSONString(), b.Literal("\"")) }) ctx := peg.NewParseContext(`"hello \"world\""`, false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(17)) }) It("parses strings with unicode escapes", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq(b.Literal("\""), b.JSONString(), b.Literal("\"")) }) ctx := peg.NewParseContext(`"hello \u0041"`, false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(14)) }) }) Context("SpaceParser", func() { It("matches whitespace", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq(b.Literal("a"), b.Space(), b.Literal("b")) }) ctx := peg.NewParseContext("a b", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(5)) }) It("matches zero whitespace", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq(b.Literal("a"), b.Space(), b.Literal("b")) }) ctx := peg.NewParseContext("ab", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(2)) }) }) Context("PythonDictStringParser", func() { It("parses basic single-quoted strings", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq(b.Literal("'"), b.PythonDictString(), b.Literal("'")) }) ctx := peg.NewParseContext("'hello world'", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) Expect(r.End).To(Equal(13)) }) It("handles escaped single quotes", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq(b.Literal("'"), b.PythonDictString(), b.Literal("'")) }) ctx := peg.NewParseContext(`'it\'s fine'`, false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) }) It("handles double quotes inside single-quoted strings", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq(b.Literal("'"), b.PythonDictString(), b.Literal("'")) }) ctx := peg.NewParseContext(`'He said "hi"'`, false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) }) }) Context("peg.ParseCharClassChar", func() { It("parses \\x hex escape", func() { r, n := peg.ParseCharClassChar(`\x41`, 0) Expect(r).To(Equal('A')) Expect(n).To(Equal(4)) }) It("parses \\u unicode escape", func() { r, n := peg.ParseCharClassChar(`\u0041`, 0) Expect(r).To(Equal('A')) Expect(n).To(Equal(6)) }) It("parses \\U unicode escape", func() { r, n := peg.ParseCharClassChar(`\U00000041`, 0) Expect(r).To(Equal('A')) Expect(n).To(Equal(10)) }) It("falls back on invalid hex", func() { r, n := peg.ParseCharClassChar(`\xZZ`, 0) Expect(r).To(Equal('x')) Expect(n).To(Equal(2)) }) }) Context("ParseAnywhere method", func() { It("finds pattern in middle of input", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Seq(b.Literal("needle"), b.Tag("after", b.Until("."))) }) ctx := peg.NewParseContext("some hay needle found.", false) r := arena.ParseAnywhere(ctx) Expect(r.Type).To(Equal(peg.Success)) tags := extractTags(&ctx.Ast, &r) Expect(tags["after"]).To(Equal(" found")) }) It("finds function tag with name", func() { haystack := "\n\n\n\nXXXX\n\n\nYYYY\n\n\n\n" needle := "foofoo" arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Tag("fun_marker", b.Choice( b.Seq( b.Tag("fun_pre", b.Seq(b.Literal("<"), b.UntilOneOf(">", needle))), b.Literal(needle), b.Tag("fun_post", b.Seq( b.Seq(b.Negate(b.Seq(b.Space(), b.Literal("<"))), b.Until(">"), b.Literal(">")), )), b.Space(), ), b.Seq( b.Tag("fun_pre", b.Seq(b.Literal("["), b.UntilOneOf("]", needle))), b.Literal(needle), b.Tag("fun_post", b.Seq( b.Negate(b.Seq(b.Space(), b.Seq(b.Literal("["), b.Until("]"), b.Literal("]")))), b.Space(), )), ), )) }) ctx := peg.NewParseContext(haystack, false) r := arena.ParseAnywhere(ctx) Expect(r.Type).To(Equal(peg.Success)) tags := extractTags(&ctx.Ast, &r) Expect(tags["fun_pre"]).To(Equal("")) }) }) Context("LazyRule", func() { It("handles recursive JSON-like structures", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { b.LazyRule("value", func() peg.ParserID { str := b.Seq(b.Literal("\""), b.JSONString(), b.Literal("\"")) arr := b.Seq( b.Literal("["), b.Space(), b.Ref("value"), b.ZeroOrMore(b.Seq(b.Space(), b.Literal(","), b.Space(), b.Ref("value"))), b.Space(), b.Literal("]"), ) return b.Choice(str, arr) }) return b.Ref("value") }) ctx := peg.NewParseContext(`["hello",["world","nested"]]`, false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) }) It("parses python dicts", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.PythonDict() }) ctx := peg.NewParseContext(`{'key': 'value', 'num': 42}`, false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) }) It("parses nested python values", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.PythonValue() }) ctx := peg.NewParseContext(`{'outer': {'inner': [1, 2, 'three']}}`, false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) }) It("parses python booleans and None", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.PythonValue() }) for _, input := range []string{"True", "False", "None"} { ctx := peg.NewParseContext(input, false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) } }) }) Context("Marker", func() { It("matches angle brackets", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Marker() }) ctx := peg.NewParseContext("", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) }) It("matches square brackets", func() { arena := peg.BuildPegParser(func(b *peg.Builder) peg.ParserID { return b.Marker() }) ctx := peg.NewParseContext("[TOOL]", false) r := arena.Parse(ctx) Expect(r.Type).To(Equal(peg.Success)) }) }) })