Files
releases/src/jsonlog/jsonlog.peg
T
Tim Hinrichs 9cfea2c20c Add jsonlog parser
Just the basic JSON types
2016-01-06 11:31:34 -08:00

165 lines
4.4 KiB
Plaintext

{
// Command json parses JSON as defined by [1].
//
// BUGS: the escaped forward solidus (`\/`) is not currently handled for strings.
//
// TODO: check if JSON's numbers are a subset of Go's numbers, since we are
// assuming they are. Currently representing all numbers as float64.
// TODO: think about relaxing a Dictionary to allow numeric keys, as they are common in practice.
// [1]: http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
package jsonlog
const (
// note: iota is built into Go and is auto-incremented
NULL = iota
BOOLEAN = iota
NUMBER = iota
STRING = iota
VARIABLE = iota
REFERENCE = iota
ARRAY = iota
DICTIONARY = iota
)
// Location records a position in source code
type Location struct {
File string
Row int
Col int
}
func NewLocation(file string, row int, col int) *Location {
l := Location{File: file, Row: row, Col: col}
return &l
}
// Term is an argument to a function
type Term struct {
Value interface{} // actual value, as represented by Go
Kind int // type of Term: one of the consts defined above
Name []byte // original string representation
Location *Location // text location in original source
}
// NewTerm creates a new Term
func NewTerm(x interface{}, kind int, orig []byte, file string, row int, col int) *Term {
t := Term{Value: x, Kind: kind, Name: orig, Location: NewLocation(file, row, col)}
return &t
}
// Equal checks if two terms are equal
func (t1 *Term) Equal (t2 *Term) bool {
return t1.Kind == t2.Kind && t1.Value == t2.Value
}
func toIfaceSlice(v interface{}) []interface{} {
if v == nil {
return nil
}
return v.([]interface{})
}
}
Prog <- _ vals:Term+ EOF {
if vals == nil {
return make([]interface{}, 0), nil
}
return vals.([]interface{}), nil
// valsSl := toIfaceSlice(vals)
// return valsSl, nil
// switch len(valsSl) {
// case 0:
// return nil, nil
// case 1:
// return valsSl[0], nil
// default:
// return valsSl, nil
// }
}
Term <- val:( Dictionary / Array / Number / String / Bool / Null ) _ {
return val, nil
}
Dictionary <- '{' _ vals:( String _ ':' _ Value ( ',' _ String _ ':' _ Value )* )? '}' {
res := make(map[string]interface{})
valsSl := toIfaceSlice(vals)
if len(valsSl) == 0 {
return res, nil
}
res[valsSl[0].(string)] = valsSl[4]
restSl := toIfaceSlice(valsSl[5])
for _, v := range restSl {
vSl := toIfaceSlice(v)
res[vSl[2].(string)] = vSl[6]
}
t := NewTerm(res, DICTIONARY, c.text, "", c.pos.line, c.pos.col)
return t, nil //res, nil
}
Array <- '[' _ vals:( Value ( ',' _ Value )* )? ']' {
valsSl := toIfaceSlice(vals)
if len(valsSl) == 0 {
return []interface{}{}, nil
}
res := []interface{}{valsSl[0]}
restSl := toIfaceSlice(valsSl[1])
for _, v := range restSl {
vSl := toIfaceSlice(v)
res = append(res, vSl[2])
}
t := NewTerm(res, ARRAY, c.text, "", c.pos.line, c.pos.col)
return t, nil //res, nil
}
Number <- '-'? Integer ( '.' DecimalDigit+ )? Exponent? {
// JSON numbers have the same syntax as Go's, and are parseable using
// strconv.
v, err := strconv.ParseFloat(string(c.text), 64)
t := NewTerm(v, NUMBER, c.text, "", c.pos.line, c.pos.col)
return t, err
}
Integer <- '0' / NonZeroDecimalDigit DecimalDigit*
Exponent <- 'e'i [+-]? DecimalDigit+
String <- '"' ( !EscapedChar . / '\\' EscapeSequence )* '"' {
// TODO : the forward slash (solidus) is not a valid escape in Go, it will
// fail if there's one in the string
v, err := strconv.Unquote(string(c.text))
t := NewTerm(v, STRING, c.text, "", c.pos.line, c.pos.col)
return t, err // v, err
}
EscapedChar <- [\x00-\x1f"\\]
EscapeSequence <- SingleCharEscape / UnicodeEscape
SingleCharEscape <- ["\\/bfnrt]
UnicodeEscape <- 'u' HexDigit HexDigit HexDigit HexDigit
DecimalDigit <- [0-9]
NonZeroDecimalDigit <- [1-9]
HexDigit <- [0-9a-f]i
Bool <- "true" {
t := NewTerm(true, BOOLEAN, c.text, "", c.pos.line, c.pos.col)
return t, nil // true, nil
} / "false" {
t := NewTerm(false, BOOLEAN, c.text, "", c.pos.line, c.pos.col)
return t, nil // false, nil
}
Null <- "null" {
t := NewTerm(nil, NULL, c.text, "", c.pos.line, c.pos.col)
return t, nil //nil, nil
}
_ "whitespace" <- [ \t\r\n]*
EOF <- !.