aboutsummaryrefslogtreecommitdiff
path: root/parser.go
diff options
context:
space:
mode:
Diffstat (limited to 'parser.go')
-rw-r--r--parser.go133
1 files changed, 133 insertions, 0 deletions
diff --git a/parser.go b/parser.go
new file mode 100644
index 0000000..a82960b
--- /dev/null
+++ b/parser.go
@@ -0,0 +1,133 @@
+package json
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+
+ "go.neonxp.dev/json/internal/lexer"
+)
+
+func (j *JSON) parse(ch chan lexer.Lexem) (Node, error) {
+ prefix := <-ch
+ return j.createChild(nil, prefix, ch)
+}
+
+func (j *JSON) createChild(parent Node, l lexer.Lexem, ch chan lexer.Lexem) (Node, error) {
+ switch l.Type {
+ case lexer.LString:
+ c, err := j.Factory(StringType)
+ if err != nil {
+ return nil, err
+ }
+ if c, ok := c.(AcceptParent); ok {
+ c.Parent(parent)
+ }
+ child := c.(StringNode)
+ child.SetString(strings.Trim(l.Value, `"`))
+ return child, nil
+ case lexer.LNumber:
+ num, err := strconv.ParseFloat(l.Value, 64)
+ if err != nil {
+ return nil, err
+ }
+ c, err := j.Factory(NumberType)
+ if err != nil {
+ return nil, err
+ }
+ if c, ok := c.(AcceptParent); ok {
+ c.Parent(parent)
+ }
+ child := c.(NumberNode)
+ child.SetNumber(num)
+ return child, nil
+ case lexer.LBoolean:
+ b := strings.ToLower(l.Value) == "true"
+ c, err := j.Factory(BooleanType)
+ if err != nil {
+ return nil, err
+ }
+ if c, ok := c.(AcceptParent); ok {
+ c.Parent(parent)
+ }
+ child := c.(BooleanNode)
+ child.SetBool(b)
+ return child, nil
+ case lexer.LObjectStart:
+ child, err := j.parseObject(parent, ch)
+ if err != nil {
+ return nil, err
+ }
+ return child, nil
+ case lexer.LArrayStart:
+ child, err := j.parseArray(parent, ch)
+ if err != nil {
+ return nil, err
+ }
+ return child, nil
+ case lexer.LNull:
+ c, err := j.Factory(NullType)
+ if err != nil {
+ return nil, err
+ }
+ if c, ok := c.(AcceptParent); ok {
+ c.Parent(parent)
+ }
+ return c.(NullNode), nil
+ default:
+ return nil, fmt.Errorf("ivalid token: '%s' type=%s", l.Value, l.Type.String())
+ }
+}
+
+func (j *JSON) parseObject(parent Node, ch chan lexer.Lexem) (ObjectNode, error) {
+ c, err := j.Factory(ObjectType)
+ if err != nil {
+ return nil, err
+ }
+ if c, ok := c.(AcceptParent); ok {
+ c.Parent(parent)
+ }
+ n := c.(ObjectNode)
+ nextKey := ""
+ for l := range ch {
+ switch l.Type {
+ case lexer.LObjectKey:
+ nextKey = strings.Trim(l.Value, `"`)
+ case lexer.LObjectEnd:
+ return n, nil
+ case lexer.LObjectValue:
+ continue
+ default:
+ child, err := j.createChild(n, l, ch)
+ if err != nil {
+ return nil, err
+ }
+ n.SetKeyValue(nextKey, child)
+ }
+ }
+ return nil, fmt.Errorf("unexpected end of object")
+}
+
+func (j *JSON) parseArray(parent Node, ch chan lexer.Lexem) (ArrayNode, error) {
+ c, err := j.Factory(ArrayType)
+ if err != nil {
+ return nil, err
+ }
+ if c, ok := c.(AcceptParent); ok {
+ c.Parent(parent)
+ }
+ n := c.(ArrayNode)
+ for l := range ch {
+ switch l.Type {
+ case lexer.LArrayEnd:
+ return n, nil
+ default:
+ child, err := j.createChild(n, l, ch)
+ if err != nil {
+ return nil, err
+ }
+ n.Append(child)
+ }
+ }
+ return nil, fmt.Errorf("unexpected end of object")
+}