1
0
Fork 0

Remove context operations from parser

This commit is contained in:
Gregory Eremin 2015-02-17 22:47:22 +07:00
parent 937c8b31d7
commit 6037100d4b
1 changed files with 66 additions and 101 deletions

View File

@ -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"
}
}