annotate icf/icf.go @ 12:84384cccda0e

bubfix subpaths and remove hardcode
author atarwn@g5
date Mon, 23 Mar 2026 12:05:05 +0500
parents 2ffb8028ccbb
children 9460f83a5664
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.
12
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
149 func (c *Config) Match(input string) ([]Directive, map[string]string, string) {
0
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
12
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
156 rem string
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
157 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
158 var best *hit
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
159
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
160 for _, b := range c.Blocks {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
161 patHost, patPath, hasPath := strings.Cut(b.ID, "/")
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
162 caps := make(map[string]string)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
163
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
164 domScore, ok := matchExact(patHost, inHost, caps)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
165 if !ok {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
166 continue
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
167 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
168
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
169 pathScore := 0
12
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
170 rem := inPath
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
171 if hasPath {
12
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
172 var pathRem string
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
173 pathScore, pathRem, ok = matchPrefix(patPath, inPath, caps)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
174 if !ok {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
175 continue
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
176 }
12
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
177 rem = pathRem
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
178 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
179
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
180 score := domScore*1000 + pathScore
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
181 if best == nil || score > best.score {
12
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
182 best = &hit{block: b, captures: caps, score: score, rem: rem}
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
183 }
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 if best == nil {
12
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
187 return nil, nil, ""
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
188 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
189
12
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
190 // rem is the unmatched suffix after the path pattern.
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
191 // Ensure it starts with "/" to form a valid absolute subpath.
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
192 subPath := best.rem
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
193 if !strings.HasPrefix(subPath, "/") {
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
194 subPath = "/" + subPath
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
195 }
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
196 return c.ResolveBlock(best.block, best.captures), best.captures, subPath
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
197 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
198
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
199 // ResolveBlock merges mixin directives (lower priority) with block directives,
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
200 // then substitutes capture variables.
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
201 func (c *Config) ResolveBlock(b ParsedBlock, caps map[string]string) []Directive {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
202 var merged []Directive
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
203 if b.Mixin != "" {
6
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
204 merged = append(merged, c.resolveAbstract(b.Mixin, make(map[string]bool))...)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
205 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
206 merged = append(merged, b.Directives...)
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
207
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
208 if len(caps) == 0 {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
209 return merged
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
210 }
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
211
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
212 // Substitute capture variables into a copy
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
213 subst := makeSubst(c.vars)
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
214 out := make([]Directive, len(merged))
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
215 for i, d := range merged {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
216 out[i].Key = d.Key
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
217 out[i].Args = make([]string, len(d.Args))
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
218 for j, a := range d.Args {
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
219 out[i].Args[j] = subst(a, caps)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
220 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
221 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
222 return out
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
223 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
224
6
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
225 // 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
226 // visited guards against circular references.
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
227 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
228 if visited[name] {
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
229 return nil
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
230 }
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
231 visited[name] = true
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
232
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
233 var out []Directive
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
234 if parent, ok := c.abstractMixin[name]; ok {
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
235 out = append(out, c.resolveAbstract(parent, visited)...)
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
236 }
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
237 out = append(out, c.abstract[name]...)
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
238 return out
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
239 }
54ab94198677 abstract mixins + building sctipt + documentation
Atarwn Gard <a@qwa.su>
parents: 4
diff changeset
240
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
241 // makeSubst returns a function that substitutes $VAR in s,
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
242 // checking caps first, then vars.
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
243 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
244 return func(s string, caps map[string]string) string {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
245 if !strings.Contains(s, "$") {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
246 return s
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
247 }
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
248 var b strings.Builder
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
249 i := 0
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
250 for i < len(s) {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
251 if s[i] != '$' {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
252 b.WriteByte(s[i])
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
253 i++
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
254 continue
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
255 }
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
256 j := i + 1
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
257 for j < len(s) && isVarChar(s[j]) {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
258 j++
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
259 }
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
260 name := s[i+1 : j]
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
261 if caps != nil {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
262 if v, ok := caps[name]; ok {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
263 b.WriteString(v)
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
264 i = j
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
265 continue
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 if v, ok := vars[name]; ok {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
269 b.WriteString(v)
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
270 } else {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
271 b.WriteString(s[i:j])
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
272 }
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
273 i = j
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
274 }
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
275 return b.String()
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
276 }
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
277 }
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
278
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
279 func readLines(r io.Reader) ([]string, error) {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
280 var out []string
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
281 scanner := bufio.NewScanner(r)
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
282 for scanner.Scan() {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
283 line := stripComment(strings.TrimSpace(scanner.Text()))
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
284 if line != "" {
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
285 out = append(out, line)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
286 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
287 }
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
288 return out, scanner.Err()
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
289 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
290
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
291 func matchExact(pat, s string, caps map[string]string) (int, bool) {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
292 score, rem, ok := matchCaptures(pat, s, caps)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
293 if !ok || rem != "" {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
294 return 0, false
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
295 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
296 return score, true
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
297 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
298
12
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
299 func matchPrefix(pat, s string, caps map[string]string) (int, string, bool) {
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
300 score, rem, ok := matchCaptures(pat, s, caps)
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
301 return score, rem, ok
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
302 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
303
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
304 func matchCaptures(pat, inp string, caps map[string]string) (int, string, bool) {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
305 for {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
306 if pat == "" {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
307 return 0, inp, true
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
308 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
309
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
310 if strings.HasPrefix(pat, "<") {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
311 end := strings.Index(pat, ">")
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
312 if end == -1 {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
313 return 0, "", false
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
314 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
315 capName := pat[1:end]
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
316 rest := pat[end+1:]
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
317
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 6
diff changeset
318 for split := len(inp); split >= 1; split-- {
12
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
319 // Captures never span path separators: <n> matches one segment only.
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
320 if strings.Contains(inp[:split], "/") {
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
321 continue
84384cccda0e bubfix subpaths and remove hardcode
atarwn@g5
parents: 8
diff changeset
322 }
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
323 score, finalRem, ok := matchCaptures(rest, inp[split:], caps)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
324 if ok {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
325 if capName != "_" {
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
326 caps[capName] = inp[:split]
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
327 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
328 return score, finalRem, true
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
329 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
330 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
331 return 0, "", false
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
332 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
333
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
334 if inp == "" || pat[0] != inp[0] {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
335 return 0, "", false
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
336 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
337 score, rem, ok := matchCaptures(pat[1:], inp[1:], caps)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
338 return score + 1, rem, ok
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
339 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
340 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
341
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
342 func braceExpand(args []string) []string {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
343 var out []string
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
344 for _, a := range args {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
345 out = append(out, expandOne(a)...)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
346 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
347 return out
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
348 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
349
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
350 func expandOne(s string) []string {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
351 start := strings.Index(s, "{")
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
352 end := strings.Index(s, "}")
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
353 if start == -1 || end == -1 || end < start {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
354 return []string{s}
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
355 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
356 prefix := s[:start]
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
357 suffix := s[end+1:]
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
358 var out []string
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
359 for _, v := range strings.Split(s[start+1:end], ",") {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
360 out = append(out, prefix+strings.TrimSpace(v)+suffix)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
361 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
362 return out
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
363 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
364
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
365 func stripComment(line string) string {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
366 if strings.HasPrefix(line, ";") {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
367 return ""
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
368 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
369 if i := strings.Index(line, " ;"); i != -1 {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
370 return strings.TrimSpace(line[:i])
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
371 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
372 return line
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
373 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
374
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
375 func isVarName(s string) bool {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
376 if s == "" {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
377 return false
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
378 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
379 for i := 0; i < len(s); i++ {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
380 if !isVarChar(s[i]) {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
381 return false
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
382 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
383 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
384 return true
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
385 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
386
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
387 func isVarChar(c byte) bool {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
388 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
389 (c >= '0' && c <= '9') || c == '_'
2
d19133be91ba ndex and smarter parser
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
390 }