annotate icf/icf.go @ 7:8e4813b4e509

update index style + justfile additions
author Atarwn Gard <a@qwa.su>
date Tue, 10 Mar 2026 12:12:33 +0500
parents 54ab94198677
children 2ffb8028ccbb
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
1 // Package icf implements the Inherited Configuration Format parser.
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
2 //
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
3 // ICF is a rule-based configuration format with variables, abstract blocks
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
4 // (mixins), pattern matching with named capture groups, and brace expansion.
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
5 package icf
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
6
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
7 import (
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
8 "bufio"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
9 "fmt"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
10 "io"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
11 "strings"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
12 )
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
13
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
14 type Directive struct {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
15 Key string
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
16 Args []string
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
17 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
18
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
19 type Config struct {
6
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
20 vars map[string]string
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
21 abstract map[string][]Directive
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
22 abstractMixin map[string]string // mixin name for each abstract block
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
23 Blocks []ParsedBlock
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
24 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
25
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
26 type ParsedBlock struct {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
27 ID string
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
28 Mixin string
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
29 Directives []Directive
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
30 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
31
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
32 type rawBlock struct {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
33 id string
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
34 mixin string
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
35 directives []rawDirective
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
36 }
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
37
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
38 type rawDirective struct {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
39 key string
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
40 args []string // after brace expansion, before var substitution
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
41 }
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
42
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
43 func Parse(r io.Reader) (*Config, error) {
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
44 lines, err := readLines(r)
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
45 if err != nil {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
46 return nil, err
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
47 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
48
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
49 // --- Pass 1: collect variables ---
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
50 vars := make(map[string]string)
4
dacc92aae6d5 expand vars in vars
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
51 subst := makeSubst(vars)
dacc92aae6d5 expand vars in vars
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
52
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
53 for _, line := range lines {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
54 if i := strings.Index(line, "="); i > 0 && !strings.HasPrefix(line, "|>") {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
55 key := line[:i]
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
56 if isVarName(key) {
4
dacc92aae6d5 expand vars in vars
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
57 vars[key] = subst(strings.TrimSpace(line[i+1:]), nil)
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
58 }
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
59 }
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
60 }
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
61
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
62 // --- Pass 2: parse blocks (raw, no capture substitution yet) ---
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
63 var raws []rawBlock
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
64 var cur *rawBlock
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
65
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
66 flush := func() {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
67 if cur != nil {
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
68 raws = append(raws, *cur)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
69 cur = nil
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
70 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
71 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
72
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
73 for _, line := range lines {
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
74 if i := strings.Index(line, "="); i > 0 && !strings.HasPrefix(line, "|>") {
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
75 if isVarName(line[:i]) {
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
76 continue
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
77 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
78 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
79
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
80 if strings.HasPrefix(line, "|>") {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
81 if cur == nil {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
82 return nil, fmt.Errorf("icf: directive outside block: %q", line)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
83 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
84 parts := strings.Fields(strings.TrimSpace(line[2:]))
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
85 if len(parts) == 0 {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
86 continue
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
87 }
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
88 cur.directives = append(cur.directives, rawDirective{
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
89 key: parts[0],
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
90 args: braceExpand(parts[1:]),
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
91 })
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
92 continue
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
93 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
94
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
95 flush()
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
96 parts := strings.Fields(line)
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
97 rb := rawBlock{id: subst(parts[0], nil)}
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
98 if len(parts) >= 2 && strings.HasPrefix(parts[1], "@") {
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
99 rb.mixin = subst(parts[1][1:], nil)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
100 }
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
101 cur = &rb
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
102 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
103 flush()
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
104
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
105 // --- Pass 3: separate abstract from concrete, apply var substitution ---
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
106 c := &Config{
6
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
107 vars: vars,
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
108 abstract: make(map[string][]Directive),
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
109 abstractMixin: make(map[string]string),
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
110 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
111
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
112 for _, rb := range raws {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
113 dirs := make([]Directive, len(rb.directives))
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
114 for i, rd := range rb.directives {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
115 args := make([]string, len(rd.args))
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
116 for j, a := range rd.args {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
117 args[j] = subst(a, nil)
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
118 }
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
119 dirs[i] = Directive{Key: rd.key, Args: args}
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
120 }
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
121
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
122 if strings.HasPrefix(rb.id, "@") {
6
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
123 name := rb.id[1:]
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
124 c.abstract[name] = dirs
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
125 if rb.mixin != "" {
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
126 c.abstractMixin[name] = rb.mixin
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
127 }
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
128 } else {
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
129 c.Blocks = append(c.Blocks, ParsedBlock{
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
130 ID: rb.id,
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
131 Mixin: rb.mixin,
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
132 Directives: dirs,
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
133 })
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
134 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
135 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
136
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
137 return c, nil
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
138 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
139
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
140 // Abstract returns the directives of a named abstract block.
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
141 // Returns nil if not found.
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
142 func (c *Config) Abstract(name string) []Directive {
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
143 return c.abstract[name]
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
144 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
145
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
146 // Match finds the most specific block matching input (e.g. "host/path") and
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
147 // returns resolved directives plus named captures.
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
148 // Domain is matched exactly; path uses prefix match.
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
149 func (c *Config) Match(input string) ([]Directive, map[string]string) {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
150 inHost, inPath, _ := strings.Cut(input, "/")
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
151
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
152 type hit struct {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
153 block ParsedBlock
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
154 captures map[string]string
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
155 score int
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
156 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
157 var best *hit
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
158
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
159 for _, b := range c.Blocks {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
160 patHost, patPath, hasPath := strings.Cut(b.ID, "/")
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
161 caps := make(map[string]string)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
162
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
163 domScore, ok := matchExact(patHost, inHost, caps)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
164 if !ok {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
165 continue
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
166 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
167
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
168 pathScore := 0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
169 if hasPath {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
170 pathScore, ok = matchPrefix(patPath, inPath, caps)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
171 if !ok {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
172 continue
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
173 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
174 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
175
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
176 score := domScore*1000 + pathScore
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
177 if best == nil || score > best.score {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
178 best = &hit{block: b, captures: caps, score: score}
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
179 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
180 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
181
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
182 if best == nil {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
183 return nil, nil
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
184 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
185
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
186 return c.ResolveBlock(best.block, best.captures), best.captures
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
187 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
188
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
189 // ResolveBlock merges mixin directives (lower priority) with block directives,
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
190 // then substitutes capture variables.
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
191 func (c *Config) ResolveBlock(b ParsedBlock, caps map[string]string) []Directive {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
192 var merged []Directive
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
193 if b.Mixin != "" {
6
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
194 merged = append(merged, c.resolveAbstract(b.Mixin, make(map[string]bool))...)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
195 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
196 merged = append(merged, b.Directives...)
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
197
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
198 if len(caps) == 0 {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
199 return merged
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
200 }
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
201
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
202 // Substitute capture variables into a copy
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
203 subst := makeSubst(c.vars)
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
204 out := make([]Directive, len(merged))
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
205 for i, d := range merged {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
206 out[i].Key = d.Key
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
207 out[i].Args = make([]string, len(d.Args))
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
208 for j, a := range d.Args {
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
209 out[i].Args[j] = subst(a, caps)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
210 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
211 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
212 return out
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
213 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
214
6
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
215 // resolveAbstract recursively expands an abstract block and its mixin chain.
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
216 // visited guards against circular references.
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
217 func (c *Config) resolveAbstract(name string, visited map[string]bool) []Directive {
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
218 if visited[name] {
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
219 return nil
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
220 }
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
221 visited[name] = true
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
222
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
223 var out []Directive
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
224 if parent, ok := c.abstractMixin[name]; ok {
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
225 out = append(out, c.resolveAbstract(parent, visited)...)
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
226 }
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
227 out = append(out, c.abstract[name]...)
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
228 return out
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
229 }
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
230
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
231 // makeSubst returns a function that substitutes $VAR in s,
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
232 // checking caps first, then vars.
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
233 func makeSubst(vars map[string]string) func(s string, caps map[string]string) string {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
234 return func(s string, caps map[string]string) string {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
235 if !strings.Contains(s, "$") {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
236 return s
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
237 }
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
238 var b strings.Builder
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
239 i := 0
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
240 for i < len(s) {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
241 if s[i] != '$' {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
242 b.WriteByte(s[i])
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
243 i++
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
244 continue
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
245 }
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
246 j := i + 1
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
247 for j < len(s) && isVarChar(s[j]) {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
248 j++
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
249 }
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
250 name := s[i+1 : j]
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
251 if caps != nil {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
252 if v, ok := caps[name]; ok {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
253 b.WriteString(v)
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
254 i = j
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
255 continue
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
256 }
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
257 }
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
258 if v, ok := vars[name]; ok {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
259 b.WriteString(v)
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
260 } else {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
261 b.WriteString(s[i:j])
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
262 }
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
263 i = j
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
264 }
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
265 return b.String()
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
266 }
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
267 }
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
268
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
269 func readLines(r io.Reader) ([]string, error) {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
270 var out []string
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
271 scanner := bufio.NewScanner(r)
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
272 for scanner.Scan() {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
273 line := stripComment(strings.TrimSpace(scanner.Text()))
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
274 if line != "" {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
275 out = append(out, line)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
276 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
277 }
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
278 return out, scanner.Err()
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
279 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
280
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
281 func matchExact(pat, s string, caps map[string]string) (int, bool) {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
282 score, rem, ok := matchCaptures(pat, s, caps)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
283 if !ok || rem != "" {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
284 return 0, false
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
285 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
286 return score, true
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
287 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
288
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
289 func matchPrefix(pat, s string, caps map[string]string) (int, bool) {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
290 score, _, ok := matchCaptures(pat, s, caps)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
291 return score, ok
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
292 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
293
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
294 func matchCaptures(pat, inp string, caps map[string]string) (int, string, bool) {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
295 for {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
296 if pat == "" {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
297 return 0, inp, true
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
298 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
299
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
300 if strings.HasPrefix(pat, "<") {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
301 end := strings.Index(pat, ">")
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
302 if end == -1 {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
303 return 0, "", false
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
304 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
305 capName := pat[1:end]
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
306 rest := pat[end+1:]
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
307
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
308 for split := 1; split <= len(inp); split++ {
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
309 score, finalRem, ok := matchCaptures(rest, inp[split:], caps)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
310 if ok {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
311 if capName != "_" {
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
312 caps[capName] = inp[:split]
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
313 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
314 return score, finalRem, true
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
315 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
316 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
317 return 0, "", false
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
318 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
319
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
320 if inp == "" || pat[0] != inp[0] {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
321 return 0, "", false
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
322 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
323 score, rem, ok := matchCaptures(pat[1:], inp[1:], caps)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
324 return score + 1, rem, ok
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
325 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
326 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
327
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
328 func braceExpand(args []string) []string {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
329 var out []string
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
330 for _, a := range args {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
331 out = append(out, expandOne(a)...)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
332 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
333 return out
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
334 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
335
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
336 func expandOne(s string) []string {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
337 start := strings.Index(s, "{")
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
338 end := strings.Index(s, "}")
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
339 if start == -1 || end == -1 || end < start {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
340 return []string{s}
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
341 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
342 prefix := s[:start]
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
343 suffix := s[end+1:]
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
344 var out []string
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
345 for _, v := range strings.Split(s[start+1:end], ",") {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
346 out = append(out, prefix+strings.TrimSpace(v)+suffix)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
347 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
348 return out
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
349 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
350
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
351 func stripComment(line string) string {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
352 if strings.HasPrefix(line, ";") {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
353 return ""
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
354 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
355 if i := strings.Index(line, " ;"); i != -1 {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
356 return strings.TrimSpace(line[:i])
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
357 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
358 return line
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
359 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
360
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
361 func isVarName(s string) bool {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
362 if s == "" {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
363 return false
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
364 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
365 for i := 0; i < len(s); i++ {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
366 if !isVarChar(s[i]) {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
367 return false
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
368 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
369 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
370 return true
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
371 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
372
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
373 func isVarChar(c byte) bool {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
374 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
375 (c >= '0' && c <= '9') || c == '_'
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
376 }