mirror of
https://github.com/gnosygnu/xowa.git
synced 2026-03-02 03:49:30 +00:00
263 lines
9.2 KiB
Java
263 lines
9.2 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.php; import gplx.*;
|
|
/*
|
|
NOTE: naive implementation of PHP evaluator. intended only for parsing Messages**.php files in MediaWiki. Specifically, it assumes the following:
|
|
- all lines are assignment lines: EX: $a = b;
|
|
- only the assignment operator is allowed (=); EX: $a = 5 + 7; fails b/c of + operator;
|
|
- no functions are supported: EX: strlen('a') fails
|
|
*/
|
|
public class Php_evaluator implements Php_tkn_wkr {
|
|
byte mode = Mode_key_bgn, next_tid = 0, next_mode = 0;
|
|
Php_line_assign cur_line; Php_itm_ary cur_ary; Php_key cur_kv_key;
|
|
ListAdp frame_stack = ListAdp_.new_();
|
|
public Php_evaluator(Gfo_msg_log msg_log) {this.msg_log = msg_log;} Gfo_msg_log msg_log;
|
|
public void Init(Php_ctx ctx) {src = ctx.Src(); frame_stack.Clear();} private byte[] src;
|
|
public ListAdp List() {return lines;} ListAdp lines = ListAdp_.new_();
|
|
public Gfo_msg_log Msg_log() {return msg_log;}
|
|
public void Clear() {
|
|
lines.Clear(); msg_log.Clear();
|
|
cur_line = null;
|
|
cur_ary = null;
|
|
cur_kv_key = null;
|
|
mode = Mode_key_bgn;
|
|
next_tid = next_mode = 0;
|
|
}
|
|
public void Process(Php_tkn tkn) {
|
|
byte tkn_tid = tkn.Tkn_tid();
|
|
switch (tkn_tid) {
|
|
case Php_tkn_.Tid_declaration: case Php_tkn_.Tid_comment: case Php_tkn_.Tid_ws: // always discard, regardless of mode
|
|
return;
|
|
}
|
|
switch (mode) {
|
|
case Mode_expect: // handles sequences like "array("
|
|
if (tkn_tid == next_tid)
|
|
mode = next_mode;
|
|
else {
|
|
Msg_many(src, tkn.Src_bgn(), tkn.Src_end(), Expecting_itm_failed, Php_tkn_.Xto_str(next_tid), Php_tkn_.Xto_str(tkn_tid));
|
|
Fail();
|
|
}
|
|
break;
|
|
case Mode_suspend:
|
|
if (tkn_tid == Php_tkn_.Tid_semic) mode = Mode_key_bgn;
|
|
break;
|
|
case Mode_key_bgn:
|
|
if (tkn_tid == Php_tkn_.Tid_var) {
|
|
cur_ary = null;
|
|
cur_line = new Php_line_assign();
|
|
lines.Add(cur_line);
|
|
|
|
Php_tkn_var var_tkn = (Php_tkn_var)tkn;
|
|
cur_line.Key_(new Php_itm_var(var_tkn.Var_name(src)));
|
|
|
|
mode = Mode_key_end;
|
|
}
|
|
else {
|
|
Msg_many(src, tkn.Src_bgn(), tkn.Src_end(), Expecting_itm_failed, Php_tkn_.Xto_str(Php_tkn_.Tid_var), Php_tkn_.Xto_str(tkn_tid));
|
|
Fail();
|
|
}
|
|
break;
|
|
case Mode_key_end:
|
|
switch (tkn_tid) {
|
|
case Php_tkn_.Tid_eq: mode = Mode_val; break;
|
|
case Php_tkn_.Tid_brack_bgn: mode = Mode_brack_itm; break;
|
|
case Php_tkn_.Tid_brack_end: Expect(Php_tkn_.Tid_eq, Mode_val); break;
|
|
default: {
|
|
Msg_many(src, tkn.Src_bgn(), tkn.Src_end(), Expecting_itm_failed, Php_tkn_.Xto_str(Php_tkn_.Tid_var), Php_tkn_.Xto_str(tkn_tid));
|
|
Fail();
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case Mode_brack_itm:
|
|
switch (tkn_tid) {
|
|
case Php_tkn_.Tid_quote:
|
|
Php_tkn_quote tkn_quote = (Php_tkn_quote)tkn;
|
|
Php_itm_quote key_sub = new Php_itm_quote(tkn_quote.Quote_text(src));
|
|
cur_line.Key_subs_(new Php_key[] {key_sub});
|
|
mode = Mode_key_end;
|
|
break;
|
|
default: {
|
|
Msg_many(src, tkn.Src_bgn(), tkn.Src_end(), Expecting_itm_failed, Php_tkn_.Xto_str(Php_tkn_.Tid_var), Php_tkn_.Xto_str(tkn_tid));
|
|
Fail();
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case Mode_val:
|
|
Php_itm line_val = null;
|
|
switch (tkn_tid) {
|
|
case Php_tkn_.Tid_null: Expect(Php_tkn_.Tid_semic, Mode_key_bgn); line_val = Php_itm_null._; break;
|
|
case Php_tkn_.Tid_false: Expect(Php_tkn_.Tid_semic, Mode_key_bgn); line_val = Php_itm_bool_false._; break;
|
|
case Php_tkn_.Tid_true: Expect(Php_tkn_.Tid_semic, Mode_key_bgn); line_val = Php_itm_bool_true._; break;
|
|
case Php_tkn_.Tid_quote:
|
|
Expect(Php_tkn_.Tid_semic, Mode_key_bgn);
|
|
Php_tkn_quote tkn_quote = (Php_tkn_quote)tkn;
|
|
line_val = new Php_itm_quote(tkn_quote.Quote_text(src));
|
|
break;
|
|
case Php_tkn_.Tid_ary:
|
|
Expect(Php_tkn_.Tid_paren_bgn, Mode_ary_subs);
|
|
Php_itm_ary ary = new Php_itm_ary();
|
|
if (cur_ary == null)
|
|
line_val = ary;
|
|
else {
|
|
cur_ary.Subs_add(ary);
|
|
frame_stack.Add(new Php_scanner_frame(cur_ary));
|
|
cur_kv_key = null;
|
|
}
|
|
this.cur_ary = ary;
|
|
break;
|
|
case Php_tkn_.Tid_txt:
|
|
case Php_tkn_.Tid_var:
|
|
break;
|
|
case Php_tkn_.Tid_eq:
|
|
case Php_tkn_.Tid_eq_kv:
|
|
case Php_tkn_.Tid_semic:
|
|
case Php_tkn_.Tid_comma:
|
|
case Php_tkn_.Tid_paren_bgn:
|
|
case Php_tkn_.Tid_paren_end:
|
|
case Php_tkn_.Tid_num:
|
|
break;
|
|
}
|
|
cur_line.Val_(line_val);
|
|
break;
|
|
case Mode_ary_subs:
|
|
switch (tkn_tid) {
|
|
case Php_tkn_.Tid_null: Ary_add_itm(Php_itm_null._); break;
|
|
case Php_tkn_.Tid_false: Ary_add_itm(Php_itm_bool_false._); break;
|
|
case Php_tkn_.Tid_true: Ary_add_itm(Php_itm_bool_true._); break;
|
|
case Php_tkn_.Tid_quote:
|
|
Php_tkn_quote tkn_quote = (Php_tkn_quote)tkn;
|
|
Ary_add_itm(new Php_itm_quote(tkn_quote.Quote_text(src)));
|
|
break;
|
|
case Php_tkn_.Tid_num:
|
|
Php_tkn_num tkn_num = (Php_tkn_num)tkn;
|
|
Ary_add_itm(new Php_itm_int(tkn_num.Num_val_int(src)));
|
|
break;
|
|
case Php_tkn_.Tid_var:
|
|
Php_tkn_var tkn_var = (Php_tkn_var)tkn;
|
|
Ary_add_itm(new Php_itm_var(Bry_.Mid(src, tkn_var.Src_bgn(), tkn_var.Src_end())));
|
|
break;
|
|
case Php_tkn_.Tid_txt:
|
|
Php_tkn_txt tkn_txt = (Php_tkn_txt)tkn;
|
|
Ary_add_itm(new Php_itm_var(Bry_.Mid(src, tkn_txt.Src_bgn(), tkn_txt.Src_end())));
|
|
break;
|
|
case Php_tkn_.Tid_ary:
|
|
Expect(Php_tkn_.Tid_paren_bgn, Mode_ary_subs);
|
|
Php_itm_ary ary = new Php_itm_ary();
|
|
if (cur_ary == null)
|
|
line_val = ary;
|
|
else {
|
|
frame_stack.Add(new Php_scanner_frame(cur_ary));
|
|
if (cur_kv_key == null)
|
|
cur_ary.Subs_add(ary);
|
|
else {
|
|
Php_itm_kv ary_itm = new Php_itm_kv().Key_(cur_kv_key).Val_(ary);
|
|
cur_ary.Subs_add(ary_itm);
|
|
cur_kv_key = null;
|
|
}
|
|
}
|
|
this.cur_ary = ary;
|
|
break;
|
|
case Php_tkn_.Tid_paren_end:
|
|
mode = Mode_ary_term;
|
|
if (frame_stack.Count() == 0)
|
|
cur_ary = null;
|
|
else {
|
|
Php_scanner_frame frame = (Php_scanner_frame)ListAdp_.Pop(frame_stack);
|
|
cur_ary = frame.Ary();
|
|
frame.Rls();
|
|
}
|
|
break;
|
|
case Php_tkn_.Tid_semic: // NOTE: will occur in following construct array(array());
|
|
mode = Mode_key_bgn;
|
|
break;
|
|
case Php_tkn_.Tid_eq:
|
|
case Php_tkn_.Tid_eq_kv:
|
|
case Php_tkn_.Tid_comma:
|
|
case Php_tkn_.Tid_paren_bgn:
|
|
break;
|
|
}
|
|
break;
|
|
case Mode_ary_dlm:
|
|
switch (tkn_tid) {
|
|
case Php_tkn_.Tid_comma:
|
|
mode = Mode_ary_subs;
|
|
break;
|
|
case Php_tkn_.Tid_paren_end:
|
|
mode = Mode_ary_term;
|
|
if (frame_stack.Count() == 0)
|
|
cur_ary = null;
|
|
else {
|
|
Php_scanner_frame frame = (Php_scanner_frame)ListAdp_.Pop(frame_stack);
|
|
cur_ary = frame.Ary();
|
|
frame.Rls();
|
|
}
|
|
break;
|
|
case Php_tkn_.Tid_eq_kv:
|
|
Php_itm_sub tmp_key = cur_ary.Subs_pop();
|
|
cur_kv_key = (Php_key)tmp_key;
|
|
mode = Mode_ary_subs;
|
|
break;
|
|
}
|
|
break;
|
|
case Mode_ary_term:
|
|
switch (tkn_tid) {
|
|
case Php_tkn_.Tid_comma:
|
|
case Php_tkn_.Tid_paren_end: // NOTE: paren_end occurs in multiple nests; EX: array(array())
|
|
mode = Mode_ary_subs;
|
|
break;
|
|
case Php_tkn_.Tid_semic:
|
|
mode = Mode_key_bgn;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
private void Fail() {mode = Mode_suspend;}
|
|
private void Ary_add_itm(Php_itm val) {
|
|
mode = Mode_ary_dlm;
|
|
if (cur_kv_key == null)
|
|
cur_ary.Subs_add((Php_itm_sub)val);
|
|
else {
|
|
Php_itm_kv ary_itm = new Php_itm_kv().Key_(cur_kv_key).Val_(val);
|
|
cur_ary.Subs_add(ary_itm);
|
|
cur_kv_key = null;
|
|
}
|
|
}
|
|
private void Expect(byte next_tid, byte next_mode) {
|
|
mode = Mode_expect;
|
|
this.next_tid = next_tid;
|
|
this.next_mode = next_mode;
|
|
}
|
|
public void Msg_many(byte[] src, int bgn, int end, Gfo_msg_itm itm, Object... args) {
|
|
msg_log.Add_itm_many(itm, src, bgn, end, args);
|
|
}
|
|
public static final Gfo_msg_itm Expecting_itm_failed = Gfo_msg_itm_.new_warn_(Php_parser.Log_nde, "expecting_itm_failed", "expecting_itm ~{0} but got ~{1} instead");
|
|
private static final byte Mode_key_bgn = 1, Mode_key_end = 2, Mode_expect = 3, Mode_suspend = 4, Mode_val = 5, Mode_ary_subs = 6, Mode_ary_dlm = 7, Mode_ary_term = 8, Mode_brack_itm = 9;
|
|
}
|
|
class Php_scanner_frame {
|
|
public Php_scanner_frame(Php_itm_ary ary) {this.ary = ary;}
|
|
public Php_itm_ary Ary() {return ary;} Php_itm_ary ary;
|
|
public void Rls() {ary = null;}
|
|
}
|
|
class Php_parser_interrupt {
|
|
public static final Php_parser_interrupt Char = new Php_parser_interrupt();
|
|
}
|
|
|