Implement += and ?=
diff --git a/ast.go b/ast.go
index f4dd83f..fe8e21f 100644
--- a/ast.go
+++ b/ast.go
@@ -23,14 +23,23 @@
ev.evalAssign(ast)
}
-func (ast *AssignAST) evalRHS(ev *Evaluator) string {
+func (ast *AssignAST) evalRHS(ev *Evaluator, lhs string) string {
switch ast.op {
case ":=":
return ev.evalExpr(ast.rhs)
case "=":
return ast.rhs
- default: // "+=", "?="
- panic(fmt.Sprintf("not implemented assign op: %q", ast.op))
+ case "+=":
+ prev, _ := ev.getVar(lhs)
+ return fmt.Sprintf("%s %s", prev, ev.evalExpr(ast.rhs))
+ case "?=":
+ prev, present := ev.getVar(lhs)
+ if present {
+ return prev
+ }
+ return ev.evalExpr(ast.rhs)
+ default:
+ panic(fmt.Sprintf("unknown assign op: %q", ast.op))
}
}
diff --git a/eval.go b/eval.go
index dbff80f..6f092cc 100644
--- a/eval.go
+++ b/eval.go
@@ -120,7 +120,7 @@
ev.lineno = ast.lineno
lhs := ev.evalExpr(ast.lhs)
- rhs := ast.evalRHS(ev)
+ rhs := ast.evalRHS(ev, lhs)
Log("ASSIGN: %s=%s", lhs, rhs)
ev.outVars[lhs] = rhs
}
@@ -165,6 +165,18 @@
}
}
+func (ev *Evaluator) getVar(name string) (string, bool) {
+ value, present := ev.outVars[name]
+ if present {
+ return value, true
+ }
+ value, present = ev.vars[name]
+ if present {
+ return value, true
+ }
+ return "", false
+}
+
func (ev *Evaluator) getVars() map[string]string {
vars := make(map[string]string)
for k, v := range ev.vars {
diff --git a/parser.go b/parser.go
index 3f9c5a2..4b93928 100644
--- a/parser.go
+++ b/parser.go
@@ -164,8 +164,10 @@
}
case '=':
ast = p.parseAssign(line, i, i+1)
- case '?':
- panic("TODO")
+ case '?', '+':
+ if i+1 < len(line) && line[i+1] == '=' {
+ ast = p.parseAssign(line, i, i+2)
+ }
}
if ast != nil {
p.mk.stmts = append(p.mk.stmts, ast)
diff --git a/test/assign_types.mk b/test/assign_types.mk
index adbceee..4ceaecd 100644
--- a/test/assign_types.mk
+++ b/test/assign_types.mk
@@ -2,6 +2,10 @@
B = $(A)
C := $(A)
A = aa
+D = b
+D += b
+E ?= c
+E ?= d
test:
- echo $(B) $(C)
+ echo $(B) $(C) $(D) $(E)