|
|
@ -24,12 +24,14 @@ const ( |
|
|
|
|
|
|
|
type Node struct { |
|
|
|
Type string // One of List, Ident, Int, Float, Rune, String
|
|
|
|
Ident string // If type is Ident.
|
|
|
|
Bool bool // If Type is Bool.
|
|
|
|
List []Node // If Type is List.
|
|
|
|
Int int64 // If Type is Int.
|
|
|
|
Float float64 // If Type is Float.
|
|
|
|
Rune rune // If Type is Rune.
|
|
|
|
String string // If Type is Ident or String.
|
|
|
|
String string // If Type is String.
|
|
|
|
List []Node // If Type is List.
|
|
|
|
Paren rune // If Type is List. One of '(', '[', '{'.
|
|
|
|
} |
|
|
|
|
|
|
|
// Parse takes an input string and returns a tree rooted on a given token.
|
|
|
@ -62,24 +64,24 @@ func Parse(input string) (Node, error) { |
|
|
|
"Expected top-level list, but got `%s.`", |
|
|
|
s.TokenText()) |
|
|
|
} |
|
|
|
return parseList(s) |
|
|
|
return parseList(s, '(') |
|
|
|
} |
|
|
|
|
|
|
|
func parseNode(s *scanner.Scanner) (Node, error) { |
|
|
|
func parseNode(s *scanner.Scanner, closeParen rune) (Node, error) { |
|
|
|
ch := s.Scan() |
|
|
|
switch ch { |
|
|
|
case scanner.Ident: |
|
|
|
text := s.TokenText() |
|
|
|
if text == "true" || text == "false" { |
|
|
|
return Node{ |
|
|
|
Type: Ident, |
|
|
|
Type: Bool, |
|
|
|
Bool: text == "true", |
|
|
|
}, nil |
|
|
|
} |
|
|
|
|
|
|
|
return Node{ |
|
|
|
Type: Ident, |
|
|
|
String: s.TokenText(), |
|
|
|
Type: Ident, |
|
|
|
Ident: s.TokenText(), |
|
|
|
}, nil |
|
|
|
|
|
|
|
case scanner.Int: |
|
|
@ -109,10 +111,10 @@ func parseNode(s *scanner.Scanner) (Node, error) { |
|
|
|
String: val[1 : len(val)-1], |
|
|
|
}, nil |
|
|
|
|
|
|
|
case '(': |
|
|
|
return parseList(s) |
|
|
|
case '(', '[', '{': |
|
|
|
return parseList(s, ch) |
|
|
|
|
|
|
|
case ')': |
|
|
|
case closeParen: |
|
|
|
return Node{}, errCloseParen |
|
|
|
|
|
|
|
case scanner.EOF: |
|
|
@ -123,18 +125,21 @@ func parseNode(s *scanner.Scanner) (Node, error) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func parseList(s *scanner.Scanner) (Node, error) { |
|
|
|
func parseList(s *scanner.Scanner, paren rune) (Node, error) { |
|
|
|
closeParen := map[rune]rune{'(': ')', '[': ']', '{': '}'}[paren] |
|
|
|
|
|
|
|
nodes := []Node{} |
|
|
|
for { |
|
|
|
n, err := parseNode(s) |
|
|
|
n, err := parseNode(s, closeParen) |
|
|
|
switch err { |
|
|
|
case nil: |
|
|
|
nodes = append(nodes, n) |
|
|
|
|
|
|
|
case errCloseParen: |
|
|
|
return Node{ |
|
|
|
Type: List, |
|
|
|
List: nodes, |
|
|
|
Type: List, |
|
|
|
List: nodes, |
|
|
|
Paren: paren, |
|
|
|
}, nil |
|
|
|
|
|
|
|
case io.EOF: |
|
|
|