mirror of
https://github.com/gnosygnu/xowa.git
synced 2025-06-13 12:54:14 +00:00
215 lines
9.0 KiB
Java
215 lines
9.0 KiB
Java
/*
|
|
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/>.
|
|
*/
|
|
package gplx.langs.gfs; import gplx.*; import gplx.langs.*;
|
|
interface Gfs_lxr {
|
|
int Lxr_tid();
|
|
int Process(Gfs_parser_ctx ctx, int bgn, int end);
|
|
}
|
|
class Gfs_lxr_whitespace implements Gfs_lxr {
|
|
public int Lxr_tid() {return Gfs_lxr_.Tid_whitespace;}
|
|
public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
|
|
byte[] src = ctx.Src(); int src_len = ctx.Src_len();
|
|
int rv = Gfs_lxr_.Rv_eos, cur_pos;
|
|
for (cur_pos = end; cur_pos < src_len; cur_pos++) {
|
|
byte b = src[cur_pos];
|
|
Object o = ctx.Trie().Match_at_w_b0(ctx.Trie_rv(), b, src, cur_pos, src_len);
|
|
if (o == null) {
|
|
rv = Gfs_lxr_.Rv_null;
|
|
ctx.Process_null(cur_pos);
|
|
break;
|
|
}
|
|
else {
|
|
Gfs_lxr lxr = (Gfs_lxr)o;
|
|
if (lxr.Lxr_tid() == Gfs_lxr_.Tid_whitespace) {}
|
|
else {
|
|
rv = Gfs_lxr_.Rv_lxr;
|
|
ctx.Process_lxr(cur_pos, lxr);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
public static final Gfs_lxr_whitespace Instance = new Gfs_lxr_whitespace(); Gfs_lxr_whitespace() {}
|
|
}
|
|
class Gfs_lxr_comment_flat implements Gfs_lxr {
|
|
public Gfs_lxr_comment_flat(byte[] bgn_bry, byte[] end_bry) {
|
|
this.bgn_bry = bgn_bry; this.bgn_bry_len = bgn_bry.length;
|
|
this.end_bry = end_bry; this.end_bry_len = end_bry.length;
|
|
} byte[] bgn_bry, end_bry; int bgn_bry_len, end_bry_len;
|
|
public int Lxr_tid() {return Gfs_lxr_.Tid_comment;}
|
|
public int Process(Gfs_parser_ctx ctx, int lxr_bgn, int lxr_end) {
|
|
byte[] src = ctx.Src(); int src_len = ctx.Src_len();
|
|
int end_pos = Bry_find_.Find_fwd(src, end_bry, lxr_end, src_len);
|
|
// if (end_pos == Bry_find_.Not_found) throw Err_.new_fmt_("comment is not closed: {0}", String_.new_u8(end_bry));
|
|
return (end_pos == Bry_find_.Not_found)
|
|
? src_len // allow eos to terminate flat comment; needed for "tidy-always-adds-nl-in-textarea" fix; NOTE: DATE:2014-06-21
|
|
: end_pos + end_bry_len; // position after end_bry
|
|
}
|
|
}
|
|
class Gfs_lxr_identifier implements Gfs_lxr {
|
|
public int Lxr_tid() {return Gfs_lxr_.Tid_identifier;}
|
|
public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
|
|
byte[] src = ctx.Src(); int src_len = ctx.Src_len();
|
|
int pos, rv = Gfs_lxr_.Rv_eos;
|
|
for (pos = end; pos < src_len; pos++) {
|
|
byte b = src[pos];
|
|
Object o = ctx.Trie().Match_at_w_b0(ctx.Trie_rv(), b, src, pos, src_len);
|
|
if (o == null) { // invalid char; stop;
|
|
rv = Gfs_lxr_.Rv_null;
|
|
ctx.Process_null(pos);
|
|
break;
|
|
}
|
|
else {
|
|
Gfs_lxr lxr = (Gfs_lxr)o;
|
|
if (lxr.Lxr_tid() == Gfs_lxr_.Tid_identifier) {} // still an identifier; continue
|
|
else { // new lxr (EX: "." in "abc."); (a) hold word of "abc"; mark "." as new lxr;
|
|
ctx.Hold_word(bgn, pos);
|
|
rv = Gfs_lxr_.Rv_lxr;
|
|
ctx.Process_lxr(pos, lxr);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (rv == Gfs_lxr_.Rv_eos) ctx.Process_eos(); // eos
|
|
return rv;
|
|
}
|
|
public static final Gfs_lxr_identifier Instance = new Gfs_lxr_identifier(); Gfs_lxr_identifier() {}
|
|
}
|
|
class Gfs_lxr_semic implements Gfs_lxr {
|
|
public int Lxr_tid() {return Gfs_lxr_.Tid_semic;}
|
|
public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
|
|
switch (ctx.Prv_lxr()) {
|
|
case Gfs_lxr_.Tid_identifier: ctx.Make_nde(bgn, end); ctx.Cur_nde_from_stack(); break; // a;
|
|
case Gfs_lxr_.Tid_quote:
|
|
case Gfs_lxr_.Tid_paren_end: ctx.Cur_nde_from_stack(); break; // a();
|
|
case Gfs_lxr_.Tid_semic: break; // a;; ignore;
|
|
default: ctx.Err_mgr().Fail_invalid_lxr(ctx, bgn, this.Lxr_tid(), Byte_ascii.Semic); break;
|
|
}
|
|
return end;
|
|
}
|
|
public static final Gfs_lxr_semic Instance = new Gfs_lxr_semic(); Gfs_lxr_semic() {}
|
|
}
|
|
class Gfs_lxr_dot implements Gfs_lxr {
|
|
public int Lxr_tid() {return Gfs_lxr_.Tid_dot;}
|
|
public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
|
|
switch (ctx.Prv_lxr()) {
|
|
case Gfs_lxr_.Tid_identifier: ctx.Make_nde(bgn, end); break; // a.
|
|
case Gfs_lxr_.Tid_paren_end: break; // a().
|
|
default: ctx.Err_mgr().Fail_invalid_lxr(ctx, bgn, this.Lxr_tid(), Byte_ascii.Dot); break;
|
|
}
|
|
return end;
|
|
}
|
|
public static final Gfs_lxr_dot Instance = new Gfs_lxr_dot(); Gfs_lxr_dot() {}
|
|
}
|
|
class Gfs_lxr_paren_bgn implements Gfs_lxr {
|
|
public int Lxr_tid() {return Gfs_lxr_.Tid_paren_bgn;}
|
|
public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
|
|
switch (ctx.Prv_lxr()) {
|
|
case Gfs_lxr_.Tid_identifier: ctx.Make_nde(bgn, end); break; // a(;
|
|
default: ctx.Err_mgr().Fail_invalid_lxr(ctx, bgn, this.Lxr_tid(), Byte_ascii.Paren_bgn); break;
|
|
}
|
|
return end;
|
|
}
|
|
public static final Gfs_lxr_paren_bgn Instance = new Gfs_lxr_paren_bgn(); Gfs_lxr_paren_bgn() {}
|
|
}
|
|
class Gfs_lxr_paren_end implements Gfs_lxr {
|
|
public int Lxr_tid() {return Gfs_lxr_.Tid_paren_end;}
|
|
public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
|
|
switch (ctx.Prv_lxr()) {
|
|
case Gfs_lxr_.Tid_paren_bgn:
|
|
case Gfs_lxr_.Tid_quote: break; // "))", "abc)", "'abc')"
|
|
case Gfs_lxr_.Tid_identifier: ctx.Make_atr_by_idf(); break; // 123)
|
|
default: ctx.Err_mgr().Fail_invalid_lxr(ctx, bgn, this.Lxr_tid(), Byte_ascii.Paren_end); break;
|
|
}
|
|
return end;
|
|
}
|
|
public static final Gfs_lxr_paren_end Instance = new Gfs_lxr_paren_end(); Gfs_lxr_paren_end() {}
|
|
}
|
|
class Gfs_lxr_quote implements Gfs_lxr {
|
|
public Gfs_lxr_quote(byte[] bgn_bry, byte[] end_bry) {
|
|
this.bgn_bry_len = bgn_bry.length;
|
|
this.end_bry = end_bry; this.end_bry_len = end_bry.length;
|
|
} private byte[] end_bry; private int bgn_bry_len, end_bry_len;
|
|
public int Lxr_tid() {return Gfs_lxr_.Tid_quote;}
|
|
public int Process(Gfs_parser_ctx ctx, int lxr_bgn, int lxr_end) {
|
|
byte[] src = ctx.Src(); int src_len = ctx.Src_len();
|
|
int end_pos = Bry_find_.Find_fwd(src, end_bry, lxr_end, src_len);
|
|
if (end_pos == Bry_find_.Not_found) throw Err_.new_wo_type("quote is not closed", "end", String_.new_u8(end_bry));
|
|
Bry_bfr bfr = ctx.Tmp_bfr().Clear();
|
|
int prv_pos = lxr_end;
|
|
int nxt_pos = end_pos + end_bry_len;
|
|
if (Bry_.Match(src, nxt_pos, nxt_pos + end_bry_len, end_bry)) { // end_bry is doubled; EX: end_bry = ' and raw = a''
|
|
while (true) {
|
|
bfr.Add_mid(src, prv_pos, end_pos); // add everything up to end_bry
|
|
bfr.Add(end_bry); // add end_bry
|
|
prv_pos = nxt_pos + end_bry_len; // set prv_pos to after doubled end_bry
|
|
end_pos = Bry_find_.Find_fwd(src, end_bry, prv_pos, src_len);
|
|
if (end_pos == Bry_find_.Not_found) throw Err_.new_wo_type("quote is not closed", "end", String_.new_u8(end_bry));
|
|
nxt_pos = end_pos + end_bry_len;
|
|
if (!Bry_.Match(src, nxt_pos, nxt_pos + end_bry_len, end_bry)) {
|
|
bfr.Add_mid(src, prv_pos, end_pos);
|
|
break;
|
|
}
|
|
}
|
|
ctx.Make_atr_by_bry(lxr_bgn + bgn_bry_len, end_pos, bfr.To_bry_and_clear());
|
|
}
|
|
else
|
|
ctx.Make_atr(lxr_bgn + bgn_bry_len, end_pos);
|
|
return end_pos + end_bry_len; // position after quote
|
|
}
|
|
}
|
|
class Gfs_lxr_curly_bgn implements Gfs_lxr {
|
|
public int Lxr_tid() {return Gfs_lxr_.Tid_curly_bgn;}
|
|
public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
|
|
switch (ctx.Prv_lxr()) {
|
|
case Gfs_lxr_.Tid_identifier: ctx.Make_nde(bgn, end); ctx.Stack_add(); break; // a{;
|
|
case Gfs_lxr_.Tid_paren_end: ctx.Stack_add(); break; // a(){; NOTE: node exists but needs to be pushed onto stack
|
|
default: ctx.Err_mgr().Fail_invalid_lxr(ctx, bgn, this.Lxr_tid(), Byte_ascii.Curly_bgn); break;
|
|
}
|
|
return end;
|
|
}
|
|
public static final Gfs_lxr_curly_bgn Instance = new Gfs_lxr_curly_bgn(); Gfs_lxr_curly_bgn() {}
|
|
}
|
|
class Gfs_lxr_curly_end implements Gfs_lxr {
|
|
public int Lxr_tid() {return Gfs_lxr_.Tid_curly_end;}
|
|
public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
|
|
ctx.Stack_pop(bgn);
|
|
return end;
|
|
}
|
|
public static final Gfs_lxr_curly_end Instance = new Gfs_lxr_curly_end(); Gfs_lxr_curly_end() {}
|
|
}
|
|
class Gfs_lxr_equal implements Gfs_lxr {
|
|
public int Lxr_tid() {return Gfs_lxr_.Tid_eq;}
|
|
public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
|
|
ctx.Make_nde(bgn, end).Op_tid_(Gfs_nde.Op_tid_assign);
|
|
return end;
|
|
}
|
|
public static final Gfs_lxr_equal Instance = new Gfs_lxr_equal(); Gfs_lxr_equal() {}
|
|
}
|
|
class Gfs_lxr_comma implements Gfs_lxr {
|
|
public int Lxr_tid() {return Gfs_lxr_.Tid_comma;}
|
|
public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
|
|
switch (ctx.Prv_lxr()) {
|
|
case Gfs_lxr_.Tid_identifier: ctx.Make_atr_by_idf(); break; // 123,
|
|
}
|
|
return end;
|
|
}
|
|
public static final Gfs_lxr_comma Instance = new Gfs_lxr_comma(); Gfs_lxr_comma() {}
|
|
}
|