Overview
Comment: | A simple parser combinator library |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
061baeefcb27371e64a70378d3deb699 |
User & Date: | spaskalev on 2015-03-19 20:17:55 |
Other Links: | manifest | tags |
Context
2015-03-19
| ||
20:36 | Added a string matching parser. check-in: 893c36d683 user: spaskalev tags: trunk | |
20:17 | A simple parser combinator library check-in: 061baeefcb user: spaskalev tags: trunk | |
2015-01-26
| ||
23:02 | full dep traversal in the collecting handler check-in: bca8ee3e12 user: spaskalev tags: trunk | |
Changes
Added src/0dev.org/parse/parse.go version [b38eeb1414].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | // Package parse provides a simple parser combinator library package parse // The N struct is a parser result node. type N struct { // Match indicates whether the parser succeeded. Matched bool // Content contains whatever was matched by the parser. Content string // Nodes contains any result nodes by nested parsers. Nodes []N } // Parser function type // Takes a string and returns a result and the remaining part of the string. type P func(string) (N, string) // A sequence of parsers. Matches when all of p match. func Seq(p ...P) P { return func(s string) (N, string) { result := N{Matched: true, Nodes: make([]N, 0, len(p))} for _, parser := range p { n, r := parser(s) result.Nodes = append(result.Nodes, n) if !n.Matched { result.Matched = false break } result.Content = result.Content + n.Content s = r } return result, s } } // Matches and returns on the first match of p. func Any(p ...P) P { return func(s string) (N, string) { result := N{Matched: false, Nodes: nil} for _, parser := range p { n, r := parser(s) if n.Matched { return n, r } result.Nodes, s = append(result.Nodes, n), r } return result, s } } // Kleene star (zero or more). Always matches. func K(p P) P { return func(s string) (N, string) { result := N{Matched: true, Nodes: nil} for n, r := p(s); n.Matched; n, r = p(r) { result.Content = result.Content + n.Content result.Nodes = append(result.Nodes, n) s = r } return result, s } } // Returns a delegating parser whose delegate can be set on later. // Useful for recursive definitions. func Defer() (P, *P) { var deferred P return func(s string) (N, string) { return deferred(s) }, &deferred } // Returns a parser that accepts the specified number of bytes func Accept(count int) P { return func(s string) (N, string) { if len(s) < count { return N{Matched: false, Content: "", Nodes: nil}, s } return N{Matched: true, Content: s[:count], Nodes: nil}, s[count:] } } |
Added src/0dev.org/parse/parse_test.go version [72baa0d593].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | package parse import ( "testing" ) func TestAccept(t *testing.T) { // Accept(0) will always match :) p0 := Accept(0) if r, s := p0(""); !r.Matched || r.Content != "" || r.Nodes != nil || s != "" { t.Error("Invalid result for Accept's negative test", r) } // Test with a non-zero amount of bytes p := Accept(1) if r, s := p(""); r.Matched || r.Content != "" || r.Nodes != nil || s != "" { t.Error("Invalid result for Accept's negative test", r) } if r, s := p("a"); !r.Matched || r.Content != "a" || r.Nodes != nil || s != "" { t.Error("Invalid result for Accept's positive test", r) } } func TestK(t *testing.T) { p := Accept(1) k := K(p) if r, s := k("aaa"); !r.Matched || r.Content != "aaa" || r.Nodes == nil || s != "" { t.Error("Invalid result for K* match test", r) } if r, s := k(""); !r.Matched || r.Content != "" || r.Nodes != nil || s != "" { t.Error("Invalid result for K* no-match test", r) } } func TestSeq(t *testing.T) { p1, p2 := Accept(1), Accept(1) s := Seq(p1, p2) if r, s := s("aa"); !r.Matched || r.Content != "aa" || r.Nodes == nil || s != "" { t.Error("Invalid result for Seq positive test", r) } if r, s := s("a"); r.Matched || r.Content != "a" || r.Nodes == nil || s != "" { t.Error("Invalid result for Seq partial match test", r) } if r, s := s(""); r.Matched || r.Content != "" || r.Nodes == nil || s != "" { t.Error("Invalid result for Seq no-match test", r) } } func TestAny(t *testing.T) { p, p0 := Accept(1), Accept(0) a := Any(p, p0) if r, s := a(""); !r.Matched || r.Content != "" || r.Nodes != nil || s != "" { t.Error("Invalid result for Any match test", r) } if r, s := a("aa"); !r.Matched || r.Content != "a" || r.Nodes != nil || s != "a" { t.Error("Invalid result for Any match test", r) } } |