package tcl import ( "log" "os" "github.com/davecgh/go-spew/spew" . "github.com/oec/goparsify" ) // Tcl parser, using combinators // Based on the grammer in: // https://wiki.tcl-lang.org/page/BNF+for+Tcl var ( word Parser words Parser command Parser script Parser ) var ( comment = NewParser("comment", Merge(Seq("#", NotChars("\r\n")))).Map(drop) wordExp = NewParser("{*}word", Seq("{*}", &word)).Map(resultchild(1)) wordSub = NewParser("[*]word", Seq("[*]", &word)).Map(resultchild(1)) wordBrc = NewParser("{command}", Seq("{", Many(&command), "}")).Map(func(r *Result) { collectchildren(&r.Child[1]); r.Result = r.Child[1].Result }) wordQtd = NewParser(`"word"`, StringLit(`"`)).Map(token) wordSmp = NewParser("simple", NotChars("{}[]* ;\t\r\n")).Map(token) ) func init() { word = NewParser("word", Any(&wordSmp, &wordQtd, &wordBrc, &wordSub, &wordExp)) words = NewParser("words", Many(&word)).Map(collectchildren) command = NewParser("command", Seq(&words, Maybe(";"))).Map(resultchild(0)) script = NewParser("script", Many(Any(&comment, &command))).Map(collectchildren) } func Parse(input string) (data interface{}, e error) { data, e = Run(&script, input, ASCIIWhitespace) return } func ParseDebug(input string) (data interface{}, e error) { EnableLogging(os.Stdout) data, e = Run(&script, input, ASCIIWhitespace) return } func found(typ string) func(*Result) { return func(r *Result) { log.Printf("found a %s: %q (r.R: %v)\n", typ, r.Token, r.Result) r.Result = r.Token } } func drop(r *Result) { r.Token = "" r.Result = nil } func token(r *Result) { r.Result = r.Token // log.Println("token:", r.Token) } func collectchildren(r *Result) { data := []string{} for _, ch := range r.Child { switch v := ch.Result.(type) { case string: data = append(data, v) case []string: data = append(data, v...) default: // log.Println("oops:", r) } } // log.Println("data: ", data) r.Result = data } func resultchild(c int) func(*Result) { return func(r *Result) { r.Result = r.Child[c].Result // log.Printf("child[%d]: %v\n", c, r.Result) } } func dump(r *Result) { spew.Dump(r) }