1
0
mirror of https://github.com/gnosygnu/xowa.git synced 2026-03-02 03:49:30 +00:00
Files
gnosygnu_xowa/400_xowa/src/gplx/php/Php_evaluator.java

263 lines
9.2 KiB
Java
Raw Normal View History

2014-06-30 00:04:32 -04: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/>.
*/
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");
2015-02-22 21:03:49 -05:00
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;
2014-06-30 00:04:32 -04:00
}
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();
}