github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/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  %%