Remove context operations from parser
This commit is contained in:
parent
937c8b31d7
commit
6037100d4b
161
parser/parser.go
161
parser/parser.go
|
@ -9,71 +9,68 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
ContextType int
|
// Holds the state of parser
|
||||||
Context struct {
|
|
||||||
Type ContextType
|
|
||||||
Key string
|
|
||||||
}
|
|
||||||
Parser struct {
|
Parser struct {
|
||||||
exps []Context
|
|
||||||
context []Context
|
|
||||||
lex *lexer.Lexer
|
lex *lexer.Lexer
|
||||||
|
ctx *context
|
||||||
|
sels map[string]*context
|
||||||
|
res map[string][]lexer.Item
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
// Creates a new parser
|
||||||
Unknown ContextType = iota
|
func New(b []byte, sels []string) *Parser {
|
||||||
Object
|
return &Parser{
|
||||||
Array
|
|
||||||
)
|
|
||||||
|
|
||||||
func New(b []byte, sel string) *Parser {
|
|
||||||
p := &Parser{
|
|
||||||
exps: parseSelector(sel),
|
|
||||||
context: []Context{},
|
|
||||||
lex: lexer.New(string(b)),
|
lex: lexer.New(string(b)),
|
||||||
|
ctx: &context{
|
||||||
|
exps: []expectation{},
|
||||||
|
},
|
||||||
|
sels: parseSelectors(sels),
|
||||||
|
res: map[string][]lexer.Item{},
|
||||||
}
|
}
|
||||||
|
|
||||||
return p
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) Parse() {
|
// Starts parsing
|
||||||
|
func (p *Parser) Parse() map[string][]interface{} {
|
||||||
go p.lex.Run()
|
go p.lex.Run()
|
||||||
p.parseValue(p.next())
|
p.parseValue(p.next())
|
||||||
|
|
||||||
|
out := map[string][]interface{}{}
|
||||||
|
for sel, res := range p.res {
|
||||||
|
for _, item := range res {
|
||||||
|
if val, err := castValue(item); err == nil {
|
||||||
|
out[sel] = append(out[sel], val)
|
||||||
|
} else {
|
||||||
|
out[sel] = append(out[sel], err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) parseValue(item lexer.Item) {
|
func (p *Parser) parseValue(item lexer.Item) {
|
||||||
if item.Token == lexer.BraceOpen {
|
|
||||||
p.enterContext(Object)
|
|
||||||
p.parseObject()
|
|
||||||
p.leaveContext()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if item.Token == lexer.BracketOpen {
|
|
||||||
p.enterContext(Array)
|
|
||||||
p.parseArray(0)
|
|
||||||
p.leaveContext()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
isMatch := p.checkContext()
|
|
||||||
switch item.Token {
|
switch item.Token {
|
||||||
case lexer.Null, lexer.Bool, lexer.Number, lexer.String:
|
case lexer.Null, lexer.Bool, lexer.Number, lexer.String:
|
||||||
if isMatch {
|
p.pushValue(item)
|
||||||
fmt.Printf("\n\nFOUND MATCH!\nVALUE: %s\n\n", item.String())
|
case lexer.BraceOpen:
|
||||||
panic("Match found")
|
p.ctx.push(object)
|
||||||
}
|
p.parseObject()
|
||||||
|
p.ctx.pop()
|
||||||
|
case lexer.BracketOpen:
|
||||||
|
p.ctx.push(array)
|
||||||
|
p.parseArray(0)
|
||||||
|
p.ctx.pop()
|
||||||
default:
|
default:
|
||||||
if isMatch {
|
|
||||||
panic("Cannot print your match, sorry :(")
|
|
||||||
} else {
|
|
||||||
unexpected(item)
|
unexpected(item)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) parseArray(i int) {
|
// Parses array recursively part by part
|
||||||
p.context[len(p.context)-1].Key = strconv.Itoa(i)
|
// Is called after '[' and ',' tokens
|
||||||
|
// Expects a value followed by ']' or ',' tokens
|
||||||
|
func (p *Parser) parseArray(i int64) {
|
||||||
|
p.ctx.setIndex(i)
|
||||||
item := p.next()
|
item := p.next()
|
||||||
if item.Token == lexer.BracketClose {
|
if item.Token == lexer.BracketClose {
|
||||||
return
|
return
|
||||||
|
@ -95,7 +92,7 @@ func (p *Parser) parseObject() {
|
||||||
case lexer.BraceClose:
|
case lexer.BraceClose:
|
||||||
return
|
return
|
||||||
case lexer.String:
|
case lexer.String:
|
||||||
p.context[len(p.context)-1].Key = item.Val
|
p.ctx.setKey(item.Val)
|
||||||
default:
|
default:
|
||||||
unexpected(item)
|
unexpected(item)
|
||||||
}
|
}
|
||||||
|
@ -116,24 +113,13 @@ func (p *Parser) parseObject() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) checkContext() bool {
|
func (p *Parser) pushValue(item lexer.Item) {
|
||||||
depth := len(p.context)
|
for sel, exp := range p.sels {
|
||||||
if depth != len(p.exps) {
|
if ok := exp.compare(p.ctx); ok {
|
||||||
return false
|
p.res[sel] = append(p.res[sel], item)
|
||||||
}
|
return
|
||||||
|
|
||||||
fmt.Println("Checking...")
|
|
||||||
fmt.Println(p.exps)
|
|
||||||
fmt.Println(p.context)
|
|
||||||
|
|
||||||
for i, exp := range p.exps {
|
|
||||||
ctx := p.context[i]
|
|
||||||
if exp.Type != ctx.Type || exp.Key != ctx.Key {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) next() lexer.Item {
|
func (p *Parser) next() lexer.Item {
|
||||||
|
@ -145,45 +131,24 @@ func (p *Parser) next() lexer.Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) enterContext(typ ContextType) {
|
func castValue(item lexer.Item) (val interface{}, err error) {
|
||||||
p.context = append(p.context, Context{
|
switch item.Token {
|
||||||
Type: typ,
|
case lexer.Null:
|
||||||
})
|
val = nil
|
||||||
}
|
case lexer.Bool:
|
||||||
|
val = (item.Val == "true")
|
||||||
func (p *Parser) leaveContext() {
|
case lexer.String:
|
||||||
p.context = p.context[:len(p.context)-1]
|
val = item.Val
|
||||||
|
case lexer.Number:
|
||||||
|
if strings.Index(item.Val, ".") > -1 {
|
||||||
|
val, err = strconv.ParseFloat(item.Val, 64)
|
||||||
|
} else {
|
||||||
|
val, err = strconv.ParseInt(item.Val, 10, 64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func unexpected(item lexer.Item) {
|
func unexpected(item lexer.Item) {
|
||||||
panic(fmt.Errorf("Unexpected token: %s", item.String()))
|
panic(fmt.Errorf("Unexpected token: %s", item.String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseSelector(sel string) []Context {
|
|
||||||
exps := []Context{}
|
|
||||||
parts := strings.Split(sel[1:], "/")
|
|
||||||
for _, part := range parts {
|
|
||||||
typ := Object
|
|
||||||
if len(part) > 2 && part[:1] == "[" && part[len(part)-1:] == "]" {
|
|
||||||
part = part[1 : len(part)-1]
|
|
||||||
typ = Array
|
|
||||||
}
|
|
||||||
exps = append(exps, Context{
|
|
||||||
Type: typ,
|
|
||||||
Key: part,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return exps
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e ContextType) String() string {
|
|
||||||
switch e {
|
|
||||||
case Array:
|
|
||||||
return "Index"
|
|
||||||
case Object:
|
|
||||||
return "Key"
|
|
||||||
default:
|
|
||||||
return "Unknown"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue