JSON parser
This commit is contained in:
parent
e0d7c7b378
commit
358b43ddbc
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1 @@
|
||||
y.go
|
||||
y.output
|
||||
|
15
Makefile
15
Makefile
@ -1,9 +1,20 @@
|
||||
default: test
|
||||
|
||||
test: y.go
|
||||
go test
|
||||
fmt: y.go json/y.go
|
||||
go fmt ./...
|
||||
|
||||
test: y.go json/y.go
|
||||
go test ./...
|
||||
|
||||
y.go: parse.y
|
||||
go tool yacc -p "hcl" parse.y
|
||||
|
||||
json/y.go: json/parse.y
|
||||
cd json/ && \
|
||||
go tool yacc -p "json" parse.y
|
||||
|
||||
clean:
|
||||
rm -f y.go
|
||||
rm -f json/y.go
|
||||
|
||||
.PHONY: default test
|
||||
|
@ -1,4 +1,4 @@
|
||||
package hcl
|
||||
package ast
|
||||
|
||||
// ValueType is an enum represnting the type of a value in
|
||||
// a LiteralNode.
|
||||
@ -8,6 +8,8 @@ const (
|
||||
ValueTypeUnknown ValueType = iota
|
||||
ValueTypeInt
|
||||
ValueTypeString
|
||||
ValueTypeBool
|
||||
ValueTypeNil
|
||||
)
|
||||
|
||||
// Node is implemented by all AST nodes for HCL.
|
@ -1,4 +1,4 @@
|
||||
package hcl
|
||||
package ast
|
||||
|
||||
import (
|
||||
"reflect"
|
@ -1,4 +1,4 @@
|
||||
package hcl
|
||||
package ast
|
||||
|
||||
// MockVisitor is a visitor implementation that can be used for tests
|
||||
// and simply records the nodes that it has visited.
|
4
json/json_test.go
Normal file
4
json/json_test.go
Normal file
@ -0,0 +1,4 @@
|
||||
package json
|
||||
|
||||
// This is the directory where our test fixtures are.
|
||||
const fixtureDir = "./test-fixtures"
|
165
json/lex.go
Normal file
165
json/lex.go
Normal file
@ -0,0 +1,165 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// This marks the end of the lexer
|
||||
const lexEOF = 0
|
||||
|
||||
// The parser uses the type <prefix>Lex as a lexer. It must provide
|
||||
// the methods Lex(*<prefix>SymType) int and Error(string).
|
||||
type jsonLex struct {
|
||||
Input string
|
||||
|
||||
pos int
|
||||
width int
|
||||
col, line int
|
||||
err error
|
||||
}
|
||||
|
||||
// The parser calls this method to get each new token.
|
||||
func (x *jsonLex) Lex(yylval *jsonSymType) int {
|
||||
for {
|
||||
c := x.next()
|
||||
if c == lexEOF {
|
||||
return lexEOF
|
||||
}
|
||||
|
||||
// Ignore all whitespace except a newline which we handle
|
||||
// specially later.
|
||||
if unicode.IsSpace(c) {
|
||||
continue
|
||||
}
|
||||
|
||||
// If it is a number, lex the number
|
||||
if c >= '0' && c <= '9' {
|
||||
x.backup()
|
||||
return x.lexNumber(yylval)
|
||||
}
|
||||
|
||||
switch c {
|
||||
case ':':
|
||||
return COLON
|
||||
case ',':
|
||||
return COMMA
|
||||
case '[':
|
||||
return LEFTBRACKET
|
||||
case ']':
|
||||
return RIGHTBRACKET
|
||||
case '{':
|
||||
return LEFTBRACE
|
||||
case '}':
|
||||
return RIGHTBRACE
|
||||
case '"':
|
||||
return x.lexString(yylval)
|
||||
default:
|
||||
x.createErr(fmt.Sprintf("unexpected character: %c", c))
|
||||
return lexEOF
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// lexNumber lexes out a number
|
||||
func (x *jsonLex) lexNumber(yylval *jsonSymType) int {
|
||||
var b bytes.Buffer
|
||||
for {
|
||||
c := x.next()
|
||||
if c == lexEOF {
|
||||
break
|
||||
}
|
||||
|
||||
// No more numeric characters
|
||||
if c < '0' || c > '9' {
|
||||
x.backup()
|
||||
break
|
||||
}
|
||||
|
||||
if _, err := b.WriteRune(c); err != nil {
|
||||
x.createErr(fmt.Sprintf("Internal error: %s", err))
|
||||
return lexEOF
|
||||
}
|
||||
}
|
||||
|
||||
v, err := strconv.ParseInt(b.String(), 0, 0)
|
||||
if err != nil {
|
||||
x.createErr(fmt.Sprintf("Expected number: %s", err))
|
||||
return lexEOF
|
||||
}
|
||||
|
||||
yylval.num = int(v)
|
||||
return NUMBER
|
||||
}
|
||||
|
||||
// lexString extracts a string from the input
|
||||
func (x *jsonLex) lexString(yylval *jsonSymType) 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 {
|
||||
return lexEOF
|
||||
}
|
||||
}
|
||||
|
||||
yylval.str = b.String()
|
||||
return STRING
|
||||
}
|
||||
|
||||
// Return the next rune for the lexer.
|
||||
func (x *jsonLex) 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
|
||||
|
||||
x.col += 1
|
||||
if x.line == 0 {
|
||||
x.line = 1
|
||||
}
|
||||
if r == '\n' {
|
||||
x.line += 1
|
||||
x.col = 0
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// peek returns but does not consume the next rune in the input
|
||||
func (x *jsonLex) peek() rune {
|
||||
r := x.next()
|
||||
x.backup()
|
||||
return r
|
||||
}
|
||||
|
||||
// backup steps back one rune. Can only be called once per next.
|
||||
func (x *jsonLex) backup() {
|
||||
x.col -= 1
|
||||
x.pos -= x.width
|
||||
}
|
||||
|
||||
// createErr records the given error
|
||||
func (x *jsonLex) createErr(msg string) {
|
||||
x.err = fmt.Errorf("Line %d, column %d: %s", x.line, x.col, msg)
|
||||
}
|
||||
|
||||
// The parser calls this method on a parse error.
|
||||
func (x *jsonLex) Error(s string) {
|
||||
x.createErr(s)
|
||||
}
|
78
json/lex_test.go
Normal file
78
json/lex_test.go
Normal file
@ -0,0 +1,78 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLexJson(t *testing.T) {
|
||||
cases := []struct {
|
||||
Input string
|
||||
Output []int
|
||||
}{
|
||||
{
|
||||
"basic.json",
|
||||
[]int{
|
||||
LEFTBRACE,
|
||||
STRING, COLON, STRING,
|
||||
RIGHTBRACE,
|
||||
lexEOF,
|
||||
},
|
||||
},
|
||||
{
|
||||
"array.json",
|
||||
[]int{
|
||||
LEFTBRACE,
|
||||
STRING, COLON, LEFTBRACKET,
|
||||
NUMBER, COMMA, NUMBER, COMMA, STRING,
|
||||
RIGHTBRACKET, COMMA,
|
||||
STRING, COLON, STRING,
|
||||
RIGHTBRACE,
|
||||
lexEOF,
|
||||
},
|
||||
},
|
||||
{
|
||||
"object.json",
|
||||
[]int{
|
||||
LEFTBRACE,
|
||||
STRING, COLON, LEFTBRACE,
|
||||
STRING, COLON, LEFTBRACKET,
|
||||
NUMBER, COMMA, NUMBER,
|
||||
RIGHTBRACKET,
|
||||
RIGHTBRACE,
|
||||
RIGHTBRACE,
|
||||
lexEOF,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
d, err := ioutil.ReadFile(filepath.Join(fixtureDir, tc.Input))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
l := &jsonLex{Input: string(d)}
|
||||
var actual []int
|
||||
for {
|
||||
token := l.Lex(new(jsonSymType))
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
40
json/parse.go
Normal file
40
json/parse.go
Normal file
@ -0,0 +1,40 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/hcl/ast"
|
||||
"github.com/hashicorp/terraform/helper/multierror"
|
||||
)
|
||||
|
||||
// jsonErrors are the errors built up from parsing. These should not
|
||||
// be accessed directly.
|
||||
var jsonErrors []error
|
||||
var jsonLock sync.Mutex
|
||||
var jsonResult *ast.ObjectNode
|
||||
|
||||
// Parse parses the given string and returns the result.
|
||||
func Parse(v string) (*ast.ObjectNode, error) {
|
||||
jsonLock.Lock()
|
||||
defer jsonLock.Unlock()
|
||||
jsonErrors = nil
|
||||
jsonResult = nil
|
||||
|
||||
// Parse
|
||||
lex := &jsonLex{Input: v}
|
||||
jsonParse(lex)
|
||||
|
||||
// If we have an error in the lexer itself, return it
|
||||
if lex.err != nil {
|
||||
return nil, lex.err
|
||||
}
|
||||
|
||||
// Build up the errors
|
||||
var err error
|
||||
if len(jsonErrors) > 0 {
|
||||
err = &multierror.Error{Errors: jsonErrors}
|
||||
jsonResult = nil
|
||||
}
|
||||
|
||||
return jsonResult, err
|
||||
}
|
136
json/parse.y
Normal file
136
json/parse.y
Normal file
@ -0,0 +1,136 @@
|
||||
// This is the yacc input for creating the parser for HCL JSON.
|
||||
|
||||
%{
|
||||
package json
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/ast"
|
||||
)
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
array ast.ListNode
|
||||
assign ast.AssignmentNode
|
||||
item ast.Node
|
||||
list []ast.Node
|
||||
num int
|
||||
str string
|
||||
obj ast.ObjectNode
|
||||
}
|
||||
|
||||
%type <array> array
|
||||
%type <assign> pair
|
||||
%type <item> value
|
||||
%type <list> elements members
|
||||
%type <obj> object
|
||||
|
||||
%token <num> NUMBER
|
||||
%token <str> COLON COMMA IDENTIFIER EQUAL NEWLINE STRING
|
||||
%token <str> LEFTBRACE RIGHTBRACE LEFTBRACKET RIGHTBRACKET
|
||||
%token <str> TRUE FALSE NULL
|
||||
|
||||
%%
|
||||
|
||||
top:
|
||||
object
|
||||
{
|
||||
obj := $1
|
||||
jsonResult = &obj
|
||||
}
|
||||
|
||||
object:
|
||||
LEFTBRACE members RIGHTBRACE
|
||||
{
|
||||
$$ = ast.ObjectNode{Elem: $2}
|
||||
}
|
||||
| LEFTBRACE RIGHTBRACE
|
||||
{
|
||||
$$ = ast.ObjectNode{}
|
||||
}
|
||||
|
||||
members:
|
||||
pair
|
||||
{
|
||||
$$ = []ast.Node{$1}
|
||||
}
|
||||
| pair COMMA members
|
||||
{
|
||||
$$ = append($3, $1)
|
||||
}
|
||||
|
||||
pair:
|
||||
STRING COLON value
|
||||
{
|
||||
$$ = ast.AssignmentNode{
|
||||
Key: $1,
|
||||
Value: $3,
|
||||
}
|
||||
}
|
||||
|
||||
value:
|
||||
STRING
|
||||
{
|
||||
$$ = ast.LiteralNode{
|
||||
Type: ast.ValueTypeString,
|
||||
Value: $1,
|
||||
}
|
||||
}
|
||||
| NUMBER
|
||||
{
|
||||
$$ = ast.LiteralNode{
|
||||
Type: ast.ValueTypeInt,
|
||||
Value: $1,
|
||||
}
|
||||
}
|
||||
| object
|
||||
{
|
||||
$$ = $1
|
||||
}
|
||||
| array
|
||||
{
|
||||
$$ = $1
|
||||
}
|
||||
| TRUE
|
||||
{
|
||||
$$ = ast.LiteralNode{
|
||||
Type: ast.ValueTypeBool,
|
||||
Value: true,
|
||||
}
|
||||
}
|
||||
| FALSE
|
||||
{
|
||||
$$ = ast.LiteralNode{
|
||||
Type: ast.ValueTypeBool,
|
||||
Value: false,
|
||||
}
|
||||
}
|
||||
| NULL
|
||||
{
|
||||
$$ = ast.LiteralNode{
|
||||
Type: ast.ValueTypeNil,
|
||||
Value: nil,
|
||||
}
|
||||
}
|
||||
|
||||
array:
|
||||
LEFTBRACKET RIGHTBRACKET
|
||||
{
|
||||
$$ = ast.ListNode{}
|
||||
}
|
||||
| LEFTBRACKET elements RIGHTBRACKET
|
||||
{
|
||||
$$ = ast.ListNode{Elem: $2}
|
||||
}
|
||||
|
||||
elements:
|
||||
value
|
||||
{
|
||||
$$ = []ast.Node{$1}
|
||||
}
|
||||
| value COMMA elements
|
||||
{
|
||||
$$ = append($3, $1)
|
||||
}
|
||||
|
||||
%%
|
39
json/parse_test.go
Normal file
39
json/parse_test.go
Normal file
@ -0,0 +1,39 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
cases := []struct {
|
||||
Name string
|
||||
Err bool
|
||||
}{
|
||||
{
|
||||
"basic.json",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"object.json",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"array.json",
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
d, err := ioutil.ReadFile(filepath.Join(fixtureDir, tc.Name))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
_, err = Parse(string(d))
|
||||
if (err != nil) != tc.Err {
|
||||
t.Fatalf("Input: %s\n\nError: %s", tc.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
4
json/test-fixtures/array.json
Normal file
4
json/test-fixtures/array.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"foo": [1, 2, "bar"],
|
||||
"bar": "baz"
|
||||
}
|
3
json/test-fixtures/basic.json
Normal file
3
json/test-fixtures/basic.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"foo": "bar"
|
||||
}
|
5
json/test-fixtures/object.json
Normal file
5
json/test-fixtures/object.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"foo": {
|
||||
"bar": [1,2]
|
||||
}
|
||||
}
|
460
json/y.go
Normal file
460
json/y.go
Normal file
@ -0,0 +1,460 @@
|
||||
//line parse.y:3
|
||||
package json
|
||||
|
||||
import __yyfmt__ "fmt"
|
||||
|
||||
//line parse.y:5
|
||||
import (
|
||||
"github.com/hashicorp/hcl/ast"
|
||||
)
|
||||
|
||||
//line parse.y:12
|
||||
type jsonSymType struct {
|
||||
yys int
|
||||
array ast.ListNode
|
||||
assign ast.AssignmentNode
|
||||
item ast.Node
|
||||
list []ast.Node
|
||||
num int
|
||||
str string
|
||||
obj ast.ObjectNode
|
||||
}
|
||||
|
||||
const NUMBER = 57346
|
||||
const COLON = 57347
|
||||
const COMMA = 57348
|
||||
const IDENTIFIER = 57349
|
||||
const EQUAL = 57350
|
||||
const NEWLINE = 57351
|
||||
const STRING = 57352
|
||||
const LEFTBRACE = 57353
|
||||
const RIGHTBRACE = 57354
|
||||
const LEFTBRACKET = 57355
|
||||
const RIGHTBRACKET = 57356
|
||||
const TRUE = 57357
|
||||
const FALSE = 57358
|
||||
const NULL = 57359
|
||||
|
||||
var jsonToknames = []string{
|
||||
"NUMBER",
|
||||
"COLON",
|
||||
"COMMA",
|
||||
"IDENTIFIER",
|
||||
"EQUAL",
|
||||
"NEWLINE",
|
||||
"STRING",
|
||||
"LEFTBRACE",
|
||||
"RIGHTBRACE",
|
||||
"LEFTBRACKET",
|
||||
"RIGHTBRACKET",
|
||||
"TRUE",
|
||||
"FALSE",
|
||||
"NULL",
|
||||
}
|
||||
var jsonStatenames = []string{}
|
||||
|
||||
const jsonEofCode = 1
|
||||
const jsonErrCode = 2
|
||||
const jsonMaxDepth = 200
|
||||
|
||||
//line parse.y:136
|
||||
|
||||
//line yacctab:1
|
||||
var jsonExca = []int{
|
||||
-1, 1,
|
||||
1, -1,
|
||||
-2, 0,
|
||||
}
|
||||
|
||||
const jsonNprod = 18
|
||||
const jsonPrivate = 57344
|
||||
|
||||
var jsonTokenNames []string
|
||||
var jsonStates []string
|
||||
|
||||
const jsonLast = 35
|
||||
|
||||
var jsonAct = []int{
|
||||
|
||||
22, 14, 24, 7, 8, 5, 3, 13, 3, 14,
|
||||
20, 21, 17, 18, 19, 13, 3, 23, 20, 7,
|
||||
17, 18, 19, 4, 25, 9, 26, 10, 12, 15,
|
||||
2, 1, 6, 11, 16,
|
||||
}
|
||||
var jsonPact = []int{
|
||||
|
||||
-5, -1000, -1000, -7, -8, -1000, 19, 22, -1000, 9,
|
||||
5, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
|
||||
-3, -1000, -12, 18, -1000, 5, -1000,
|
||||
}
|
||||
var jsonPgo = []int{
|
||||
|
||||
0, 34, 32, 17, 0, 23, 29, 31,
|
||||
}
|
||||
var jsonR1 = []int{
|
||||
|
||||
0, 7, 6, 6, 5, 5, 2, 3, 3, 3,
|
||||
3, 3, 3, 3, 1, 1, 4, 4,
|
||||
}
|
||||
var jsonR2 = []int{
|
||||
|
||||
0, 1, 3, 2, 1, 3, 3, 1, 1, 1,
|
||||
1, 1, 1, 1, 2, 3, 1, 3,
|
||||
}
|
||||
var jsonChk = []int{
|
||||
|
||||
-1000, -7, -6, 11, -5, 12, -2, 10, 12, 6,
|
||||
5, -5, -3, 10, 4, -6, -1, 15, 16, 17,
|
||||
13, 14, -4, -3, 14, 6, -4,
|
||||
}
|
||||
var jsonDef = []int{
|
||||
|
||||
0, -2, 1, 0, 0, 3, 4, 0, 2, 0,
|
||||
0, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||
0, 14, 0, 16, 15, 0, 17,
|
||||
}
|
||||
var jsonTok1 = []int{
|
||||
|
||||
1,
|
||||
}
|
||||
var jsonTok2 = []int{
|
||||
|
||||
2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17,
|
||||
}
|
||||
var jsonTok3 = []int{
|
||||
0,
|
||||
}
|
||||
|
||||
//line yaccpar:1
|
||||
|
||||
/* parser for yacc output */
|
||||
|
||||
var jsonDebug = 0
|
||||
|
||||
type jsonLexer interface {
|
||||
Lex(lval *jsonSymType) int
|
||||
Error(s string)
|
||||
}
|
||||
|
||||
const jsonFlag = -1000
|
||||
|
||||
func jsonTokname(c int) string {
|
||||
// 4 is TOKSTART above
|
||||
if c >= 4 && c-4 < len(jsonToknames) {
|
||||
if jsonToknames[c-4] != "" {
|
||||
return jsonToknames[c-4]
|
||||
}
|
||||
}
|
||||
return __yyfmt__.Sprintf("tok-%v", c)
|
||||
}
|
||||
|
||||
func jsonStatname(s int) string {
|
||||
if s >= 0 && s < len(jsonStatenames) {
|
||||
if jsonStatenames[s] != "" {
|
||||
return jsonStatenames[s]
|
||||
}
|
||||
}
|
||||
return __yyfmt__.Sprintf("state-%v", s)
|
||||
}
|
||||
|
||||
func jsonlex1(lex jsonLexer, lval *jsonSymType) int {
|
||||
c := 0
|
||||
char := lex.Lex(lval)
|
||||
if char <= 0 {
|
||||
c = jsonTok1[0]
|
||||
goto out
|
||||
}
|
||||
if char < len(jsonTok1) {
|
||||
c = jsonTok1[char]
|
||||
goto out
|
||||
}
|
||||
if char >= jsonPrivate {
|
||||
if char < jsonPrivate+len(jsonTok2) {
|
||||
c = jsonTok2[char-jsonPrivate]
|
||||
goto out
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(jsonTok3); i += 2 {
|
||||
c = jsonTok3[i+0]
|
||||
if c == char {
|
||||
c = jsonTok3[i+1]
|
||||
goto out
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if c == 0 {
|
||||
c = jsonTok2[1] /* unknown char */
|
||||
}
|
||||
if jsonDebug >= 3 {
|
||||
__yyfmt__.Printf("lex %s(%d)\n", jsonTokname(c), uint(char))
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func jsonParse(jsonlex jsonLexer) int {
|
||||
var jsonn int
|
||||
var jsonlval jsonSymType
|
||||
var jsonVAL jsonSymType
|
||||
jsonS := make([]jsonSymType, jsonMaxDepth)
|
||||
|
||||
Nerrs := 0 /* number of errors */
|
||||
Errflag := 0 /* error recovery flag */
|
||||
jsonstate := 0
|
||||
jsonchar := -1
|
||||
jsonp := -1
|
||||
goto jsonstack
|
||||
|
||||
ret0:
|
||||
return 0
|
||||
|
||||
ret1:
|
||||
return 1
|
||||
|
||||
jsonstack:
|
||||
/* put a state and value onto the stack */
|
||||
if jsonDebug >= 4 {
|
||||
__yyfmt__.Printf("char %v in %v\n", jsonTokname(jsonchar), jsonStatname(jsonstate))
|
||||
}
|
||||
|
||||
jsonp++
|
||||
if jsonp >= len(jsonS) {
|
||||
nyys := make([]jsonSymType, len(jsonS)*2)
|
||||
copy(nyys, jsonS)
|
||||
jsonS = nyys
|
||||
}
|
||||
jsonS[jsonp] = jsonVAL
|
||||
jsonS[jsonp].yys = jsonstate
|
||||
|
||||
jsonnewstate:
|
||||
jsonn = jsonPact[jsonstate]
|
||||
if jsonn <= jsonFlag {
|
||||
goto jsondefault /* simple state */
|
||||
}
|
||||
if jsonchar < 0 {
|
||||
jsonchar = jsonlex1(jsonlex, &jsonlval)
|
||||
}
|
||||
jsonn += jsonchar
|
||||
if jsonn < 0 || jsonn >= jsonLast {
|
||||
goto jsondefault
|
||||
}
|
||||
jsonn = jsonAct[jsonn]
|
||||
if jsonChk[jsonn] == jsonchar { /* valid shift */
|
||||
jsonchar = -1
|
||||
jsonVAL = jsonlval
|
||||
jsonstate = jsonn
|
||||
if Errflag > 0 {
|
||||
Errflag--
|
||||
}
|
||||
goto jsonstack
|
||||
}
|
||||
|
||||
jsondefault:
|
||||
/* default state action */
|
||||
jsonn = jsonDef[jsonstate]
|
||||
if jsonn == -2 {
|
||||
if jsonchar < 0 {
|
||||
jsonchar = jsonlex1(jsonlex, &jsonlval)
|
||||
}
|
||||
|
||||
/* look through exception table */
|
||||
xi := 0
|
||||
for {
|
||||
if jsonExca[xi+0] == -1 && jsonExca[xi+1] == jsonstate {
|
||||
break
|
||||
}
|
||||
xi += 2
|
||||
}
|
||||
for xi += 2; ; xi += 2 {
|
||||
jsonn = jsonExca[xi+0]
|
||||
if jsonn < 0 || jsonn == jsonchar {
|
||||
break
|
||||
}
|
||||
}
|
||||
jsonn = jsonExca[xi+1]
|
||||
if jsonn < 0 {
|
||||
goto ret0
|
||||
}
|
||||
}
|
||||
if jsonn == 0 {
|
||||
/* error ... attempt to resume parsing */
|
||||
switch Errflag {
|
||||
case 0: /* brand new error */
|
||||
jsonlex.Error("syntax error")
|
||||
Nerrs++
|
||||
if jsonDebug >= 1 {
|
||||
__yyfmt__.Printf("%s", jsonStatname(jsonstate))
|
||||
__yyfmt__.Printf(" saw %s\n", jsonTokname(jsonchar))
|
||||
}
|
||||
fallthrough
|
||||
|
||||
case 1, 2: /* incompletely recovered error ... try again */
|
||||
Errflag = 3
|
||||
|
||||
/* find a state where "error" is a legal shift action */
|
||||
for jsonp >= 0 {
|
||||
jsonn = jsonPact[jsonS[jsonp].yys] + jsonErrCode
|
||||
if jsonn >= 0 && jsonn < jsonLast {
|
||||
jsonstate = jsonAct[jsonn] /* simulate a shift of "error" */
|
||||
if jsonChk[jsonstate] == jsonErrCode {
|
||||
goto jsonstack
|
||||
}
|
||||
}
|
||||
|
||||
/* the current p has no shift on "error", pop stack */
|
||||
if jsonDebug >= 2 {
|
||||
__yyfmt__.Printf("error recovery pops state %d\n", jsonS[jsonp].yys)
|
||||
}
|
||||
jsonp--
|
||||
}
|
||||
/* there is no state on the stack with an error shift ... abort */
|
||||
goto ret1
|
||||
|
||||
case 3: /* no shift yet; clobber input char */
|
||||
if jsonDebug >= 2 {
|
||||
__yyfmt__.Printf("error recovery discards %s\n", jsonTokname(jsonchar))
|
||||
}
|
||||
if jsonchar == jsonEofCode {
|
||||
goto ret1
|
||||
}
|
||||
jsonchar = -1
|
||||
goto jsonnewstate /* try again in the same state */
|
||||
}
|
||||
}
|
||||
|
||||
/* reduction by production jsonn */
|
||||
if jsonDebug >= 2 {
|
||||
__yyfmt__.Printf("reduce %v in:\n\t%v\n", jsonn, jsonStatname(jsonstate))
|
||||
}
|
||||
|
||||
jsonnt := jsonn
|
||||
jsonpt := jsonp
|
||||
_ = jsonpt // guard against "declared and not used"
|
||||
|
||||
jsonp -= jsonR2[jsonn]
|
||||
jsonVAL = jsonS[jsonp+1]
|
||||
|
||||
/* consult goto table to find next state */
|
||||
jsonn = jsonR1[jsonn]
|
||||
jsong := jsonPgo[jsonn]
|
||||
jsonj := jsong + jsonS[jsonp].yys + 1
|
||||
|
||||
if jsonj >= jsonLast {
|
||||
jsonstate = jsonAct[jsong]
|
||||
} else {
|
||||
jsonstate = jsonAct[jsonj]
|
||||
if jsonChk[jsonstate] != -jsonn {
|
||||
jsonstate = jsonAct[jsong]
|
||||
}
|
||||
}
|
||||
// dummy call; replaced with literal code
|
||||
switch jsonnt {
|
||||
|
||||
case 1:
|
||||
//line parse.y:37
|
||||
{
|
||||
obj := jsonS[jsonpt-0].obj
|
||||
jsonResult = &obj
|
||||
}
|
||||
case 2:
|
||||
//line parse.y:44
|
||||
{
|
||||
jsonVAL.obj = ast.ObjectNode{Elem: jsonS[jsonpt-1].list}
|
||||
}
|
||||
case 3:
|
||||
//line parse.y:48
|
||||
{
|
||||
jsonVAL.obj = ast.ObjectNode{}
|
||||
}
|
||||
case 4:
|
||||
//line parse.y:54
|
||||
{
|
||||
jsonVAL.list = []ast.Node{jsonS[jsonpt-0].assign}
|
||||
}
|
||||
case 5:
|
||||
//line parse.y:58
|
||||
{
|
||||
jsonVAL.list = append(jsonS[jsonpt-0].list, jsonS[jsonpt-2].assign)
|
||||
}
|
||||
case 6:
|
||||
//line parse.y:64
|
||||
{
|
||||
jsonVAL.assign = ast.AssignmentNode{
|
||||
Key: jsonS[jsonpt-2].str,
|
||||
Value: jsonS[jsonpt-0].item,
|
||||
}
|
||||
}
|
||||
case 7:
|
||||
//line parse.y:73
|
||||
{
|
||||
jsonVAL.item = ast.LiteralNode{
|
||||
Type: ast.ValueTypeString,
|
||||
Value: jsonS[jsonpt-0].str,
|
||||
}
|
||||
}
|
||||
case 8:
|
||||
//line parse.y:80
|
||||
{
|
||||
jsonVAL.item = ast.LiteralNode{
|
||||
Type: ast.ValueTypeInt,
|
||||
Value: jsonS[jsonpt-0].num,
|
||||
}
|
||||
}
|
||||
case 9:
|
||||
//line parse.y:87
|
||||
{
|
||||
jsonVAL.item = jsonS[jsonpt-0].obj
|
||||
}
|
||||
case 10:
|
||||
//line parse.y:91
|
||||
{
|
||||
jsonVAL.item = jsonS[jsonpt-0].array
|
||||
}
|
||||
case 11:
|
||||
//line parse.y:95
|
||||
{
|
||||
jsonVAL.item = ast.LiteralNode{
|
||||
Type: ast.ValueTypeBool,
|
||||
Value: true,
|
||||
}
|
||||
}
|
||||
case 12:
|
||||
//line parse.y:102
|
||||
{
|
||||
jsonVAL.item = ast.LiteralNode{
|
||||
Type: ast.ValueTypeBool,
|
||||
Value: false,
|
||||
}
|
||||
}
|
||||
case 13:
|
||||
//line parse.y:109
|
||||
{
|
||||
jsonVAL.item = ast.LiteralNode{
|
||||
Type: ast.ValueTypeNil,
|
||||
Value: nil,
|
||||
}
|
||||
}
|
||||
case 14:
|
||||
//line parse.y:118
|
||||
{
|
||||
jsonVAL.array = ast.ListNode{}
|
||||
}
|
||||
case 15:
|
||||
//line parse.y:122
|
||||
{
|
||||
jsonVAL.array = ast.ListNode{Elem: jsonS[jsonpt-1].list}
|
||||
}
|
||||
case 16:
|
||||
//line parse.y:128
|
||||
{
|
||||
jsonVAL.list = []ast.Node{jsonS[jsonpt-0].item}
|
||||
}
|
||||
case 17:
|
||||
//line parse.y:132
|
||||
{
|
||||
jsonVAL.list = append(jsonS[jsonpt-0].list, jsonS[jsonpt-2].item)
|
||||
}
|
||||
}
|
||||
goto jsonstack /* stack new state and value */
|
||||
}
|
5
parse.go
5
parse.go
@ -3,6 +3,7 @@ package hcl
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/hcl/ast"
|
||||
"github.com/hashicorp/terraform/helper/multierror"
|
||||
)
|
||||
|
||||
@ -10,10 +11,10 @@ import (
|
||||
// be accessed directly.
|
||||
var hclErrors []error
|
||||
var hclLock sync.Mutex
|
||||
var hclResult *ObjectNode
|
||||
var hclResult *ast.ObjectNode
|
||||
|
||||
// Parse parses the given string and returns the result.
|
||||
func Parse(v string) (*ObjectNode, error) {
|
||||
func Parse(v string) (*ast.ObjectNode, error) {
|
||||
hclLock.Lock()
|
||||
defer hclLock.Unlock()
|
||||
hclErrors = nil
|
||||
|
54
parse.y
54
parse.y
@ -3,14 +3,18 @@
|
||||
%{
|
||||
package hcl
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/ast"
|
||||
)
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
list []Node
|
||||
listitem Node
|
||||
num int
|
||||
obj ObjectNode
|
||||
str string
|
||||
list []ast.Node
|
||||
listitem ast.Node
|
||||
num int
|
||||
obj ast.ObjectNode
|
||||
str string
|
||||
}
|
||||
|
||||
%type <list> list objectlist
|
||||
@ -27,7 +31,7 @@ package hcl
|
||||
top:
|
||||
objectlist
|
||||
{
|
||||
hclResult = &ObjectNode{
|
||||
hclResult = &ast.ObjectNode{
|
||||
Key: "",
|
||||
Elem: $1,
|
||||
}
|
||||
@ -36,7 +40,7 @@ top:
|
||||
objectlist:
|
||||
objectitem
|
||||
{
|
||||
$$ = []Node{$1}
|
||||
$$ = []ast.Node{$1}
|
||||
}
|
||||
| objectitem objectlist
|
||||
{
|
||||
@ -46,46 +50,46 @@ objectlist:
|
||||
object:
|
||||
LEFTBRACE objectlist RIGHTBRACE
|
||||
{
|
||||
$$ = ObjectNode{Elem: $2}
|
||||
$$ = ast.ObjectNode{Elem: $2}
|
||||
}
|
||||
| LEFTBRACE RIGHTBRACE
|
||||
{
|
||||
$$ = ObjectNode{}
|
||||
$$ = ast.ObjectNode{}
|
||||
}
|
||||
|
||||
objectitem:
|
||||
IDENTIFIER EQUAL NUMBER
|
||||
{
|
||||
$$ = AssignmentNode{
|
||||
$$ = ast.AssignmentNode{
|
||||
Key: $1,
|
||||
Value: LiteralNode{
|
||||
Type: ValueTypeInt,
|
||||
Value: ast.LiteralNode{
|
||||
Type: ast.ValueTypeInt,
|
||||
Value: $3,
|
||||
},
|
||||
}
|
||||
}
|
||||
| IDENTIFIER EQUAL STRING
|
||||
{
|
||||
$$ = AssignmentNode{
|
||||
$$ = ast.AssignmentNode{
|
||||
Key: $1,
|
||||
Value: LiteralNode{
|
||||
Type: ValueTypeString,
|
||||
Value: ast.LiteralNode{
|
||||
Type: ast.ValueTypeString,
|
||||
Value: $3,
|
||||
},
|
||||
}
|
||||
}
|
||||
| IDENTIFIER EQUAL object
|
||||
{
|
||||
$$ = AssignmentNode{
|
||||
$$ = ast.AssignmentNode{
|
||||
Key: $1,
|
||||
Value: $3,
|
||||
}
|
||||
}
|
||||
| IDENTIFIER EQUAL LEFTBRACKET list RIGHTBRACKET
|
||||
{
|
||||
$$ = AssignmentNode{
|
||||
$$ = ast.AssignmentNode{
|
||||
Key: $1,
|
||||
Value: ListNode{Elem: $4},
|
||||
Value: ast.ListNode{Elem: $4},
|
||||
}
|
||||
}
|
||||
| block
|
||||
@ -101,9 +105,9 @@ block:
|
||||
}
|
||||
| blockId block
|
||||
{
|
||||
$$ = ObjectNode{
|
||||
$$ = ast.ObjectNode{
|
||||
Key: $1,
|
||||
Elem: []Node{$2},
|
||||
Elem: []ast.Node{$2},
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,7 +124,7 @@ blockId:
|
||||
list:
|
||||
listitem
|
||||
{
|
||||
$$ = []Node{$1}
|
||||
$$ = []ast.Node{$1}
|
||||
}
|
||||
| list COMMA listitem
|
||||
{
|
||||
@ -130,15 +134,15 @@ list:
|
||||
listitem:
|
||||
NUMBER
|
||||
{
|
||||
$$ = LiteralNode{
|
||||
Type: ValueTypeInt,
|
||||
$$ = ast.LiteralNode{
|
||||
Type: ast.ValueTypeInt,
|
||||
Value: $1,
|
||||
}
|
||||
}
|
||||
| STRING
|
||||
{
|
||||
$$ = LiteralNode{
|
||||
Type: ValueTypeString,
|
||||
$$ = ast.LiteralNode{
|
||||
Type: ast.ValueTypeString,
|
||||
Value: $1,
|
||||
}
|
||||
}
|
||||
|
467
y.go
Normal file
467
y.go
Normal file
@ -0,0 +1,467 @@
|
||||
//line parse.y:4
|
||||
package hcl
|
||||
|
||||
import __yyfmt__ "fmt"
|
||||
|
||||
//line parse.y:4
|
||||
import (
|
||||
"github.com/hashicorp/hcl/ast"
|
||||
)
|
||||
|
||||
//line parse.y:12
|
||||
type hclSymType struct {
|
||||
yys int
|
||||
list []ast.Node
|
||||
listitem ast.Node
|
||||
num int
|
||||
obj ast.ObjectNode
|
||||
str string
|
||||
}
|
||||
|
||||
const NUMBER = 57346
|
||||
const COMMA = 57347
|
||||
const IDENTIFIER = 57348
|
||||
const EQUAL = 57349
|
||||
const NEWLINE = 57350
|
||||
const STRING = 57351
|
||||
const LEFTBRACE = 57352
|
||||
const RIGHTBRACE = 57353
|
||||
const LEFTBRACKET = 57354
|
||||
const RIGHTBRACKET = 57355
|
||||
|
||||
var hclToknames = []string{
|
||||
"NUMBER",
|
||||
"COMMA",
|
||||
"IDENTIFIER",
|
||||
"EQUAL",
|
||||
"NEWLINE",
|
||||
"STRING",
|
||||
"LEFTBRACE",
|
||||
"RIGHTBRACE",
|
||||
"LEFTBRACKET",
|
||||
"RIGHTBRACKET",
|
||||
}
|
||||
var hclStatenames = []string{}
|
||||
|
||||
const hclEofCode = 1
|
||||
const hclErrCode = 2
|
||||
const hclMaxDepth = 200
|
||||
|
||||
//line parse.y:150
|
||||
|
||||
//line yacctab:1
|
||||
var hclExca = []int{
|
||||
-1, 1,
|
||||
1, -1,
|
||||
-2, 0,
|
||||
}
|
||||
|
||||
const hclNprod = 19
|
||||
const hclPrivate = 57344
|
||||
|
||||
var hclTokenNames []string
|
||||
var hclStates []string
|
||||
|
||||
const hclLast = 33
|
||||
|
||||
var hclAct = []int{
|
||||
|
||||
21, 14, 24, 26, 2, 1, 15, 12, 8, 17,
|
||||
4, 25, 10, 7, 9, 19, 13, 18, 22, 7,
|
||||
12, 4, 16, 23, 7, 5, 6, 27, 3, 20,
|
||||
0, 0, 11,
|
||||
}
|
||||
var hclPact = []int{
|
||||
|
||||
15, -1000, -1000, 15, 7, -1000, 10, -1000, -1000, -3,
|
||||
-1000, -1000, 4, -1000, -1000, -1000, -1000, 14, -9, -1000,
|
||||
-2, -1000, -1000, -1000, -1000, -1000, 14, -1000,
|
||||
}
|
||||
var hclPgo = []int{
|
||||
|
||||
0, 29, 4, 0, 28, 25, 12, 26, 5,
|
||||
}
|
||||
var hclR1 = []int{
|
||||
|
||||
0, 8, 2, 2, 6, 6, 4, 4, 4, 4,
|
||||
4, 5, 5, 7, 7, 1, 1, 3, 3,
|
||||
}
|
||||
var hclR2 = []int{
|
||||
|
||||
0, 1, 1, 2, 3, 2, 3, 3, 3, 5,
|
||||
1, 2, 2, 1, 1, 1, 3, 1, 1,
|
||||
}
|
||||
var hclChk = []int{
|
||||
|
||||
-1000, -8, -2, -4, 6, -5, -7, 9, -2, 7,
|
||||
-6, -5, 10, 6, 4, 9, -6, 12, -2, 11,
|
||||
-1, -3, 4, 9, 11, 13, 5, -3,
|
||||
}
|
||||
var hclDef = []int{
|
||||
|
||||
0, -2, 1, 2, 13, 10, 0, 14, 3, 0,
|
||||
11, 12, 0, 13, 6, 7, 8, 0, 0, 5,
|
||||
0, 15, 17, 18, 4, 9, 0, 16,
|
||||
}
|
||||
var hclTok1 = []int{
|
||||
|
||||
1,
|
||||
}
|
||||
var hclTok2 = []int{
|
||||
|
||||
2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13,
|
||||
}
|
||||
var hclTok3 = []int{
|
||||
0,
|
||||
}
|
||||
|
||||
//line yaccpar:1
|
||||
|
||||
/* parser for yacc output */
|
||||
|
||||
var hclDebug = 0
|
||||
|
||||
type hclLexer interface {
|
||||
Lex(lval *hclSymType) int
|
||||
Error(s string)
|
||||
}
|
||||
|
||||
const hclFlag = -1000
|
||||
|
||||
func hclTokname(c int) string {
|
||||
// 4 is TOKSTART above
|
||||
if c >= 4 && c-4 < len(hclToknames) {
|
||||
if hclToknames[c-4] != "" {
|
||||
return hclToknames[c-4]
|
||||
}
|
||||
}
|
||||
return __yyfmt__.Sprintf("tok-%v", c)
|
||||
}
|
||||
|
||||
func hclStatname(s int) string {
|
||||
if s >= 0 && s < len(hclStatenames) {
|
||||
if hclStatenames[s] != "" {
|
||||
return hclStatenames[s]
|
||||
}
|
||||
}
|
||||
return __yyfmt__.Sprintf("state-%v", s)
|
||||
}
|
||||
|
||||
func hcllex1(lex hclLexer, lval *hclSymType) int {
|
||||
c := 0
|
||||
char := lex.Lex(lval)
|
||||
if char <= 0 {
|
||||
c = hclTok1[0]
|
||||
goto out
|
||||
}
|
||||
if char < len(hclTok1) {
|
||||
c = hclTok1[char]
|
||||
goto out
|
||||
}
|
||||
if char >= hclPrivate {
|
||||
if char < hclPrivate+len(hclTok2) {
|
||||
c = hclTok2[char-hclPrivate]
|
||||
goto out
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(hclTok3); i += 2 {
|
||||
c = hclTok3[i+0]
|
||||
if c == char {
|
||||
c = hclTok3[i+1]
|
||||
goto out
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if c == 0 {
|
||||
c = hclTok2[1] /* unknown char */
|
||||
}
|
||||
if hclDebug >= 3 {
|
||||
__yyfmt__.Printf("lex %s(%d)\n", hclTokname(c), uint(char))
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func hclParse(hcllex hclLexer) int {
|
||||
var hcln int
|
||||
var hcllval hclSymType
|
||||
var hclVAL hclSymType
|
||||
hclS := make([]hclSymType, hclMaxDepth)
|
||||
|
||||
Nerrs := 0 /* number of errors */
|
||||
Errflag := 0 /* error recovery flag */
|
||||
hclstate := 0
|
||||
hclchar := -1
|
||||
hclp := -1
|
||||
goto hclstack
|
||||
|
||||
ret0:
|
||||
return 0
|
||||
|
||||
ret1:
|
||||
return 1
|
||||
|
||||
hclstack:
|
||||
/* put a state and value onto the stack */
|
||||
if hclDebug >= 4 {
|
||||
__yyfmt__.Printf("char %v in %v\n", hclTokname(hclchar), hclStatname(hclstate))
|
||||
}
|
||||
|
||||
hclp++
|
||||
if hclp >= len(hclS) {
|
||||
nyys := make([]hclSymType, len(hclS)*2)
|
||||
copy(nyys, hclS)
|
||||
hclS = nyys
|
||||
}
|
||||
hclS[hclp] = hclVAL
|
||||
hclS[hclp].yys = hclstate
|
||||
|
||||
hclnewstate:
|
||||
hcln = hclPact[hclstate]
|
||||
if hcln <= hclFlag {
|
||||
goto hcldefault /* simple state */
|
||||
}
|
||||
if hclchar < 0 {
|
||||
hclchar = hcllex1(hcllex, &hcllval)
|
||||
}
|
||||
hcln += hclchar
|
||||
if hcln < 0 || hcln >= hclLast {
|
||||
goto hcldefault
|
||||
}
|
||||
hcln = hclAct[hcln]
|
||||
if hclChk[hcln] == hclchar { /* valid shift */
|
||||
hclchar = -1
|
||||
hclVAL = hcllval
|
||||
hclstate = hcln
|
||||
if Errflag > 0 {
|
||||
Errflag--
|
||||
}
|
||||
goto hclstack
|
||||
}
|
||||
|
||||
hcldefault:
|
||||
/* default state action */
|
||||
hcln = hclDef[hclstate]
|
||||
if hcln == -2 {
|
||||
if hclchar < 0 {
|
||||
hclchar = hcllex1(hcllex, &hcllval)
|
||||
}
|
||||
|
||||
/* look through exception table */
|
||||
xi := 0
|
||||
for {
|
||||
if hclExca[xi+0] == -1 && hclExca[xi+1] == hclstate {
|
||||
break
|
||||
}
|
||||
xi += 2
|
||||
}
|
||||
for xi += 2; ; xi += 2 {
|
||||
hcln = hclExca[xi+0]
|
||||
if hcln < 0 || hcln == hclchar {
|
||||
break
|
||||
}
|
||||
}
|
||||
hcln = hclExca[xi+1]
|
||||
if hcln < 0 {
|
||||
goto ret0
|
||||
}
|
||||
}
|
||||
if hcln == 0 {
|
||||
/* error ... attempt to resume parsing */
|
||||
switch Errflag {
|
||||
case 0: /* brand new error */
|
||||
hcllex.Error("syntax error")
|
||||
Nerrs++
|
||||
if hclDebug >= 1 {
|
||||
__yyfmt__.Printf("%s", hclStatname(hclstate))
|
||||
__yyfmt__.Printf(" saw %s\n", hclTokname(hclchar))
|
||||
}
|
||||
fallthrough
|
||||
|
||||
case 1, 2: /* incompletely recovered error ... try again */
|
||||
Errflag = 3
|
||||
|
||||
/* find a state where "error" is a legal shift action */
|
||||
for hclp >= 0 {
|
||||
hcln = hclPact[hclS[hclp].yys] + hclErrCode
|
||||
if hcln >= 0 && hcln < hclLast {
|
||||
hclstate = hclAct[hcln] /* simulate a shift of "error" */
|
||||
if hclChk[hclstate] == hclErrCode {
|
||||
goto hclstack
|
||||
}
|
||||
}
|
||||
|
||||
/* the current p has no shift on "error", pop stack */
|
||||
if hclDebug >= 2 {
|
||||
__yyfmt__.Printf("error recovery pops state %d\n", hclS[hclp].yys)
|
||||
}
|
||||
hclp--
|
||||
}
|
||||
/* there is no state on the stack with an error shift ... abort */
|
||||
goto ret1
|
||||
|
||||
case 3: /* no shift yet; clobber input char */
|
||||
if hclDebug >= 2 {
|
||||
__yyfmt__.Printf("error recovery discards %s\n", hclTokname(hclchar))
|
||||
}
|
||||
if hclchar == hclEofCode {
|
||||
goto ret1
|
||||
}
|
||||
hclchar = -1
|
||||
goto hclnewstate /* try again in the same state */
|
||||
}
|
||||
}
|
||||
|
||||
/* reduction by production hcln */
|
||||
if hclDebug >= 2 {
|
||||
__yyfmt__.Printf("reduce %v in:\n\t%v\n", hcln, hclStatname(hclstate))
|
||||
}
|
||||
|
||||
hclnt := hcln
|
||||
hclpt := hclp
|
||||
_ = hclpt // guard against "declared and not used"
|
||||
|
||||
hclp -= hclR2[hcln]
|
||||
hclVAL = hclS[hclp+1]
|
||||
|
||||
/* consult goto table to find next state */
|
||||
hcln = hclR1[hcln]
|
||||
hclg := hclPgo[hcln]
|
||||
hclj := hclg + hclS[hclp].yys + 1
|
||||
|
||||
if hclj >= hclLast {
|
||||
hclstate = hclAct[hclg]
|
||||
} else {
|
||||
hclstate = hclAct[hclj]
|
||||
if hclChk[hclstate] != -hcln {
|
||||
hclstate = hclAct[hclg]
|
||||
}
|
||||
}
|
||||
// dummy call; replaced with literal code
|
||||
switch hclnt {
|
||||
|
||||
case 1:
|
||||
//line parse.y:33
|
||||
{
|
||||
hclResult = &ast.ObjectNode{
|
||||
Key: "",
|
||||
Elem: hclS[hclpt-0].list,
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
//line parse.y:42
|
||||
{
|
||||
hclVAL.list = []ast.Node{hclS[hclpt-0].listitem}
|
||||
}
|
||||
case 3:
|
||||
//line parse.y:46
|
||||
{
|
||||
hclVAL.list = append(hclS[hclpt-0].list, hclS[hclpt-1].listitem)
|
||||
}
|
||||
case 4:
|
||||
//line parse.y:52
|
||||
{
|
||||
hclVAL.obj = ast.ObjectNode{Elem: hclS[hclpt-1].list}
|
||||
}
|
||||
case 5:
|
||||
//line parse.y:56
|
||||
{
|
||||
hclVAL.obj = ast.ObjectNode{}
|
||||
}
|
||||
case 6:
|
||||
//line parse.y:62
|
||||
{
|
||||
hclVAL.listitem = ast.AssignmentNode{
|
||||
Key: hclS[hclpt-2].str,
|
||||
Value: ast.LiteralNode{
|
||||
Type: ast.ValueTypeInt,
|
||||
Value: hclS[hclpt-0].num,
|
||||
},
|
||||
}
|
||||
}
|
||||
case 7:
|
||||
//line parse.y:72
|
||||
{
|
||||
hclVAL.listitem = ast.AssignmentNode{
|
||||
Key: hclS[hclpt-2].str,
|
||||
Value: ast.LiteralNode{
|
||||
Type: ast.ValueTypeString,
|
||||
Value: hclS[hclpt-0].str,
|
||||
},
|
||||
}
|
||||
}
|
||||
case 8:
|
||||
//line parse.y:82
|
||||
{
|
||||
hclVAL.listitem = ast.AssignmentNode{
|
||||
Key: hclS[hclpt-2].str,
|
||||
Value: hclS[hclpt-0].obj,
|
||||
}
|
||||
}
|
||||
case 9:
|
||||
//line parse.y:89
|
||||
{
|
||||
hclVAL.listitem = ast.AssignmentNode{
|
||||
Key: hclS[hclpt-4].str,
|
||||
Value: ast.ListNode{Elem: hclS[hclpt-1].list},
|
||||
}
|
||||
}
|
||||
case 10:
|
||||
//line parse.y:96
|
||||
{
|
||||
hclVAL.listitem = hclS[hclpt-0].obj
|
||||
}
|
||||
case 11:
|
||||
//line parse.y:102
|
||||
{
|
||||
hclVAL.obj = hclS[hclpt-0].obj
|
||||
hclVAL.obj.Key = hclS[hclpt-1].str
|
||||
}
|
||||
case 12:
|
||||
//line parse.y:107
|
||||
{
|
||||
hclVAL.obj = ast.ObjectNode{
|
||||
Key: hclS[hclpt-1].str,
|
||||
Elem: []ast.Node{hclS[hclpt-0].obj},
|
||||
}
|
||||
}
|
||||
case 13:
|
||||
//line parse.y:116
|
||||
{
|
||||
hclVAL.str = hclS[hclpt-0].str
|
||||
}
|
||||
case 14:
|
||||
//line parse.y:120
|
||||
{
|
||||
hclVAL.str = hclS[hclpt-0].str
|
||||
}
|
||||
case 15:
|
||||
//line parse.y:126
|
||||
{
|
||||
hclVAL.list = []ast.Node{hclS[hclpt-0].listitem}
|
||||
}
|
||||
case 16:
|
||||
//line parse.y:130
|
||||
{
|
||||
hclVAL.list = append(hclS[hclpt-2].list, hclS[hclpt-0].listitem)
|
||||
}
|
||||
case 17:
|
||||
//line parse.y:136
|
||||
{
|
||||
hclVAL.listitem = ast.LiteralNode{
|
||||
Type: ast.ValueTypeInt,
|
||||
Value: hclS[hclpt-0].num,
|
||||
}
|
||||
}
|
||||
case 18:
|
||||
//line parse.y:143
|
||||
{
|
||||
hclVAL.listitem = ast.LiteralNode{
|
||||
Type: ast.ValueTypeString,
|
||||
Value: hclS[hclpt-0].str,
|
||||
}
|
||||
}
|
||||
}
|
||||
goto hclstack /* stack new state and value */
|
||||
}
|
Loading…
Reference in New Issue
Block a user