diff --git a/.gitignore b/.gitignore index 72a053db9..e852cc3b5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,6 @@ example.tf terraform.tfplan terraform.tfstate bin/ -config/y.go -config/y.output modules-dev/ pkg/ vendor/ diff --git a/Makefile b/Makefile index cfc16cb07..44922e283 100644 --- a/Makefile +++ b/Makefile @@ -2,26 +2,26 @@ TEST?=./... default: test -bin: config/y.go generate +bin: generate @sh -c "'$(CURDIR)/scripts/build.sh'" -dev: config/y.go generate +dev: generate @TF_DEV=1 sh -c "'$(CURDIR)/scripts/build.sh'" -test: config/y.go generate +test: generate TF_ACC= go test $(TEST) $(TESTARGS) -timeout=10s -parallel=4 -testacc: config/y.go generate +testacc: generate @if [ "$(TEST)" = "./..." ]; then \ echo "ERROR: Set TEST to a specific package"; \ exit 1; \ fi TF_ACC=1 go test $(TEST) -v $(TESTARGS) -timeout 45m -testrace: config/y.go generate +testrace: generate TF_ACC= go test -race $(TEST) $(TESTARGS) -updatedeps: config/y.go +updatedeps: go get -u golang.org/x/tools/cmd/stringer # Go 1.4 changed the format of `go get` a bit by requiring the # canonical full path. We work around this and just force. @@ -31,14 +31,7 @@ updatedeps: config/y.go go get -f -u -v ./...; \ fi -config/y.go: config/expr.y - cd config/ && \ - go tool yacc -p "expr" expr.y - -clean: - rm config/y.go - generate: go generate ./... -.PHONY: bin clean default generate test updatedeps +.PHONY: bin default generate test updatedeps diff --git a/config/expr.y b/config/expr.y deleted file mode 100644 index 1c295cce6..000000000 --- a/config/expr.y +++ /dev/null @@ -1,91 +0,0 @@ -// This is the yacc input for creating the parser for interpolation -// expressions in Go. - -// To build it: -// -// go tool yacc -p "expr" expr.y (produces y.go) -// - -%{ -package config - -import ( - "fmt" -) - -%} - -%union { - expr Interpolation - str string - variable InterpolatedVariable - args []Interpolation -} - -%type args -%type expr -%type string -%type variable - -%token STRING IDENTIFIER -%token COMMA LEFTPAREN RIGHTPAREN - -%% - -top: - expr - { - exprResult = $1 - } - -expr: - string - { - $$ = &LiteralInterpolation{Literal: $1} - } -| variable - { - $$ = &VariableInterpolation{Variable: $1} - } -| IDENTIFIER LEFTPAREN args RIGHTPAREN - { - f, ok := Funcs[$1] - if !ok { - exprErrors = append(exprErrors, fmt.Errorf( - "Unknown function: %s", $1)) - } - - $$ = &FunctionInterpolation{Func: f, Args: $3} - } - -args: - { - $$ = nil - } -| args COMMA expr - { - $$ = append($1, $3) - } -| expr - { - $$ = append($$, $1) - } - -string: - STRING - { - $$ = $1 - } - -variable: - IDENTIFIER - { - var err error - $$, err = NewInterpolatedVariable($1) - if err != nil { - exprErrors = append(exprErrors, fmt.Errorf( - "Error parsing variable '%s': %s", $1, err)) - } - } - -%% diff --git a/config/expr_lex.go b/config/expr_lex.go deleted file mode 100644 index f94e947ba..000000000 --- a/config/expr_lex.go +++ /dev/null @@ -1,134 +0,0 @@ -package config - -import ( - "bytes" - "fmt" - "log" - "unicode" - "unicode/utf8" -) - -// The parser expects the lexer to return 0 on EOF. -const lexEOF = 0 - -// The parser uses the type Lex as a lexer. It must provide -// the methods Lex(*SymType) int and Error(string). -type exprLex struct { - Err error - Input string - - pos int - width int -} - -// The parser calls this method to get each new token. -func (x *exprLex) Lex(yylval *exprSymType) int { - for { - c := x.next() - if c == lexEOF { - return lexEOF - } - - // Ignore all whitespace - if unicode.IsSpace(c) { - continue - } - - switch c { - case '"': - return x.lexString(yylval) - case ',': - return COMMA - case '(': - return LEFTPAREN - case ')': - return RIGHTPAREN - default: - x.backup() - return x.lexId(yylval) - } - } -} - -func (x *exprLex) lexId(yylval *exprSymType) int { - var b bytes.Buffer - for { - c := x.next() - if c == lexEOF { - break - } - - // If this isn't a character we want in an ID, return out. - // One day we should make this a regexp. - if c != '_' && - c != '-' && - c != '.' && - c != '*' && - !unicode.IsLetter(c) && - !unicode.IsNumber(c) { - x.backup() - break - } - - if _, err := b.WriteRune(c); err != nil { - log.Printf("ERR: %s", err) - return lexEOF - } - } - - yylval.str = b.String() - return IDENTIFIER -} - -func (x *exprLex) lexString(yylval *exprSymType) int { - var b bytes.Buffer - for { - c := x.next() - if c == lexEOF { - break - } - - // String end - if c == '"' { - break - } - - if _, err := b.WriteRune(c); err != nil { - log.Printf("ERR: %s", err) - return lexEOF - } - } - - yylval.str = b.String() - return STRING -} - -// Return the next rune for the lexer. -func (x *exprLex) next() rune { - if int(x.pos) >= len(x.Input) { - x.width = 0 - return lexEOF - } - - r, w := utf8.DecodeRuneInString(x.Input[x.pos:]) - x.width = w - x.pos += x.width - return r -} - -// peek returns but does not consume the next rune in the input -func (x *exprLex) peek() rune { - r := x.next() - x.backup() - return r -} - -// backup steps back one rune. Can only be called once per next. -func (x *exprLex) backup() { - x.pos -= x.width -} - -// The parser calls this method on a parse error. -func (x *exprLex) Error(s string) { - x.Err = fmt.Errorf("parse error: %s", s) -} diff --git a/config/expr_lex_test.go b/config/expr_lex_test.go deleted file mode 100644 index 8e94d86f3..000000000 --- a/config/expr_lex_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package config - -import ( - "io/ioutil" - "path/filepath" - "reflect" - "testing" -) - -func TestLex(t *testing.T) { - cases := []struct { - Input string - Output []int - }{ - { - "concat.hcl", - []int{IDENTIFIER, LEFTPAREN, - STRING, COMMA, STRING, COMMA, STRING, - RIGHTPAREN, lexEOF}, - }, - } - - for _, tc := range cases { - d, err := ioutil.ReadFile(filepath.Join( - fixtureDir, "interpolations", tc.Input)) - if err != nil { - t.Fatalf("err: %s", err) - } - - l := &exprLex{Input: string(d)} - var actual []int - for { - token := l.Lex(new(exprSymType)) - actual = append(actual, token) - - if token == lexEOF { - break - } - - if len(actual) > 500 { - t.Fatalf("Input:%s\n\nExausted.", tc.Input) - } - } - - if !reflect.DeepEqual(actual, tc.Output) { - t.Fatalf( - "Input: %s\n\nBad: %#v\n\nExpected: %#v", - tc.Input, actual, tc.Output) - } - } -} diff --git a/config/expr_parse.go b/config/expr_parse.go deleted file mode 100644 index c6fb39f87..000000000 --- a/config/expr_parse.go +++ /dev/null @@ -1,40 +0,0 @@ -package config - -import ( - "sync" - - "github.com/hashicorp/terraform/helper/multierror" -) - -// exprErrors are the errors built up from parsing. These should not -// be accessed directly. -var exprErrors []error -var exprLock sync.Mutex -var exprResult Interpolation - -// ExprParse parses the given expression and returns an executable -// Interpolation. -func ExprParse(v string) (Interpolation, error) { - exprLock.Lock() - defer exprLock.Unlock() - exprErrors = nil - exprResult = nil - - // Parse - lex := &exprLex{Input: v} - exprParse(lex) - - // Build up the errors - var err error - if lex.Err != nil { - err = multierror.ErrorAppend(err, lex.Err) - } - if len(exprErrors) > 0 { - err = multierror.ErrorAppend(err, exprErrors...) - } - if err != nil { - exprResult = nil - } - - return exprResult, err -} diff --git a/config/expr_parse_test.go b/config/expr_parse_test.go deleted file mode 100644 index da77c7bda..000000000 --- a/config/expr_parse_test.go +++ /dev/null @@ -1,148 +0,0 @@ -package config - -import ( - "reflect" - "testing" -) - -func TestExprParse(t *testing.T) { - cases := []struct { - Input string - Result Interpolation - Error bool - }{ - { - "foo", - nil, - true, - }, - - { - `"foo"`, - &LiteralInterpolation{Literal: "foo"}, - false, - }, - - { - "var.foo", - &VariableInterpolation{ - Variable: &UserVariable{ - Name: "foo", - key: "var.foo", - }, - }, - false, - }, - - { - "module.foo.bar", - &VariableInterpolation{ - Variable: &ModuleVariable{ - Name: "foo", - Field: "bar", - key: "module.foo.bar", - }, - }, - false, - }, - - { - "lookup(var.foo, var.bar)", - &FunctionInterpolation{ - Func: nil, // Funcs["lookup"] - Args: []Interpolation{ - &VariableInterpolation{ - Variable: &UserVariable{ - Name: "foo", - key: "var.foo", - }, - }, - &VariableInterpolation{ - Variable: &UserVariable{ - Name: "bar", - key: "var.bar", - }, - }, - }, - }, - false, - }, - - { - "lookup(var.foo, lookup(var.baz, var.bar))", - &FunctionInterpolation{ - Func: nil, // Funcs["lookup"] - Args: []Interpolation{ - &VariableInterpolation{ - Variable: &UserVariable{ - Name: "foo", - key: "var.foo", - }, - }, - &FunctionInterpolation{ - Func: nil, // Funcs["lookup"] - Args: []Interpolation{ - &VariableInterpolation{ - Variable: &UserVariable{ - Name: "baz", - key: "var.baz", - }, - }, - &VariableInterpolation{ - Variable: &UserVariable{ - Name: "bar", - key: "var.bar", - }, - }, - }, - }, - }, - }, - false, - }, - - { - `concat("foo","-","0.0/16")`, - &FunctionInterpolation{ - Func: nil, // Funcs["lookup"] - Args: []Interpolation{ - &LiteralInterpolation{Literal: "foo"}, - &LiteralInterpolation{Literal: "-"}, - &LiteralInterpolation{Literal: "0.0/16"}, - }, - }, - false, - }, - } - - for i, tc := range cases { - actual, err := ExprParse(tc.Input) - if (err != nil) != tc.Error { - t.Fatalf("%d. Error: %s", i, err) - } - - // This is jank, but reflect.DeepEqual never has functions - // being the same. - f, ok := actual.(*FunctionInterpolation) - if ok { - fs := make([]*FunctionInterpolation, 1) - fs[0] = f - for len(fs) > 0 { - f := fs[0] - fs = fs[1:] - - f.Func = nil - for _, a := range f.Args { - f, ok := a.(*FunctionInterpolation) - if ok { - fs = append(fs, f) - } - } - } - } - - if !reflect.DeepEqual(actual, tc.Result) { - t.Fatalf("%d bad: %#v", i, actual) - } - } -}