aboutsummaryrefslogtreecommitdiff
path: root/tcl.go
blob: 4bddee373d2674e732c3492cd00a8d050fd412ec (plain)
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package tcl

import (
	"log"
	"os"

	"github.com/davecgh/go-spew/spew"
	. "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, &ltm, &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)
	}
}

func dump(r *Result) {
	spew.Dump(r)
}