aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eval.go6
-rw-r--r--evalcmd.go2
-rw-r--r--expr.go53
-rw-r--r--expr_test.go2
-rw-r--r--func.go2
-rw-r--r--parser.go16
-rw-r--r--testcase/unmatched_paren.mk2
-rw-r--r--var.go8
8 files changed, 52 insertions, 39 deletions
diff --git a/eval.go b/eval.go
index 736c7e1..0ee66ba 100644
--- a/eval.go
+++ b/eval.go
@@ -289,7 +289,7 @@ func (ev *Evaluator) evalMaybeRule(ast *maybeRuleAST) error {
if assign != nil {
if ast.term == ';' {
- nexpr, _, err := parseExpr(ast.afterTerm, nil, false)
+ nexpr, _, err := parseExpr(ast.afterTerm, nil, parseOp{})
if err != nil {
return ast.errorf("parse error: %q: %v", string(ast.afterTerm), err)
}
@@ -424,7 +424,7 @@ func (ev *Evaluator) evalInclude(ast *includeAST) error {
ev.srcpos = ast.srcpos
logf("%s include %q", ev.srcpos, ast.expr)
- v, _, err := parseExpr([]byte(ast.expr), nil, false)
+ v, _, err := parseExpr([]byte(ast.expr), nil, parseOp{})
if err != nil {
return ast.errorf("parse failed: %q: %v", ast.expr, err)
}
@@ -538,7 +538,7 @@ func (ev *Evaluator) evalExport(ast *exportAST) error {
ev.lastRule = nil
ev.srcpos = ast.srcpos
- v, _, err := parseExpr(ast.expr, nil, false)
+ v, _, err := parseExpr(ast.expr, nil, parseOp{})
if err != nil {
return ast.errorf("failed to parse: %q: %v", string(ast.expr), err)
}
diff --git a/evalcmd.go b/evalcmd.go
index 9f201c7..7252918 100644
--- a/evalcmd.go
+++ b/evalcmd.go
@@ -236,7 +236,7 @@ func (r runner) eval(ev *Evaluator, s string) ([]runner, error) {
return []runner{r}, nil
}
// TODO(ukai): parse once more earlier?
- expr, _, err := parseExpr([]byte(r.cmd), nil, false)
+ expr, _, err := parseExpr([]byte(r.cmd), nil, parseOp{})
if err != nil {
return nil, ev.errorf("parse cmd %q: %v", r.cmd, err)
}
diff --git a/expr.go b/expr.go
index b69fecd..f0624a1 100644
--- a/expr.go
+++ b/expr.go
@@ -26,7 +26,6 @@ import (
)
var (
- errEndOfInput = errors.New("parse: unexpected end of input")
errNotLiteral = errors.New("valueNum: not literal")
bufFree = sync.Pool{
@@ -323,14 +322,21 @@ func valueNum(v Value) (int, error) {
return 0, errNotLiteral
}
+type parseOp struct {
+ // alloc indicates text will be allocated as literal (string)
+ alloc bool
+
+ // matchParen matches parenthesis.
+ // note: required for func arg
+ matchParen bool
+}
+
// parseExpr parses expression in `in` until it finds any byte in term.
// if term is nil, it will parse to end of input.
-// if term is not nil, and it reaches to end of input, return errEndOfInput.
+// if term is not nil, and it reaches to end of input, return error.
// it returns parsed value, and parsed length `n`, so in[n-1] is any byte of
// term, and in[n:] is next input.
-// if alloc is true, text will be literal (allocate string).
-// otherwise, text will be tmpval on in.
-func parseExpr(in, term []byte, alloc bool) (Value, int, error) {
+func parseExpr(in, term []byte, op parseOp) (Value, int, error) {
var exp expr
b := 0
i := 0
@@ -348,20 +354,20 @@ Loop:
break Loop
}
if in[i+1] == '$' {
- exp = appendStr(exp, in[b:i+1], alloc)
+ exp = appendStr(exp, in[b:i+1], op.alloc)
i += 2
b = i
continue
}
if bytes.IndexByte(term, in[i+1]) >= 0 {
- exp = appendStr(exp, in[b:i], alloc)
+ exp = appendStr(exp, in[b:i], op.alloc)
exp = append(exp, &varref{varname: literal("")})
i++
b = i
break Loop
}
- exp = appendStr(exp, in[b:i], alloc)
- v, n, err := parseDollar(in[i:], alloc)
+ exp = appendStr(exp, in[b:i], op.alloc)
+ v, n, err := parseDollar(in[i:], op.alloc)
if err != nil {
return nil, 0, err
}
@@ -370,6 +376,9 @@ Loop:
exp = append(exp, v)
continue
case '(', '{':
+ if !op.matchParen {
+ break
+ }
cp := closeParen(ch)
if i := bytes.IndexByte(term, cp); i >= 0 {
parenDepth++
@@ -379,6 +388,9 @@ Loop:
parenDepth++
}
case saveParen:
+ if !op.matchParen {
+ break
+ }
parenDepth--
if parenDepth == 0 {
i := bytes.IndexByte(term, 0)
@@ -388,9 +400,9 @@ Loop:
}
i++
}
- exp = appendStr(exp, in[b:i], alloc)
+ exp = appendStr(exp, in[b:i], op.alloc)
if i == len(in) && term != nil {
- return exp, i, errEndOfInput
+ return exp, i, fmt.Errorf("parse: unexpected end of input: %q %d [%q]", in, i, term)
}
return compactExpr(exp), i, nil
}
@@ -433,9 +445,10 @@ func parseDollar(in []byte, alloc bool) (Value, int, error) {
term := []byte{paren, ':', ' '}
var varname expr
i := 2
+ op := parseOp{alloc: alloc}
Again:
for {
- e, n, err := parseExpr(in[i:], term, alloc)
+ e, n, err := parseExpr(in[i:], term, op)
if err != nil {
return nil, 0, err
}
@@ -457,7 +470,7 @@ Again:
case literal, tmpval:
funcName := intern(token.String())
if f, ok := funcMap[funcName]; ok {
- return parseFunc(f(), in, i+1, term[:1], funcName, alloc)
+ return parseFunc(f(), in, i+1, term[:1], funcName, op.alloc)
}
}
term = term[:2] // drop ' '
@@ -465,20 +478,21 @@ Again:
case ':':
// ${varname:...}
colon := in[i : i+1]
- term = term[:2]
- term[1] = '=' // term={paren, '='}.
- e, n, err := parseExpr(in[i+1:], term, alloc)
+ var vterm []byte
+ vterm = append(vterm, term[:2]...)
+ vterm[1] = '=' // term={paren, '='}.
+ e, n, err := parseExpr(in[i+1:], vterm, op)
if err != nil {
return nil, 0, err
}
i += 1 + n
if in[i] == paren {
- varname = appendStr(varname, colon, alloc)
+ varname = appendStr(varname, colon, op.alloc)
return &varref{varname: varname, paren: oparen}, i + 1, nil
}
// ${varname:xx=...}
pat := e
- subst, n, err := parseExpr(in[i+1:], term[:1], alloc)
+ subst, n, err := parseExpr(in[i+1:], term[:1], op)
if err != nil {
return nil, 0, err
}
@@ -600,12 +614,13 @@ func parseFunc(f mkFunc, in []byte, s int, term []byte, funcName string, alloc b
return f, i, nil
}
narg := 1
+ op := parseOp{alloc: alloc, matchParen: true}
for {
if arity != 0 && narg >= arity {
// final arguments.
term = term[:1] // drop ','
}
- v, n, err := parseExpr(in[i:], term, alloc)
+ v, n, err := parseExpr(in[i:], term, op)
if err != nil {
return nil, 0, err
}
diff --git a/expr_test.go b/expr_test.go
index 7a38cf5..ad51a89 100644
--- a/expr_test.go
+++ b/expr_test.go
@@ -290,7 +290,7 @@ func TestParseExpr(t *testing.T) {
},
},
} {
- val, _, err := parseExpr([]byte(tc.in), nil, true)
+ val, _, err := parseExpr([]byte(tc.in), nil, parseOp{alloc: true})
if tc.isErr {
if err == nil {
t.Errorf(`parseExpr(%q)=_, _, nil; want error`, tc.in)
diff --git a/func.go b/func.go
index 576855e..89fdbe2 100644
--- a/func.go
+++ b/func.go
@@ -1240,7 +1240,7 @@ func (f *funcEvalAssign) Eval(w io.Writer, ev *Evaluator) error {
case ":=":
// TODO(ukai): compute parsed expr in Compact when f.rhs is
// literal? e.g. literal("$(foo)") => varref{literal("foo")}.
- exp, _, err := parseExpr(rhs, nil, false)
+ exp, _, err := parseExpr(rhs, nil, parseOp{})
if err != nil {
return ev.errorf("eval assign error: %q: %v", f.String(), err)
}
diff --git a/parser.go b/parser.go
index c025307..5eb496e 100644
--- a/parser.go
+++ b/parser.go
@@ -167,11 +167,11 @@ func (p *parser) processRecipeLine(line []byte) []byte {
}
func newAssignAST(p *parser, lhsBytes []byte, rhsBytes []byte, op string) (*assignAST, error) {
- lhs, _, err := parseExpr(lhsBytes, nil, true)
+ lhs, _, err := parseExpr(lhsBytes, nil, parseOp{alloc: true})
if err != nil {
return nil, err
}
- rhs, _, err := parseExpr(rhsBytes, nil, true)
+ rhs, _, err := parseExpr(rhsBytes, nil, parseOp{alloc: true})
if err != nil {
return nil, err
}
@@ -224,7 +224,7 @@ func (p *parser) parseMaybeRule(line []byte, equalIndex, semicolonIndex int) (as
term = '='
}
- v, _, err := parseExpr(expr, nil, true)
+ v, _, err := parseExpr(expr, nil, parseOp{alloc: true})
if err != nil {
return nil, p.srcpos().error(err)
}
@@ -249,7 +249,7 @@ func (p *parser) parseInclude(line string, oplen int) {
}
func (p *parser) parseIfdef(line []byte, oplen int) {
- lhs, _, err := parseExpr(trimLeftSpaceBytes(line[oplen+1:]), nil, true)
+ lhs, _, err := parseExpr(trimLeftSpaceBytes(line[oplen+1:]), nil, parseOp{alloc: true})
if err != nil {
p.err = p.srcpos().error(err)
return
@@ -296,14 +296,14 @@ func (p *parser) parseEq(s string, op string) (string, string, bool, error) {
s = s[1 : len(s)-1]
term := []byte{','}
in := []byte(s)
- v, n, err := parseExpr(in, term, false)
+ v, n, err := parseExpr(in, term, parseOp{matchParen: true})
if err != nil {
return "", "", false, err
}
lhs := v.String()
n++
n += skipSpaces(in[n:], nil)
- v, n, err = parseExpr(in[n:], nil, false)
+ v, n, err = parseExpr(in[n:], nil, parseOp{matchParen: true})
if err != nil {
return "", "", false, err
}
@@ -329,12 +329,12 @@ func (p *parser) parseIfeq(line string, oplen int) {
return
}
- lhs, _, err := parseExpr([]byte(lhsBytes), nil, true)
+ lhs, _, err := parseExpr([]byte(lhsBytes), nil, parseOp{matchParen: true})
if err != nil {
p.err = p.srcpos().error(err)
return
}
- rhs, _, err := parseExpr([]byte(rhsBytes), nil, true)
+ rhs, _, err := parseExpr([]byte(rhsBytes), nil, parseOp{matchParen: true})
if err != nil {
p.err = p.srcpos().error(err)
return
diff --git a/testcase/unmatched_paren.mk b/testcase/unmatched_paren.mk
index 6f5d6c8..38c8954 100644
--- a/testcase/unmatched_paren.mk
+++ b/testcase/unmatched_paren.mk
@@ -1,5 +1,3 @@
-# TODO(go): Fix.
-
PAREN:=(
$(PAREN):=PASS
diff --git a/var.go b/var.go
index 446b00d..7169152 100644
--- a/var.go
+++ b/var.go
@@ -115,7 +115,7 @@ func (v *simpleVar) dump(d *dumpbuf) {
}
func (v *simpleVar) Append(ev *Evaluator, s string) (Var, error) {
- val, _, err := parseExpr([]byte(s), nil, false)
+ val, _, err := parseExpr([]byte(s), nil, parseOp{})
if err != nil {
return nil, err
}
@@ -165,7 +165,7 @@ func (v *automaticVar) dump(d *dumpbuf) {
}
func (v *automaticVar) Append(ev *Evaluator, s string) (Var, error) {
- val, _, err := parseExpr([]byte(s), nil, false)
+ val, _, err := parseExpr([]byte(s), nil, parseOp{})
if err != nil {
return nil, err
}
@@ -230,7 +230,7 @@ func (v *recursiveVar) Append(_ *Evaluator, s string) (Var, error) {
} else {
exp = expr{v.expr, literal(" ")}
}
- sv, _, err := parseExpr([]byte(s), nil, true)
+ sv, _, err := parseExpr([]byte(s), nil, parseOp{alloc: true})
if err != nil {
return nil, err
}
@@ -248,7 +248,7 @@ func (v *recursiveVar) AppendVar(ev *Evaluator, val Value) (Var, error) {
buf.WriteString(v.expr.String())
buf.WriteByte(' ')
buf.WriteString(val.String())
- e, _, err := parseExpr(buf.Bytes(), nil, true)
+ e, _, err := parseExpr(buf.Bytes(), nil, parseOp{alloc: true})
if err != nil {
return nil, err
}