Skip to content

Instantly share code, notes, and snippets.

@iliabylich
Created June 29, 2017 16:21
Show Gist options
  • Save iliabylich/836975bb029f95f3042bba36cc2b56c0 to your computer and use it in GitHub Desktop.
Save iliabylich/836975bb029f95f3042bba36cc2b56c0 to your computer and use it in GitHub Desktop.
parslet_json_parser
require 'parslet'
require 'json'
class JSONParser < Parslet::Parser
rule(:object) { str('{') >> spaces? >> object_content.maybe.as(:object) >> spaces? >> str('}') }
rule(:object_content) { (kv_pair >> (comma >> kv_pair).repeat).maybe }
rule(:kv_pair) { (key.as(:key) >> spaces? >> str(':') >> spaces? >> value.as(:value)).as(:kv_pair) }
rule(:key) { string }
rule(:value) { string | float | integer | object | array | _true | _false | null }
rule(:string) { str('"') >> (str('"').absent? >> any).repeat.as(:string) >> str('"') }
rule(:integer) { digits.as(:integer) }
rule(:float) { (digits >> str('.') >> digits).as(:float) }
rule(:array) { str('[') >> spaces? >> array_content.as(:array) >> spaces? >> str(']') }
rule(:array_content) { (array_item >> (comma >> array_item).repeat).maybe }
rule(:array_item) { value }
rule(:_true) { str('true').as(:true) }
rule(:_false) { str('false').as(:false) }
rule(:null) { str('null').as(:null) }
rule(:space) { match('\s') }
rule(:spaces) { space >> spaces.maybe }
rule(:spaces?) { spaces.maybe }
rule(:comma) { spaces? >> str(',') >> spaces? }
rule(:digit) { match('\d') }
rule(:digits) { digit >> digits.maybe }
rule(:top) { spaces? >> value >> spaces? }
root(:top)
end
class JSONTransformer < Parslet::Transform
rule(true: simple(:true)) { true }
rule(false: simple(:false)) { false }
rule(null: simple(:null)) { nil }
rule(string: simple(:string)) { string.to_s }
rule(kv_pair: { key: subtree(:key), value: subtree(:value) }) { { key => value } }
rule(integer: simple(:integer)) { integer.to_i }
rule(float: simple(:float)) { float.to_f }
rule(array: subtree(:array)) { array }
rule(object: subtree(:object)) { (object.is_a?(Array) ? object : [object]).inject(&:merge) }
end
json = <<-JSON
{
"true": true,
" false": false,
"null":
null,
"integer":
123,
"float": 123.456,
"string": "a string",
"array": [1, 2, 3],
"object": {
"a": "b"
}
}
JSON
p JSON.parse(json)
parser = JSONParser.new
tree = parser.parse(json)
transformer = JSONTransformer.new
output = transformer.apply(tree)
p output
p JSON.parse(json) == output
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment