diff --git a/spec/json_parser.propane b/spec/json_parser.propane new file mode 100644 index 0000000..50b1462 --- /dev/null +++ b/spec/json_parser.propane @@ -0,0 +1,179 @@ +<< +import std.math; +import json_types; +private string string_value; +>> + +ptype JSONValue; +ptype array = JSONValue[]; +ptype dict = JSONValue[string]; +ptype string = string; + +drop /\s+/; +token lbrace /\{/; +token rbrace /\}/; +token lbracket /\[/; +token rbracket /\]/; +token comma /,/; +token colon /:/; +token number /-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][-+]?[0-9]+)?/ << + double n; + bool negative; + size_t i = 0u; + if (match[i] == '-') + { + negative = true; + i++; + } + while ('0' <= match[i] && match[i] <= '9') + { + n *= 10.0; + n += (match[i] - '0'); + i++; + } + if (match[i] == '.') + { + i++; + double mult = 0.1; + while ('0' <= match[i] && match[i] <= '9') + { + n += mult * (match[i] - '0'); + mult /= 10.0; + i++; + } + } + if (match[i] == 'e' || match[i] == 'E') + { + bool exp_negative; + i++; + if (match[i] == '-') + { + exp_negative = true; + i++; + } + else if (match[i] == '+') + { + i++; + } + long exp; + while ('0' <= match[i] && match[i] <= '9') + { + exp *= 10; + exp += (match[i] - '0'); + i++; + } + if (exp_negative) + { + exp = -exp; + } + n = pow(n, exp); + } + if (negative) + { + n = -n; + } + $$ = new JSONNumber(n); +>> +token true << + $$ = new JSONTrue(); +>> +token false << + $$ = new JSONFalse(); +>> +token null << + $$ = new JSONNull(); +>> +/"/ << + $mode(string); + string_value = ""; +>> +string: token string (string) /"/ << + $$ = string_value; + $mode(default); +>> +string: /\\"/ << + string_value ~= "\""; +>> +string: /\\\\/ << + string_value ~= "\\"; +>> +string: /\\\// << + string_value ~= "/"; +>> +string: /\\b/ << + string_value ~= "\b"; +>> +string: /\\f/ << + string_value ~= "\f"; +>> +string: /\\n/ << + string_value ~= "\n"; +>> +string: /\\r/ << + string_value ~= "\r"; +>> +string: /\\t/ << + string_value ~= "\t"; +>> +string: /\\u[0-9a-fA-F]{4}/ << + /* Not actually going to encode the code point for this example... */ + string_value ~= "{" ~ match[2..6] ~ "}"; +>> +string: /[^\\]/ << + string_value ~= match; +>> +Start -> Value << + $$ = $1; +>> +Value -> string << + $$ = new JSONString($1); +>> +Value -> number << + $$ = $1; +>> +Value -> Object << + $$ = $1; +>> +Value -> Array << + $$ = $1; +>> +Value -> true << + $$ = $1; +>> +Value -> false << + $$ = $1; +>> +Value -> null << + $$ = $1; +>> +Object -> lbrace rbrace << + $$ = new JSONObject(); +>> +Object -> lbrace KeyValues rbrace << + $$ = new JSONObject($2); +>> +KeyValues (dict) -> KeyValue << + $$ = $1; +>> +KeyValues -> KeyValues comma KeyValue << + foreach (key, value; $3) + { + $1[key] = value; + } + $$ = $1; +>> +KeyValue (dict) -> string colon Value << + $$ = [$1: $3]; +>> +Array -> lbracket rbracket << + $$ = new JSONArray(); +>> +Array -> lbracket Values rbracket << + $$ = new JSONArray($2); +>> +Values (array) -> Value << + $$ = [$1]; +>> +Values -> Values comma Value << + $$ = $1 ~ [$3]; +>> diff --git a/spec/propane_spec.rb b/spec/propane_spec.rb index c336946..894b162 100644 --- a/spec/propane_spec.rb +++ b/spec/propane_spec.rb @@ -336,187 +336,7 @@ EOF end it "allows creating a JSON parser" do - write_grammar <> - -ptype JSONValue; -ptype array = JSONValue[]; -ptype dict = JSONValue[string]; -ptype string = string; - -drop /\\s+/; -token lbrace /\\{/; -token rbrace /\\}/; -token lbracket /\\[/; -token rbracket /\\]/; -token comma /,/; -token colon /:/; -token number /-?(0|[1-9][0-9]*)(\\.[0-9]+)?([eE][-+]?[0-9]+)?/ << - double n; - bool negative; - size_t i = 0u; - if (match[i] == '-') - { - negative = true; - i++; - } - while ('0' <= match[i] && match[i] <= '9') - { - n *= 10.0; - n += (match[i] - '0'); - i++; - } - if (match[i] == '.') - { - i++; - double mult = 0.1; - while ('0' <= match[i] && match[i] <= '9') - { - n += mult * (match[i] - '0'); - mult /= 10.0; - i++; - } - } - if (match[i] == 'e' || match[i] == 'E') - { - bool exp_negative; - i++; - if (match[i] == '-') - { - exp_negative = true; - i++; - } - else if (match[i] == '+') - { - i++; - } - long exp; - while ('0' <= match[i] && match[i] <= '9') - { - exp *= 10; - exp += (match[i] - '0'); - i++; - } - if (exp_negative) - { - exp = -exp; - } - n = pow(n, exp); - } - if (negative) - { - n = -n; - } - $$ = new JSONNumber(n); ->> -token true << - $$ = new JSONTrue(); ->> -token false << - $$ = new JSONFalse(); ->> -token null << - $$ = new JSONNull(); ->> -/"/ << - $mode(string); - string_value = ""; ->> -string: token string (string) /"/ << - $$ = string_value; - $mode(default); ->> -string: /\\\\"/ << - string_value ~= "\\""; ->> -string: /\\\\\\\\/ << - string_value ~= "\\\\"; ->> -string: /\\\\\\// << - string_value ~= "/"; ->> -string: /\\\\b/ << - string_value ~= "\\b"; ->> -string: /\\\\f/ << - string_value ~= "\\f"; ->> -string: /\\\\n/ << - string_value ~= "\\n"; ->> -string: /\\\\r/ << - string_value ~= "\\r"; ->> -string: /\\\\t/ << - string_value ~= "\\t"; ->> -string: /\\\\u[0-9a-fA-F]{4}/ << - /* Not actually going to encode the code point for this example... */ - string_value ~= "{" ~ match[2..6] ~ "}"; ->> -string: /[^\\\\]/ << - string_value ~= match; ->> -Start -> Value << - $$ = $1; ->> -Value -> string << - $$ = new JSONString($1); ->> -Value -> number << - $$ = $1; ->> -Value -> Object << - $$ = $1; ->> -Value -> Array << - $$ = $1; ->> -Value -> true << - $$ = $1; ->> -Value -> false << - $$ = $1; ->> -Value -> null << - $$ = $1; ->> -Object -> lbrace rbrace << - $$ = new JSONObject(); ->> -Object -> lbrace KeyValues rbrace << - $$ = new JSONObject($2); ->> -KeyValues (dict) -> KeyValue << - $$ = $1; ->> -KeyValues -> KeyValues comma KeyValue << - foreach (key, value; $3) - { - $1[key] = value; - } - $$ = $1; ->> -KeyValue (dict) -> string colon Value << - $$ = [$1: $3]; ->> -Array -> lbracket rbracket << - $$ = new JSONArray(); ->> -Array -> lbracket Values rbracket << - $$ = new JSONArray($2); ->> -Values (array) -> Value << - $$ = [$1]; ->> -Values -> Values comma Value << - $$ = $1 ~ [$3]; ->> -EOF + write_grammar(File.read("spec/json_parser.propane")) build_parser compile("spec/test_parsing_json.d", "spec/json_types.d") end