github.com/franklinhu/terraform@v0.6.9-0.20151202232446-81f7fb1e6f9e/config/lang/lang.y (about) 1 // This is the yacc input for creating the parser for interpolation 2 // expressions in Go. To build it, just run `go generate` on this 3 // package, as the lexer has the go generate pragma within it. 4 5 %{ 6 package lang 7 8 import ( 9 "github.com/hashicorp/terraform/config/lang/ast" 10 ) 11 12 %} 13 14 %union { 15 node ast.Node 16 nodeList []ast.Node 17 str string 18 token *parserToken 19 } 20 21 %token <str> PROGRAM_BRACKET_LEFT PROGRAM_BRACKET_RIGHT 22 %token <str> PROGRAM_STRING_START PROGRAM_STRING_END 23 %token <str> PAREN_LEFT PAREN_RIGHT COMMA 24 25 %token <token> ARITH_OP IDENTIFIER INTEGER FLOAT STRING 26 27 %type <node> expr interpolation literal literalModeTop literalModeValue 28 %type <nodeList> args 29 30 %left ARITH_OP 31 32 %% 33 34 top: 35 { 36 parserResult = &ast.LiteralNode{ 37 Value: "", 38 Typex: ast.TypeString, 39 Posx: ast.Pos{Column: 1, Line: 1}, 40 } 41 } 42 | literalModeTop 43 { 44 parserResult = $1 45 46 // We want to make sure that the top value is always a Concat 47 // so that the return value is always a string type from an 48 // interpolation. 49 // 50 // The logic for checking for a LiteralNode is a little annoying 51 // because functionally the AST is the same, but we do that because 52 // it makes for an easy literal check later (to check if a string 53 // has any interpolations). 54 if _, ok := $1.(*ast.Concat); !ok { 55 if n, ok := $1.(*ast.LiteralNode); !ok || n.Typex != ast.TypeString { 56 parserResult = &ast.Concat{ 57 Exprs: []ast.Node{$1}, 58 Posx: $1.Pos(), 59 } 60 } 61 } 62 } 63 64 literalModeTop: 65 literalModeValue 66 { 67 $$ = $1 68 } 69 | literalModeTop literalModeValue 70 { 71 var result []ast.Node 72 if c, ok := $1.(*ast.Concat); ok { 73 result = append(c.Exprs, $2) 74 } else { 75 result = []ast.Node{$1, $2} 76 } 77 78 $$ = &ast.Concat{ 79 Exprs: result, 80 Posx: result[0].Pos(), 81 } 82 } 83 84 literalModeValue: 85 literal 86 { 87 $$ = $1 88 } 89 | interpolation 90 { 91 $$ = $1 92 } 93 94 interpolation: 95 PROGRAM_BRACKET_LEFT expr PROGRAM_BRACKET_RIGHT 96 { 97 $$ = $2 98 } 99 100 expr: 101 PAREN_LEFT expr PAREN_RIGHT 102 { 103 $$ = $2 104 } 105 | literalModeTop 106 { 107 $$ = $1 108 } 109 | INTEGER 110 { 111 $$ = &ast.LiteralNode{ 112 Value: $1.Value.(int), 113 Typex: ast.TypeInt, 114 Posx: $1.Pos, 115 } 116 } 117 | FLOAT 118 { 119 $$ = &ast.LiteralNode{ 120 Value: $1.Value.(float64), 121 Typex: ast.TypeFloat, 122 Posx: $1.Pos, 123 } 124 } 125 | expr ARITH_OP expr 126 { 127 $$ = &ast.Arithmetic{ 128 Op: $2.Value.(ast.ArithmeticOp), 129 Exprs: []ast.Node{$1, $3}, 130 Posx: $1.Pos(), 131 } 132 } 133 | IDENTIFIER 134 { 135 $$ = &ast.VariableAccess{Name: $1.Value.(string), Posx: $1.Pos} 136 } 137 | IDENTIFIER PAREN_LEFT args PAREN_RIGHT 138 { 139 $$ = &ast.Call{Func: $1.Value.(string), Args: $3, Posx: $1.Pos} 140 } 141 142 args: 143 { 144 $$ = nil 145 } 146 | args COMMA expr 147 { 148 $$ = append($1, $3) 149 } 150 | expr 151 { 152 $$ = append($$, $1) 153 } 154 155 literal: 156 STRING 157 { 158 $$ = &ast.LiteralNode{ 159 Value: $1.Value.(string), 160 Typex: ast.TypeString, 161 Posx: $1.Pos, 162 } 163 } 164 165 %%