package tcl import ( "log" "os" . "github.com/oec/goparsify" ) // Tcl tokenizer parser, using combinators var ( word Parser words Parser subcommand Parser command Parser ltm Parser script Parser ) var ( comment = NewParser("comment", Merge(Seq("#", NotChars("\r\n"), Chars("\r\n")))).Map(drop) wordExp = NewParser("{*}word", Seq("{*}", &word)).Map(resultchild(1)) wordSub = NewParser("[*]word", Seq("[*]", &word)).Map(resultchild(1)) wordQtd = NewParser(`"word"`, StringLit(`"`)).Map(token) wordSmp = NewParser("simple", NotChars("{} \t\r\n")).Map(token) group = NewParser("{group}", Seq("{", Maybe(Chars("\r\n")), Some(Any(&subcommand, &words)), "}")).Map(func(r *Result) { collectchildren(&r.Child[2]) r.Result = r.Child[2].Result }) ) func init() { word = NewParser("word", Any(&wordQtd, &group, &wordSmp, &wordSub, &wordExp)) words = NewParser("words", Many(&word)).Map(collectchildren) subcommand = NewParser("subcommand", Seq(&words, Any(";", Chars("\r\n")))).Map(resultchild(0)) command = NewParser("command", subcommand).Map(resultchild(0)) script = NewParser("script", Many(Any(&comment, <m, &command))).Map(collectchildren) ltm = NewParser("ltm", Seq("ltm", subcommand)).Map(resultchild(1)) } func simpleWhitespace(s *State) { for s.Pos < len(s.Input) { switch s.Input[s.Pos] { case '\t', '\v', '\f', ' ': s.Pos++ default: return } } } func Parse(input string) (data interface{}, e error) { data, e = Run(&script, input, simpleWhitespace) return } func ParseDebug(input string) (data interface{}, e error) { EnableLogging(os.Stdout) data, e = Run(&script, input, simpleWhitespace) 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 := []interface{}{} for _, ch := range r.Child { switch v := ch.Result.(type) { case string, []string, []interface{}: data = append(data, v) } } 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) } }