blob: 6c63216cd52016ad5398e50f166f5c62fe8dbd94 [file] [log] [blame]
Shinichiro Hamajib69bf8a2015-06-10 14:52:06 +09001// Copyright 2015 Google Inc. All rights reserved
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090015package main
16
17import (
18 "bytes"
19 "errors"
20 "fmt"
21 "io"
Fumitoshi Ukaif0a2ba72015-04-19 00:02:32 +090022 "strconv"
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090023 "strings"
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +090024 "sync"
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090025)
26
27var (
28 errEndOfInput = errors.New("parse: unexpected end of input")
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +090029 errNotLiteral = errors.New("valueNum: not literal")
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +090030
31 bufFree = sync.Pool{
Fumitoshi Ukaid0bf88c2015-05-08 10:54:32 +090032 New: func() interface{} { return new(buffer) },
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +090033 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090034)
35
Fumitoshi Ukaid0bf88c2015-05-08 10:54:32 +090036type buffer struct {
37 bytes.Buffer
38 args [][]byte
39}
40
41func newBuf() *buffer {
42 buf := bufFree.Get().(*buffer)
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +090043 return buf
44}
45
Fumitoshi Ukaid0bf88c2015-05-08 10:54:32 +090046func freeBuf(buf *buffer) {
Fumitoshi Ukai7ff5b232015-05-08 00:44:12 +090047 if cap(buf.Bytes()) > 1024 {
48 return
49 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +090050 buf.Reset()
Fumitoshi Ukaid0bf88c2015-05-08 10:54:32 +090051 buf.args = buf.args[:0]
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +090052 bufFree.Put(buf)
53}
54
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090055type Value interface {
56 String() string
57 Eval(w io.Writer, ev *Evaluator)
Shinichiro Hamajic8bc7312015-04-28 02:48:03 +090058 Serialize() SerializableVar
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +090059 Dump(w io.Writer)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090060}
61
Fumitoshi Ukai6ac7f692015-04-15 17:13:51 +090062type Valuer interface {
63 Value() []byte
64}
65
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090066// literal is literal value.
67type literal string
68
69func (s literal) String() string { return string(s) }
70func (s literal) Eval(w io.Writer, ev *Evaluator) {
Fumitoshi Ukai5541c7e2015-04-18 22:47:03 +090071 io.WriteString(w, string(s))
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090072}
Shinichiro Hamajic8bc7312015-04-28 02:48:03 +090073func (s literal) Serialize() SerializableVar {
74 return SerializableVar{Type: "literal", V: string(s)}
75}
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +090076func (s literal) Dump(w io.Writer) {
Fumitoshi Ukai936de102015-06-08 11:21:16 +090077 dumpByte(w, ValueTypeLiteral)
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +090078 dumpBytes(w, []byte(s))
79}
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090080
81// tmpval is temporary value.
82type tmpval []byte
83
84func (t tmpval) String() string { return string(t) }
85func (t tmpval) Eval(w io.Writer, ev *Evaluator) {
86 w.Write(t)
87}
Fumitoshi Ukai6ac7f692015-04-15 17:13:51 +090088func (t tmpval) Value() []byte { return []byte(t) }
Shinichiro Hamajic8bc7312015-04-28 02:48:03 +090089func (t tmpval) Serialize() SerializableVar {
90 return SerializableVar{Type: "tmpval", V: string(t)}
91}
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +090092func (t tmpval) Dump(w io.Writer) {
Fumitoshi Ukai936de102015-06-08 11:21:16 +090093 dumpByte(w, ValueTypeTmpval)
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +090094 dumpBytes(w, t)
95}
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090096
97// Expr is a list of values.
98type Expr []Value
99
100func (e Expr) String() string {
101 var s []string
102 for _, v := range e {
103 s = append(s, v.String())
104 }
105 return strings.Join(s, "")
106}
107
108func (e Expr) Eval(w io.Writer, ev *Evaluator) {
109 for _, v := range e {
110 v.Eval(w, ev)
111 }
112}
113
Shinichiro Hamajic8bc7312015-04-28 02:48:03 +0900114func (e Expr) Serialize() SerializableVar {
115 r := SerializableVar{Type: "expr"}
116 for _, v := range e {
117 r.Children = append(r.Children, v.Serialize())
118 }
119 return r
120}
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +0900121func (e Expr) Dump(w io.Writer) {
Fumitoshi Ukai936de102015-06-08 11:21:16 +0900122 dumpByte(w, ValueTypeExpr)
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +0900123 dumpInt(w, len(e))
124 for _, v := range e {
125 v.Dump(w)
126 }
127}
Shinichiro Hamajic8bc7312015-04-28 02:48:03 +0900128
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900129func compactExpr(e Expr) Value {
130 if len(e) == 1 {
131 return e[0]
132 }
133 // TODO(ukai): concat literal
134 return e
135}
136
137// varref is variable reference. e.g. ${foo}.
138type varref struct {
139 varname Value
140}
141
142func (v varref) String() string {
143 varname := v.varname.String()
144 if len(varname) == 1 {
145 return fmt.Sprintf("$%s", varname)
146 }
147 return fmt.Sprintf("${%s}", varname)
148}
149
150func (v varref) Eval(w io.Writer, ev *Evaluator) {
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900151 te := traceEvent.begin("var", v, traceEventMain)
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900152 buf := newBuf()
153 v.varname.Eval(buf, ev)
154 vv := ev.LookupVar(buf.String())
155 freeBuf(buf)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900156 vv.Eval(w, ev)
Fumitoshi Ukai432a2422015-06-11 15:16:29 +0900157 traceEvent.end(te)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900158}
159
Shinichiro Hamajic8bc7312015-04-28 02:48:03 +0900160func (v varref) Serialize() SerializableVar {
161 return SerializableVar{
Shinichiro Hamaji3d6d0aa2015-04-28 16:18:44 +0900162 Type: "varref",
Shinichiro Hamajic8bc7312015-04-28 02:48:03 +0900163 Children: []SerializableVar{v.varname.Serialize()},
164 }
165}
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +0900166func (v varref) Dump(w io.Writer) {
Fumitoshi Ukai936de102015-06-08 11:21:16 +0900167 dumpByte(w, ValueTypeVarref)
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +0900168 v.varname.Dump(w)
169}
Shinichiro Hamajic8bc7312015-04-28 02:48:03 +0900170
Fumitoshi Ukaif0a2ba72015-04-19 00:02:32 +0900171// paramref is parameter reference e.g. $1.
172type paramref int
173
174func (p paramref) String() string {
175 return fmt.Sprintf("$%d", int(p))
176}
177
178func (p paramref) Eval(w io.Writer, ev *Evaluator) {
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900179 te := traceEvent.begin("param", p, traceEventMain)
Fumitoshi Ukaif0a2ba72015-04-19 00:02:32 +0900180 n := int(p)
181 if n < len(ev.paramVars) {
182 ev.paramVars[n].Eval(w, ev)
183 } else {
184 // out of range?
185 // panic(fmt.Sprintf("out of range %d: %d", n, len(ev.paramVars)))
186 }
Fumitoshi Ukai432a2422015-06-11 15:16:29 +0900187 traceEvent.end(te)
Fumitoshi Ukaif0a2ba72015-04-19 00:02:32 +0900188}
189
Shinichiro Hamajic8bc7312015-04-28 02:48:03 +0900190func (p paramref) Serialize() SerializableVar {
191 return SerializableVar{Type: "paramref", V: strconv.Itoa(int(p))}
192}
193
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +0900194func (p paramref) Dump(w io.Writer) {
Fumitoshi Ukai936de102015-06-08 11:21:16 +0900195 dumpByte(w, ValueTypeParamref)
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +0900196 dumpInt(w, int(p))
197}
198
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900199// varsubst is variable substitutaion. e.g. ${var:pat=subst}.
200type varsubst struct {
201 varname Value
202 pat Value
203 subst Value
204}
205
206func (v varsubst) String() string {
207 return fmt.Sprintf("${%s:%s=%s}", v.varname, v.pat, v.subst)
208}
209
210func (v varsubst) Eval(w io.Writer, ev *Evaluator) {
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900211 te := traceEvent.begin("varsubst", v, traceEventMain)
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900212 buf := newBuf()
213 params := ev.args(buf, v.varname, v.pat, v.subst)
214 vname := string(params[0])
215 pat := string(params[1])
216 subst := string(params[2])
217 buf.Reset()
218 vv := ev.LookupVar(vname)
219 vv.Eval(buf, ev)
220 vals := splitSpaces(buf.String())
221 freeBuf(buf)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900222 space := false
223 for _, val := range vals {
224 if space {
Fumitoshi Ukai5541c7e2015-04-18 22:47:03 +0900225 io.WriteString(w, " ")
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900226 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900227 io.WriteString(w, substRef(pat, subst, val))
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900228 space = true
229 }
Fumitoshi Ukai432a2422015-06-11 15:16:29 +0900230 traceEvent.end(te)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900231}
232
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +0900233func (v varsubst) Serialize() SerializableVar {
Shinichiro Hamajic8bc7312015-04-28 02:48:03 +0900234 return SerializableVar{
235 Type: "varsubst",
236 Children: []SerializableVar{
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +0900237 v.varname.Serialize(),
238 v.pat.Serialize(),
239 v.subst.Serialize(),
Shinichiro Hamajic8bc7312015-04-28 02:48:03 +0900240 },
241 }
242}
243
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +0900244func (v varsubst) Dump(w io.Writer) {
Fumitoshi Ukai936de102015-06-08 11:21:16 +0900245 dumpByte(w, ValueTypeVarsubst)
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +0900246 v.varname.Dump(w)
247 v.pat.Dump(w)
248 v.subst.Dump(w)
249}
250
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900251func str(buf []byte, alloc bool) Value {
252 if alloc {
253 return literal(string(buf))
254 }
255 return tmpval(buf)
256}
257
258func appendStr(expr Expr, buf []byte, alloc bool) Expr {
259 if len(buf) == 0 {
260 return expr
261 }
262 if len(expr) == 0 {
263 return Expr{str(buf, alloc)}
264 }
265 switch v := expr[len(expr)-1].(type) {
266 case literal:
267 v += literal(string(buf))
268 expr[len(expr)-1] = v
269 return expr
270 case tmpval:
271 v = append(v, buf...)
272 expr[len(expr)-1] = v
273 return expr
274 }
275 return append(expr, str(buf, alloc))
276}
277
278func valueNum(v Value) (int, error) {
279 switch v := v.(type) {
280 case literal, tmpval:
281 n, err := strconv.ParseInt(v.String(), 10, 64)
282 return int(n), err
283 }
284 return 0, errNotLiteral
285}
286
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900287// parseExpr parses expression in `in` until it finds any byte in term.
288// if term is nil, it will parse to end of input.
289// if term is not nil, and it reaches to end of input, return errEndOfInput.
290// it returns parsed value, and parsed length `n`, so in[n-1] is any byte of
291// term, and in[n:] is next input.
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900292// if alloc is true, text will be literal (allocate string).
293// otherwise, text will be tmpval on in.
294func parseExpr(in, term []byte, alloc bool) (Value, int, error) {
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900295 var expr Expr
Fumitoshi Ukai00178d12015-04-18 00:11:05 +0900296 b := 0
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900297 i := 0
298 var saveParen byte
299 parenDepth := 0
300Loop:
301 for i < len(in) {
302 ch := in[i]
Fumitoshi Ukai96c79f12015-04-18 22:58:13 +0900303 if term != nil && bytes.IndexByte(term, ch) >= 0 {
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900304 break Loop
305 }
306 switch ch {
307 case '$':
308 if i+1 >= len(in) {
309 break Loop
310 }
311 if in[i+1] == '$' {
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900312 expr = appendStr(expr, in[b:i+1], alloc)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900313 i += 2
Fumitoshi Ukai00178d12015-04-18 00:11:05 +0900314 b = i
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900315 continue
316 }
317 if bytes.IndexByte(term, in[i+1]) >= 0 {
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900318 expr = appendStr(expr, in[b:i], alloc)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900319 expr = append(expr, varref{varname: literal("")})
320 i++
Fumitoshi Ukai00178d12015-04-18 00:11:05 +0900321 b = i
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900322 break Loop
323 }
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900324 expr = appendStr(expr, in[b:i], alloc)
325 v, n, err := parseDollar(in[i:], alloc)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900326 if err != nil {
327 return nil, 0, err
328 }
329 i += n
Fumitoshi Ukai00178d12015-04-18 00:11:05 +0900330 b = i
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900331 expr = append(expr, v)
332 continue
333 case '(', '{':
334 cp := closeParen(ch)
335 if i := bytes.IndexByte(term, cp); i >= 0 {
336 parenDepth++
337 saveParen = cp
338 term[i] = 0
339 } else if cp == saveParen {
340 parenDepth++
341 }
342 case saveParen:
343 parenDepth--
344 if parenDepth == 0 {
345 i := bytes.IndexByte(term, 0)
346 term[i] = saveParen
347 saveParen = 0
348 }
349 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900350 i++
351 }
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900352 expr = appendStr(expr, in[b:i], alloc)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900353 if i == len(in) && term != nil {
354 return expr, i, errEndOfInput
355 }
356 return compactExpr(expr), i, nil
357}
358
359func closeParen(ch byte) byte {
360 switch ch {
361 case '(':
362 return ')'
363 case '{':
364 return '}'
365 }
366 return 0
367}
368
369// parseDollar parses
370// $(func expr[, expr...]) # func = literal SP
371// $(expr:expr=expr)
372// $(expr)
373// $x
374// it returns parsed value and parsed length.
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900375func parseDollar(in []byte, alloc bool) (Value, int, error) {
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900376 if len(in) <= 1 {
377 return nil, 0, errors.New("empty expr")
378 }
379 if in[0] != '$' {
380 return nil, 0, errors.New("should starts with $")
381 }
382 if in[1] == '$' {
383 return nil, 0, errors.New("should handle $$ as literal $")
384 }
385 paren := closeParen(in[1])
386 if paren == 0 {
387 // $x case.
Fumitoshi Ukaif0a2ba72015-04-19 00:02:32 +0900388 if in[1] >= '0' && in[1] <= '9' {
389 return paramref(in[1] - '0'), 2, nil
390 }
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900391 return varref{varname: str(in[1:2], alloc)}, 2, nil
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900392 }
393 term := []byte{paren, ':', ' '}
394 var varname Expr
395 i := 2
396Again:
397 for {
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900398 e, n, err := parseExpr(in[i:], term, alloc)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900399 if err != nil {
400 return nil, 0, err
401 }
402 varname = append(varname, e)
403 i += n
404 switch in[i] {
405 case paren:
406 // ${expr}
Fumitoshi Ukaif0a2ba72015-04-19 00:02:32 +0900407 vname := compactExpr(varname)
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900408 n, err := valueNum(vname)
409 if err == nil {
410 // ${n}
411 return paramref(n), i + 1, nil
Fumitoshi Ukaif0a2ba72015-04-19 00:02:32 +0900412 }
413 return varref{varname: vname}, i + 1, nil
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900414 case ' ':
415 // ${e ...}
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900416 switch token := e.(type) {
417 case literal, tmpval:
418 funcName := intern(token.String())
Shinichiro Hamaji2216dd62015-04-11 13:44:39 +0900419 if f, ok := funcMap[funcName]; ok {
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900420 return parseFunc(f(), in, i+1, term[:1], funcName, alloc)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900421 }
422 }
423 term = term[:2] // drop ' '
424 continue Again
425 case ':':
426 // ${varname:...}
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900427 colon := in[i:i+1]
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900428 term = term[:2]
429 term[1] = '=' // term={paren, '='}.
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900430 e, n, err := parseExpr(in[i+1:], term, alloc)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900431 if err != nil {
432 return nil, 0, err
433 }
434 i += 1 + n
435 if in[i] == paren {
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900436 varname = appendStr(varname, colon, alloc)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900437 return varref{varname: varname}, i + 1, nil
438 }
439 // ${varname:xx=...}
440 pat := e
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900441 subst, n, err := parseExpr(in[i+1:], term[:1], alloc)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900442 if err != nil {
443 return nil, 0, err
444 }
445 i += 1 + n
446 // ${first:pat=e}
447 return varsubst{
448 varname: compactExpr(varname),
449 pat: pat,
450 subst: subst,
451 }, i + 1, nil
452 default:
453 panic(fmt.Sprintf("unexpected char"))
454 }
455 }
456}
457
458// skipSpaces skips spaces at front of `in` before any bytes in term.
459// in[n] will be the first non white space in in.
460func skipSpaces(in, term []byte) int {
461 for i := 0; i < len(in); i++ {
462 if bytes.IndexByte(term, in[i]) >= 0 {
463 return i
464 }
465 switch in[i] {
466 case ' ', '\t':
467 default:
468 return i
469 }
470 }
471 return len(in)
472}
473
Fumitoshi Ukaiee5c6fc2015-04-16 13:13:10 +0900474// trimLiteralSpace trims literal space around v.
475func trimLiteralSpace(v Value) Value {
476 switch v := v.(type) {
477 case literal:
478 return literal(strings.TrimSpace(string(v)))
479 case tmpval:
480 b := bytes.TrimSpace([]byte(v))
481 if len(b) == 0 {
482 return literal("")
483 }
484 return tmpval(b)
485 case Expr:
486 if len(v) == 0 {
487 return v
488 }
489 switch s := v[0].(type) {
490 case literal, tmpval:
491 t := trimLiteralSpace(s)
492 if t == literal("") {
493 v = v[1:]
494 } else {
495 v[0] = t
496 }
497 }
498 switch s := v[len(v)-1].(type) {
499 case literal, tmpval:
500 t := trimLiteralSpace(s)
501 if t == literal("") {
502 v = v[:len(v)-1]
503 } else {
504 v[len(v)-1] = t
505 }
506 }
507 return compactExpr(v)
508 }
509 return v
510}
511
512// concatLine concatinates line with "\\\n" in function expression.
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900513// TODO(ukai): less alloc?
Fumitoshi Ukaiee5c6fc2015-04-16 13:13:10 +0900514func concatLine(v Value) Value {
515 switch v := v.(type) {
516 case literal:
517 for {
518 s := string(v)
519 i := strings.Index(s, "\\\n")
520 if i < 0 {
521 return v
522 }
523 v = literal(s[:i] + strings.TrimLeft(s[i+2:], " \t"))
524 }
525 case tmpval:
526 for {
527 b := []byte(v)
528 i := bytes.Index(b, []byte{'\\', '\n'})
529 if i < 0 {
530 return v
531 }
532 var buf bytes.Buffer
533 buf.Write(b[:i])
534 buf.Write(bytes.TrimLeft(b[i+2:], " \t"))
Fumitoshi Ukaid8d84252015-04-19 17:30:13 +0900535 v = tmpval(buf.Bytes())
Fumitoshi Ukaiee5c6fc2015-04-16 13:13:10 +0900536 }
537 case Expr:
538 for i := range v {
539 switch vv := v[i].(type) {
540 case literal, tmpval:
541 v[i] = concatLine(vv)
542 }
543 }
544 return v
545 }
546 return v
547}
548
Fumitoshi Ukaiebf945c2015-04-10 17:30:04 +0900549// parseFunc parses function arguments from in[s:] for f.
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900550// in[0] is '$' and in[s] is space just after func name.
Fumitoshi Ukaiebf945c2015-04-10 17:30:04 +0900551// in[:n] will be "${func args...}"
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900552func parseFunc(f Func, in []byte, s int, term []byte, funcName string, alloc bool) (Value, int, error) {
553 f.AddArg(str(in[1:s-1], alloc))
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900554 arity := f.Arity()
555 term = append(term, ',')
Fumitoshi Ukaiebf945c2015-04-10 17:30:04 +0900556 i := skipSpaces(in[s:], term)
557 i = s + i
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900558 if i == len(in) {
559 return f, i, nil
560 }
561 narg := 1
562 for {
563 if arity != 0 && narg >= arity {
564 // final arguments.
565 term = term[:1] // drop ','
566 }
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900567 v, n, err := parseExpr(in[i:], term, alloc)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900568 if err != nil {
569 return nil, 0, err
570 }
Fumitoshi Ukaiee5c6fc2015-04-16 13:13:10 +0900571 v = concatLine(v)
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900572 // TODO(ukai): do this in funcIf, funcAnd, or funcOr's compactor?
Fumitoshi Ukaiee5c6fc2015-04-16 13:13:10 +0900573 if (narg == 1 && funcName == "if") || funcName == "and" || funcName == "or" {
574 v = trimLiteralSpace(v)
575 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900576 f.AddArg(v)
577 i += n
578 narg++
579 if in[i] == term[0] {
580 i++
581 break
582 }
583 i++ // should be ','
584 if i == len(in) {
585 break
586 }
587 }
Fumitoshi Ukai9f6b6352015-04-16 16:25:09 +0900588 var fv Value
589 fv = f
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900590 if compactor, ok := f.(Compactor); ok {
Fumitoshi Ukai9f6b6352015-04-16 16:25:09 +0900591 fv = compactor.Compact()
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900592 }
Fumitoshi Ukai432a2422015-06-11 15:16:29 +0900593 if katiEvalStatsFlag || traceEvent.enabled() {
Fumitoshi Ukaif543f4d2015-06-15 15:21:47 +0900594 fv = funcstats{
595 Value: fv,
596 str: fv.String(),
597 }
598
Fumitoshi Ukai6ac7f692015-04-15 17:13:51 +0900599 }
Fumitoshi Ukai9f6b6352015-04-16 16:25:09 +0900600 return fv, i, nil
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900601}
Fumitoshi Ukai6ac7f692015-04-15 17:13:51 +0900602
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900603type Compactor interface {
Fumitoshi Ukai9f6b6352015-04-16 16:25:09 +0900604 Compact() Value
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900605}
606
Fumitoshi Ukai6ac7f692015-04-15 17:13:51 +0900607type funcstats struct {
Fumitoshi Ukai9f6b6352015-04-16 16:25:09 +0900608 Value
Fumitoshi Ukaif543f4d2015-06-15 15:21:47 +0900609 str string
Fumitoshi Ukai6ac7f692015-04-15 17:13:51 +0900610}
611
612func (f funcstats) Eval(w io.Writer, ev *Evaluator) {
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900613 te := traceEvent.begin("func", literal(f.str), traceEventMain)
Fumitoshi Ukai9f6b6352015-04-16 16:25:09 +0900614 f.Value.Eval(w, ev)
Fumitoshi Ukai6ac7f692015-04-15 17:13:51 +0900615 // TODO(ukai): per functype?
Fumitoshi Ukai432a2422015-06-11 15:16:29 +0900616 traceEvent.end(te)
Fumitoshi Ukai6ac7f692015-04-15 17:13:51 +0900617}
Fumitoshi Ukai4a708512015-06-11 17:15:49 +0900618
619type matchVarref struct{}
620
621func (m matchVarref) String() string { return "$(match-any)" }
622func (m matchVarref) Eval(w io.Writer, ev *Evaluator) { panic("not implemented") }
623func (m matchVarref) Serialize() SerializableVar { panic("not implemented") }
624func (m matchVarref) Dump(w io.Writer) { panic("not implemented") }
625
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900626func matchValue(expr, pat Value) bool {
627 switch pat := pat.(type) {
628 case literal:
629 return literal(expr.String()) == pat
630 }
631 // TODO: other type match?
632 return false
633}
634
Fumitoshi Ukai4a708512015-06-11 17:15:49 +0900635func matchExpr(expr, pat Expr) ([]Value, bool) {
636 if len(expr) != len(pat) {
637 return nil, false
638 }
639 var mv matchVarref
640 var matches []Value
641 for i := range expr {
642 if pat[i] == mv {
643 switch expr[i].(type) {
644 case paramref, varref:
645 matches = append(matches, expr[i])
646 continue
647 }
648 return nil, false
649 }
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900650 if !matchValue(expr[i], pat[i]) {
Fumitoshi Ukai4a708512015-06-11 17:15:49 +0900651 return nil, false
652 }
653 }
654 return matches, true
655}