mirror of https://github.com/buggins/dlangui.git
json parsing
This commit is contained in:
parent
424bf7a83e
commit
589a02debd
|
@ -1,9 +1,10 @@
|
||||||
module dlangui.core.settings;
|
module dlangui.core.settings;
|
||||||
|
|
||||||
import std.range;
|
import std.range;
|
||||||
import std.algorithm;
|
import std.algorithm : equal;
|
||||||
import std.conv;
|
import std.conv : to;
|
||||||
import std.utf;
|
import std.utf : encode;
|
||||||
|
import std.math : pow;
|
||||||
|
|
||||||
enum SettingType {
|
enum SettingType {
|
||||||
STRING,
|
STRING,
|
||||||
|
@ -1015,12 +1016,8 @@ final class Setting {
|
||||||
@property char peek() {
|
@property char peek() {
|
||||||
return pos < json.length ? json[pos] : 0;
|
return pos < json.length ? json[pos] : 0;
|
||||||
}
|
}
|
||||||
/// returns next char, 0 if eof
|
|
||||||
@property char nextChar() {
|
|
||||||
return pos < json.length ? json[pos++] : 0;
|
|
||||||
}
|
|
||||||
/// skips current char, returns next one (or null if eof)
|
/// skips current char, returns next one (or null if eof)
|
||||||
@property char skipChar() {
|
@property char nextChar() {
|
||||||
if (pos < json.length - 1) {
|
if (pos < json.length - 1) {
|
||||||
return json[++pos];
|
return json[++pos];
|
||||||
} else {
|
} else {
|
||||||
|
@ -1102,7 +1099,7 @@ final class Setting {
|
||||||
error("unexpected end of file while parsing unicode character entity inside string");
|
error("unexpected end of file while parsing unicode character entity inside string");
|
||||||
dchar ch = 0;
|
dchar ch = 0;
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
int d = parseHexDigit(skipChar);
|
int d = parseHexDigit(nextChar);
|
||||||
if (d < 0)
|
if (d < 0)
|
||||||
error("error while parsing unicode character entity inside string");
|
error("error while parsing unicode character entity inside string");
|
||||||
ch = (ch << 4) | d;
|
ch = (ch << 4) | d;
|
||||||
|
@ -1112,23 +1109,23 @@ final class Setting {
|
||||||
return buf[0..sz].dup;
|
return buf[0..sz].dup;
|
||||||
}
|
}
|
||||||
|
|
||||||
string parseString() {
|
@property string parseString() {
|
||||||
char ch = peek;
|
char ch = peek;
|
||||||
if (ch != '\"') {
|
if (ch != '\"') {
|
||||||
error("cannot parse string");
|
error("cannot parse string");
|
||||||
}
|
}
|
||||||
char[] res;
|
char[] res;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
ch = skipChar;
|
ch = nextChar;
|
||||||
if (!ch)
|
if (!ch)
|
||||||
error("unexpected end of file while parsing string");
|
error("unexpected end of file while parsing string");
|
||||||
if (ch == '\"') {
|
if (ch == '\"') {
|
||||||
skipChar;
|
nextChar;
|
||||||
return cast(string)res;
|
return cast(string)res;
|
||||||
}
|
}
|
||||||
if (ch == '\\') {
|
if (ch == '\\') {
|
||||||
// escape sequence
|
// escape sequence
|
||||||
ch = skipChar;
|
ch = nextChar;
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'n':
|
case 'n':
|
||||||
res ~= '\n';
|
res ~= '\n';
|
||||||
|
@ -1161,16 +1158,16 @@ final class Setting {
|
||||||
}
|
}
|
||||||
return cast(string)res;
|
return cast(string)res;
|
||||||
}
|
}
|
||||||
string parseIdent() {
|
@property string parseIdent() {
|
||||||
char ch = peek;
|
char ch = peek;
|
||||||
if (ch == '\"') {
|
if (ch == '\"') {
|
||||||
return parseString();
|
return parseString;
|
||||||
}
|
}
|
||||||
char[] res;
|
char[] res;
|
||||||
if (isAlpha(ch)) {
|
if (isAlpha(ch)) {
|
||||||
res ~= ch;
|
res ~= ch;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
ch = skipChar;
|
ch = nextChar;
|
||||||
if (isAlNum(ch)) {
|
if (isAlNum(ch)) {
|
||||||
res ~= ch;
|
res ~= ch;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1197,71 +1194,142 @@ final class Setting {
|
||||||
pos += ident.length;
|
pos += ident.length;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Setting parseNumber(Setting res) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Setting parseValue(ref JsonParser parser) {
|
// parse long, ulong or double
|
||||||
char ch = parser.skipSpaces;
|
void parseNumber(Setting res) {
|
||||||
Setting res = new Setting();
|
char ch = peek;
|
||||||
if (ch == '\"') {
|
int sign = 1;
|
||||||
res = parser.parseString;
|
if (ch == '-') {
|
||||||
return res;
|
sign = -1;
|
||||||
} else if (ch == '[') {
|
nextChar;
|
||||||
//res.parseArray(parser);
|
}
|
||||||
} else if (ch == '{') {
|
if (!isDigit(ch))
|
||||||
res.parseMap(parser);
|
error("cannot parse number");
|
||||||
} else {
|
ulong n = 0;
|
||||||
if (parser.parseKeyword("null")) {
|
while (isDigit(ch)) {
|
||||||
return res;
|
n = n * 10 + (ch - '0');
|
||||||
} else if (parser.parseKeyword("true")) {
|
ch = nextChar;
|
||||||
res = true;
|
}
|
||||||
return res;
|
if (ch == '.' || ch == 'e' || ch == 'E') {
|
||||||
} else if (parser.parseKeyword("false")) {
|
// floating
|
||||||
res = false;
|
ulong n2 = 0;
|
||||||
return res;
|
ulong n2_div = 1;
|
||||||
} else if (ch == '-' || JsonParser.isDigit(ch)) {
|
if (ch == '.') {
|
||||||
return parser.parseNumber(res);
|
ch = nextChar;
|
||||||
|
while(isDigit(ch)) {
|
||||||
|
n2 = n2 * 10 + (ch - '0');
|
||||||
|
n2_div *= 10;
|
||||||
|
ch = nextChar;
|
||||||
|
}
|
||||||
|
if (isAlpha(ch) && ch != 'e' && ch != 'E')
|
||||||
|
error("error while parsing number");
|
||||||
|
}
|
||||||
|
int shift = 0;
|
||||||
|
int shiftSign = 1;
|
||||||
|
if (ch == 'e' || ch == 'E') {
|
||||||
|
ch = nextChar;
|
||||||
|
if (ch == '-') {
|
||||||
|
shiftSign = -1;
|
||||||
|
ch = nextChar;
|
||||||
|
}
|
||||||
|
if (!isDigit(ch))
|
||||||
|
error("error while parsing number");
|
||||||
|
while(isDigit(ch)) {
|
||||||
|
shift = shift * 10 + (ch - '0');
|
||||||
|
ch = nextChar;
|
||||||
|
}
|
||||||
|
if (shiftSign < 0)
|
||||||
|
shift = -shift;
|
||||||
|
}
|
||||||
|
if (isAlpha(ch))
|
||||||
|
error("error while parsing number");
|
||||||
|
double v = sign > 0 ? n : -n;
|
||||||
|
if (n2) // part after period
|
||||||
|
v += cast(double)n2 / n2_div;
|
||||||
|
if (shift) // E part - pow10
|
||||||
|
v *= pow(10.0, shift);
|
||||||
|
res.floating = v;
|
||||||
} else {
|
} else {
|
||||||
parser.error("cannot parse JSON value");
|
// integer
|
||||||
|
if (isAlpha(ch))
|
||||||
|
error("cannot parse number");
|
||||||
|
if (sign < 0 || !(n & 0x8000000000000000L))
|
||||||
|
res.integer = cast(long)(n * sign); // signed
|
||||||
|
else
|
||||||
|
res.uinteger = n; // unsigned
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseMap(ref JsonParser parser) {
|
private void parseMap(ref JsonParser parser) {
|
||||||
clear(SettingType.OBJECT);
|
clear(SettingType.OBJECT);
|
||||||
parser.skipChar; // skip initial {
|
parser.nextChar; // skip initial {
|
||||||
for(;;) {
|
for(;;) {
|
||||||
char ch = parser.skipSpaces;
|
char ch = parser.skipSpaces;
|
||||||
if (ch == '}') {
|
if (ch == '}') {
|
||||||
parser.skipChar;
|
parser.nextChar;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
string key = parser.parseIdent();
|
string key = parser.parseIdent;
|
||||||
ch = parser.skipSpaces;
|
ch = parser.skipSpaces;
|
||||||
if (ch != ':')
|
if (ch != ':')
|
||||||
parser.error("no : char after object field name");
|
parser.error("no : char after object field name");
|
||||||
parser.skipChar();
|
parser.nextChar;
|
||||||
Setting value = parseValue(parser);
|
this[key] = (new Setting()).parseJSON(parser);
|
||||||
this[key] = value;
|
|
||||||
ch = parser.skipSpaces;
|
ch = parser.skipSpaces;
|
||||||
if (ch == ',') {
|
if (ch == ',') {
|
||||||
parser.skipChar();
|
parser.nextChar;
|
||||||
parser.skipSpaces();
|
parser.skipSpaces;
|
||||||
} else if (ch != '}') {
|
} else if (ch != '}') {
|
||||||
parser.error("unexpected character when waiting for , or } while parsing object");
|
parser.error("unexpected character when waiting for , or } while parsing object");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void parseJSON(ref JsonParser parser) {
|
|
||||||
char ch = parser.skipSpaces;
|
private void parseArray(ref JsonParser parser) {
|
||||||
if (ch == '{') {
|
clear(SettingType.ARRAY);
|
||||||
parseMap(parser);
|
parser.nextChar; // skip initial [
|
||||||
} else if (ch == '[') {
|
for(;;) {
|
||||||
} else if (ch == '\"') {
|
char ch = parser.skipSpaces;
|
||||||
|
if (ch == ']') {
|
||||||
|
parser.nextChar;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Setting value = new Setting();
|
||||||
|
value.parseJSON(parser);
|
||||||
|
this[_store.array.length] = value;
|
||||||
|
ch = parser.skipSpaces;
|
||||||
|
if (ch == ',') {
|
||||||
|
parser.nextChar;
|
||||||
|
parser.skipSpaces;
|
||||||
|
} else if (ch != ']') {
|
||||||
|
parser.error("unexpected character when waiting for , or ] while parsing array");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Setting parseJSON(ref JsonParser parser) {
|
||||||
|
char ch = parser.skipSpaces;
|
||||||
|
if (ch == '\"') {
|
||||||
|
this = parser.parseString;
|
||||||
|
} else if (ch == '[') {
|
||||||
|
parseArray(parser);
|
||||||
|
} else if (ch == '{') {
|
||||||
|
parseMap(parser);
|
||||||
|
} else if (parser.parseKeyword("null")) {
|
||||||
|
// do nothing - we already have NULL value
|
||||||
|
} else if (parser.parseKeyword("true")) {
|
||||||
|
this = true;
|
||||||
|
} else if (parser.parseKeyword("false")) {
|
||||||
|
this = false;
|
||||||
|
} else if (ch == '-' || JsonParser.isDigit(ch)) {
|
||||||
|
parser.parseNumber(this);
|
||||||
|
} else {
|
||||||
|
parser.error("cannot parse JSON value");
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
bool parseJSON(string s) {
|
bool parseJSON(string s) {
|
||||||
clear(SettingType.NULL);
|
clear(SettingType.NULL);
|
||||||
JsonParser parser;
|
JsonParser parser;
|
||||||
|
|
Loading…
Reference in New Issue