aboutsummaryrefslogblamecommitdiff
path: root/parser.go
blob: e902fc3460187bc0192e233ff76a149a46c9802e (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

















                                                                                           
                                                       



                                                  
                                           

                                       
                                                                 





                                                           
                                                       



                                                  
                                           

                                       
                                          


                                                       
                                                        



                                                  
                                           

                                        
                                        













                                                       
                                                     



                                                  
                                           







                                                                                              
                                               



                                          
                                   















                                                             
                                             





                                                                                
                                              



                                          
                                   















                                                             
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.Produce(StringType)
		if err != nil {
			return nil, err
		}
		if c, ok := c.(AcceptParent); ok {
			c.SetParent(parent)
		}
		child := c.(StringNode)
		j.Factory.Fill(child, 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.Produce(NumberType)
		if err != nil {
			return nil, err
		}
		if c, ok := c.(AcceptParent); ok {
			c.SetParent(parent)
		}
		child := c.(NumberNode)
		j.Factory.Fill(child, num)
		return child, nil
	case lexer.LBoolean:
		b := strings.ToLower(l.Value) == "true"
		c, err := j.Factory.Produce(BooleanType)
		if err != nil {
			return nil, err
		}
		if c, ok := c.(AcceptParent); ok {
			c.SetParent(parent)
		}
		child := c.(BooleanNode)
		j.Factory.Fill(child, 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.Produce(NullType)
		if err != nil {
			return nil, err
		}
		if c, ok := c.(AcceptParent); ok {
			c.SetParent(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.Produce(ObjectType)
	if err != nil {
		return nil, err
	}
	if c, ok := c.(AcceptParent); ok {
		c.SetParent(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.Set(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.Produce(ArrayType)
	if err != nil {
		return nil, err
	}
	if c, ok := c.(AcceptParent); ok {
		c.SetParent(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")
}