parser: implement node interface methods

This commit is contained in:
Fatih Arslan 2015-10-12 00:20:17 +03:00
parent 77c7bc18c5
commit 82c5032a95
4 changed files with 123 additions and 30 deletions

View File

@ -14,39 +14,88 @@ const (
Object
)
// Node is an element in the parse tree.
// Node is an element in the abstract syntax tree.
type Node interface {
node()
String() string
Type() NodeType
Pos() scanner.Pos
End() scanner.Pos
}
func (IdentStatement) node() {}
func (BlockStatement) node() {}
func (AssignStatement) node() {}
func (ListStatement) node() {}
func (ObjectStatement) node() {}
// IdentStatement represents an identifier.
type IdentStatement struct {
Token scanner.Token
Pos scanner.Pos // position of the literal
Value string
pos scanner.Pos // position of the literal
token scanner.Token
value string
}
func (i IdentStatement) String() string {
return i.value
}
func (i IdentStatement) Pos() scanner.Pos {
return i.pos
}
type BlockStatement struct {
Lbrace scanner.Pos // position of "{"
Rbrace scanner.Pos // position of "}"
List []Node // the nodes in lexical order
lbrace scanner.Pos // position of "{"
rbrace scanner.Pos // position of "}"
list []Node // the nodes in lexical order
}
func (b BlockStatement) String() string {
s := "{\n"
for _, n := range b.list {
s += n.String() + "\n"
}
s += "}"
return s
}
func (b BlockStatement) Pos() scanner.Pos {
return b.lbrace
}
// AssignStatement represents an assignment
type AssignStatement struct {
Lhs Node // left hand side of the assignment
Rhs Node // right hand side of the assignment
Assign scanner.Pos // position of "="
lhs Node // left hand side of the assignment
rhs Node // right hand side of the assignment
assign scanner.Pos // position of "="
}
func (a AssignStatement) String() string {
return a.lhs.String() + " = " + a.rhs.String()
}
func (a AssignStatement) Pos() scanner.Pos {
return a.lhs.Pos()
}
// ListStatement represents a list
type ListStatement struct {
Lbrack scanner.Pos // position of "["
Rbrack scanner.Pos // position of "]"
List []Node // the elements in lexical order
lbrack scanner.Pos // position of "["
rbrack scanner.Pos // position of "]"
list []Node // the elements in lexical order
}
func (l ListStatement) String() string {
s := "[\n"
for _, n := range l.list {
s += n.String() + ",\n"
}
s += "]"
return s
}
func (l ListStatement) Pos() scanner.Pos {
return l.lbrack
}
// ObjectStatment represents an object
@ -54,3 +103,21 @@ type ObjectStatement struct {
Idents []Node // the idents in elements in lexical order
BlockStatement
}
func (o ObjectStatement) String() string {
s := ""
for i, n := range o.Idents {
s += n.String()
if i != len(o.Idents) {
s += " "
}
}
s += o.BlockStatement.String()
return s
}
func (o ObjectStatement) Pos() scanner.Pos {
return o.Idents[0].Pos()
}

View File

@ -3,14 +3,46 @@ package parser
import "github.com/fatih/hcl/scanner"
type Parser struct {
sc *scanner.Scanner
sc *scanner.Scanner
buf struct {
tok scanner.Token // last read token
n int // buffer size (max = 1)
}
}
func NewParser(src []byte) *Parser {
return &Parser{
sc: scanner.NewScanner(src),
sc: scanner.New(src),
}
}
func (p *Parser) Parse() {
func (p *Parser) Parse() Node {
tok := p.scan()
switch tok.Type() {
case scanner.IDENT:
// p.parseStatement()
case scanner.EOF:
}
return nil
}
// scan returns the next token from the underlying scanner.
// If a token has been unscanned then read that instead.
func (p *Parser) scan() scanner.Token {
// If we have a token on the buffer, then return it.
if p.buf.n != 0 {
p.buf.n = 0
return p.buf.tok
}
// Otherwise read the next token from the scanner and Save it to the buffer
// in case we unscan later.
p.buf.tok = p.sc.Scan()
return p.buf.tok
}
// unscan pushes the previously read token back onto the buffer.
func (p *Parser) unread() { p.buf.n = 1 }

View File

@ -42,15 +42,9 @@ type Scanner struct {
tokPos Pos
}
// NewScannerstring creates and initializes a new instance of Scanner using
// string src as its source content.
func NewScannerString(src string) *Scanner {
return NewScanner([]byte(src))
}
// NewScanner creates and initializes a new instance of Scanner using src as
// New creates and initializes a new instance of Scanner using src as
// its source content.
func NewScanner(src []byte) *Scanner {
func New(src []byte) *Scanner {
// even though we accept a src, we read from a io.Reader compatible type
// (*bytes.Buffer). So in the future we might easily change it to streaming
// read.

View File

@ -182,7 +182,7 @@ func TestPosition(t *testing.T) {
}
}
s := NewScanner(buf.Bytes())
s := New(buf.Bytes())
pos := Pos{"", 4, 1, 5}
s.Scan()
@ -329,7 +329,7 @@ func TestRealExample(t *testing.T) {
{EOF, ``},
}
s := NewScanner([]byte(complexHCL))
s := New([]byte(complexHCL))
for _, l := range literals {
tok := s.Scan()
if l.token != tok.Type() {
@ -366,7 +366,7 @@ func TestError(t *testing.T) {
}
func testError(t *testing.T, src, pos, msg string, tok TokenType) {
s := NewScanner([]byte(src))
s := New([]byte(src))
errorCalled := false
s.Error = func(p Pos, m string) {
@ -401,7 +401,7 @@ func testTokenList(t *testing.T, tokenList []tokenPair) {
fmt.Fprintf(buf, "%s\n", ident.text)
}
s := NewScanner(buf.Bytes())
s := New(buf.Bytes())
for _, ident := range tokenList {
tok := s.Scan()
if tok.Type() != ident.tok {