terraform/config/lang/lang.y

166 lines
3.3 KiB
Plaintext
Raw Normal View History

2015-01-11 21:38:45 +01:00
// This is the yacc input for creating the parser for interpolation
// expressions in Go. To build it, just run `go generate` on this
// package, as the lexer has the go generate pragma within it.
%{
package lang
import (
"github.com/hashicorp/terraform/config/lang/ast"
)
%}
%union {
2015-01-11 22:03:37 +01:00
node ast.Node
nodeList []ast.Node
str string
2015-01-12 09:28:47 +01:00
token *parserToken
2015-01-11 21:38:45 +01:00
}
2015-01-12 09:28:47 +01:00
%token <str> PROGRAM_BRACKET_LEFT PROGRAM_BRACKET_RIGHT
%token <str> PROGRAM_STRING_START PROGRAM_STRING_END
2015-01-11 22:03:37 +01:00
%token <str> PAREN_LEFT PAREN_RIGHT COMMA
2015-01-11 21:38:45 +01:00
%token <token> ARITH_OP IDENTIFIER INTEGER FLOAT STRING
2015-01-12 09:28:47 +01:00
2015-02-26 23:26:14 +01:00
%type <node> expr interpolation literal literalModeTop literalModeValue
2015-01-11 22:03:37 +01:00
%type <nodeList> args
2015-01-11 21:38:45 +01:00
2015-02-26 23:33:56 +01:00
%left ARITH_OP
2015-01-11 21:38:45 +01:00
%%
top:
{
parserResult = &ast.LiteralNode{
Value: "",
2015-01-15 05:58:46 +01:00
Typex: ast.TypeString,
Posx: ast.Pos{Column: 1, Line: 1},
}
}
| literalModeTop
2015-01-11 21:38:45 +01:00
{
parserResult = $1
// We want to make sure that the top value is always a Concat
// so that the return value is always a string type from an
// interpolation.
//
// The logic for checking for a LiteralNode is a little annoying
// because functionally the AST is the same, but we do that because
// it makes for an easy literal check later (to check if a string
// has any interpolations).
if _, ok := $1.(*ast.Concat); !ok {
2015-01-15 05:58:46 +01:00
if n, ok := $1.(*ast.LiteralNode); !ok || n.Typex != ast.TypeString {
parserResult = &ast.Concat{
Exprs: []ast.Node{$1},
Posx: $1.Pos(),
}
}
}
2015-01-11 21:38:45 +01:00
}
literalModeTop:
literalModeValue
2015-01-11 22:03:37 +01:00
{
$$ = $1
2015-01-11 22:03:37 +01:00
}
| literalModeTop literalModeValue
2015-01-11 21:38:45 +01:00
{
var result []ast.Node
if c, ok := $1.(*ast.Concat); ok {
result = append(c.Exprs, $2)
} else {
result = []ast.Node{$1, $2}
}
$$ = &ast.Concat{
Exprs: result,
2015-01-12 09:28:47 +01:00
Posx: result[0].Pos(),
2015-01-11 21:38:45 +01:00
}
}
literalModeValue:
literal
{
$$ = $1
}
| interpolation
{
$$ = $1
}
2015-01-11 21:38:45 +01:00
interpolation:
PROGRAM_BRACKET_LEFT expr PROGRAM_BRACKET_RIGHT
{
$$ = $2
}
expr:
PAREN_LEFT expr PAREN_RIGHT
{
$$ = $2
}
| literalModeTop
2015-01-11 22:03:37 +01:00
{
$$ = $1
}
2015-01-12 17:53:27 +01:00
| INTEGER
{
$$ = &ast.LiteralNode{
Value: $1.Value.(int),
2015-01-15 05:58:46 +01:00
Typex: ast.TypeInt,
2015-01-12 17:53:27 +01:00
Posx: $1.Pos,
}
}
| FLOAT
{
$$ = &ast.LiteralNode{
Value: $1.Value.(float64),
2015-01-15 05:58:46 +01:00
Typex: ast.TypeFloat,
2015-01-12 17:53:27 +01:00
Posx: $1.Pos,
}
}
2015-02-26 23:26:14 +01:00
| expr ARITH_OP expr
{
2015-02-26 23:26:14 +01:00
$$ = &ast.Arithmetic{
Op: $2.Value.(ast.ArithmeticOp),
Exprs: []ast.Node{$1, $3},
Posx: $1.Pos(),
}
}
2015-01-11 22:03:37 +01:00
| IDENTIFIER
2015-01-11 21:38:45 +01:00
{
2015-01-12 09:28:47 +01:00
$$ = &ast.VariableAccess{Name: $1.Value.(string), Posx: $1.Pos}
2015-01-11 21:38:45 +01:00
}
2015-01-11 22:03:37 +01:00
| IDENTIFIER PAREN_LEFT args PAREN_RIGHT
2015-01-11 21:38:45 +01:00
{
2015-01-12 09:28:47 +01:00
$$ = &ast.Call{Func: $1.Value.(string), Args: $3, Posx: $1.Pos}
2015-01-11 21:38:45 +01:00
}
2015-01-11 22:03:37 +01:00
args:
{
$$ = nil
}
| args COMMA expr
{
$$ = append($1, $3)
}
| expr
{
$$ = append($$, $1)
}
2015-01-11 21:38:45 +01:00
literal:
STRING
{
2015-01-12 09:28:47 +01:00
$$ = &ast.LiteralNode{
Value: $1.Value.(string),
2015-01-15 05:58:46 +01:00
Typex: ast.TypeString,
2015-01-12 09:28:47 +01:00
Posx: $1.Pos,
}
2015-01-11 21:38:45 +01:00
}
%%