1
0
mirror of https://github.com/gnosygnu/xowa.git synced 2025-06-13 12:54:14 +00:00
gnosygnu_xowa/400_xowa/src/gplx/langs/jsons/Json_parser.java

182 lines
6.6 KiB
Java
Raw Normal View History

2015-07-13 01:10:02 +00:00
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
2015-09-21 03:43:51 +00:00
package gplx.langs.jsons; import gplx.*; import gplx.langs.*;
import gplx.core.primitives.*;
2015-07-13 01:10:02 +00:00
public class Json_parser {
2015-08-31 02:57:59 +00:00
private byte[] src; private int src_len, pos; private final Number_parser num_parser = new Number_parser();
public Json_factory Factory() {return factory;} private final Json_factory factory = new Json_factory();
public Json_doc Parse_by_apos_ary(String... ary) {return Parse_by_apos(String_.Concat_lines_nl(ary));}
public Json_doc Parse_by_apos(String s) {return Parse(Bry_.Replace(Bry_.new_u8(s), Byte_ascii.Apos, Byte_ascii.Quote));}
public Json_doc Parse(String src) {return Parse(Bry_.new_u8(src));}
2015-07-13 01:10:02 +00:00
public Json_doc Parse(byte[] src) {
2015-08-31 02:57:59 +00:00
synchronized (factory) {
this.src = src; if (src == null) return null;
this.src_len = src.length; if (src_len == 0) return null;
this.pos = 0;
Skip_ws();
boolean root_is_nde = true;
switch (src[pos]) {
case Byte_ascii.Curly_bgn: root_is_nde = Bool_.Y; break;
case Byte_ascii.Brack_bgn: root_is_nde = Bool_.N; break;
default: return null;
}
Skip_ws();
Json_doc doc = new Json_doc();
2015-09-07 01:31:25 +00:00
Json_grp root = null;
if (root_is_nde)
root = Make_nde(doc);
else
root = Make_ary(doc);
2015-08-31 02:57:59 +00:00
doc.Ctor(src, root);
return doc;
}
2015-07-13 01:10:02 +00:00
}
2015-07-21 04:06:09 +00:00
private Json_nde Make_nde(Json_doc doc) {
2015-07-13 01:10:02 +00:00
++pos; // brack_bgn
2015-07-21 04:06:09 +00:00
Json_nde nde = new Json_nde(doc, pos);
2015-07-13 01:10:02 +00:00
while (pos < src_len) {
Skip_ws();
if (src[pos] == Byte_ascii.Curly_end) {++pos; return nde;}
2015-07-20 03:16:49 +00:00
else nde.Add(Make_kv(doc));
2015-07-13 01:10:02 +00:00
Skip_ws();
switch (src[pos++]) {
case Byte_ascii.Comma: break;
case Byte_ascii.Curly_end: return nde;
2015-07-20 03:16:49 +00:00
default: throw Err_.new_unhandled(src[pos - 1]);
2015-07-13 01:10:02 +00:00
}
}
2015-07-20 03:16:49 +00:00
throw Err_.new_wo_type("eos inside nde");
2015-07-13 01:10:02 +00:00
}
2015-08-31 02:57:59 +00:00
private Json_itm Make_kv(Json_doc doc) {
2015-07-13 01:10:02 +00:00
Json_itm key = Make_string(doc);
Skip_ws();
Chk(Byte_ascii.Colon);
Skip_ws();
Json_itm val = Make_val(doc);
2015-07-21 04:06:09 +00:00
return new Json_kv(key, val);
2015-07-13 01:10:02 +00:00
}
2015-08-31 02:57:59 +00:00
private Json_itm Make_val(Json_doc doc) {
2015-07-13 01:10:02 +00:00
while (pos < src_len) {
byte b = src[pos];
switch (b) {
case Byte_ascii.Ltr_n: return Make_literal(Bry_null_ull , 3, factory.Null());
case Byte_ascii.Ltr_f: return Make_literal(Bry_bool_alse , 4, factory.Bool_n());
case Byte_ascii.Ltr_t: return Make_literal(Bry_bool_rue , 3, factory.Bool_y());
case Byte_ascii.Quote: return Make_string(doc);
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
case Byte_ascii.Dash: return Make_num(doc);
case Byte_ascii.Brack_bgn: return Make_ary(doc);
case Byte_ascii.Curly_bgn: return Make_nde(doc);
}
2015-08-17 06:09:16 +00:00
throw Err_.new_unhandled(Char_.To_str(b));
2015-07-13 01:10:02 +00:00
}
2015-07-20 03:16:49 +00:00
throw Err_.new_wo_type("eos reached in val");
2015-07-13 01:10:02 +00:00
}
2015-08-31 02:57:59 +00:00
private Json_itm Make_literal(byte[] remainder, int remainder_len, Json_itm singleton) {
2015-07-13 01:10:02 +00:00
++pos; // 1st char
int literal_end = pos + remainder_len;
2015-09-21 03:43:51 +00:00
if (Bry_.Eq(src, pos, literal_end, remainder)) {
2015-07-13 01:10:02 +00:00
pos = literal_end;
return singleton;
}
2015-08-31 02:57:59 +00:00
throw Err_.new_("json.parser", "invalid literal", "excerpt", Bry_.Mid_by_len_safe(src, pos - 1, 16));
2015-07-13 01:10:02 +00:00
}
2015-08-31 02:57:59 +00:00
private Json_itm Make_string(Json_doc doc) {
2015-07-13 01:10:02 +00:00
int bgn = pos++; // ++: quote_bgn
boolean exact = true;
while (pos < src_len) {
switch (src[pos]) {
case Byte_ascii.Backslash:
++pos; // backslash
switch (src[pos]) {
case Byte_ascii.Ltr_u: pos += 4; break; // \uFFFF 4 hex-dec
default: ++pos; break; // \? " \ / b f n r t
}
exact = false;
break;
case Byte_ascii.Quote:
return factory.Str(doc, bgn, ++pos, exact); // ++: quote_end
default:
++pos;
break;
}
}
2015-07-20 03:16:49 +00:00
throw Err_.new_wo_type("eos reached inside quote");
2015-07-13 01:10:02 +00:00
}
2015-08-31 02:57:59 +00:00
private Json_itm Make_num(Json_doc doc) {
2015-07-13 01:10:02 +00:00
int num_bgn = pos;
boolean loop = true;
while (loop) {
2015-07-20 03:16:49 +00:00
if (pos == src_len) throw Err_.new_wo_type("eos reached inside num");
2015-07-13 01:10:02 +00:00
switch (src[pos]) {
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
++pos;
break;
case Byte_ascii.Dot:
case Byte_ascii.Dash: case Byte_ascii.Plus:
case Byte_ascii.Ltr_E: case Byte_ascii.Ltr_e: // e e+ e- E E+ E-
++pos;
break;
default:
loop = false;
break;
}
}
num_parser.Parse(src, num_bgn, pos);
return num_parser.Has_frac()
? factory.Decimal(doc, num_bgn, pos)
: factory.Int(doc, num_bgn, pos);
}
2015-08-31 02:57:59 +00:00
private Json_ary Make_ary(Json_doc doc) {
2015-07-21 04:06:09 +00:00
Json_ary rv = factory.Ary(pos++, pos); // brack_bgn
2015-07-13 01:10:02 +00:00
while (pos < src_len) {
Skip_ws();
if (src[pos] == Byte_ascii.Brack_end) {++pos; return rv;}
2015-07-20 03:16:49 +00:00
else rv.Add(Make_val(doc));
2015-07-13 01:10:02 +00:00
Skip_ws();
switch (src[pos]) {
case Byte_ascii.Comma: ++pos; break;
case Byte_ascii.Brack_end: ++pos; return rv;
}
}
2015-07-20 03:16:49 +00:00
throw Err_.new_wo_type("eos inside ary");
2015-07-13 01:10:02 +00:00
}
private void Skip_ws() {
while (pos < src_len) {
switch (src[pos]) {
case Byte_ascii.Space: case Byte_ascii.Nl: case Byte_ascii.Tab: case Byte_ascii.Cr: ++pos; break;
default: return;
}
}
}
private void Chk(byte expd) {
if (src[pos] == expd)
++pos;
else
2015-08-17 06:09:16 +00:00
throw err_(src, pos, "expected '{0}' but got '{1}'", Char_.To_str(expd), Char_.To_str(src[pos]));
2015-07-13 01:10:02 +00:00
}
2015-08-31 02:57:59 +00:00
private Err err_(byte[] src, int bgn, String fmt, Object... args) {return err_(src, bgn, src.length, fmt, args);}
private Err err_(byte[] src, int bgn, int src_len, String fmt, Object... args) {
2015-10-19 02:17:57 +00:00
String msg = String_.Format(fmt, args) + " " + Int_.To_str(bgn) + " " + String_.new_u8__by_len(src, bgn, 20);
2015-07-20 03:16:49 +00:00
return Err_.new_wo_type(msg);
2015-07-13 01:10:02 +00:00
}
2015-08-31 02:57:59 +00:00
private static final byte[] Bry_bool_rue = Bry_.new_a7("rue"), Bry_bool_alse = Bry_.new_a7("alse"), Bry_null_ull = Bry_.new_a7("ull");
2015-07-13 01:10:02 +00:00
}