mirror of
https://github.com/gnosygnu/xowa.git
synced 2024-09-29 23:10:52 +00:00
XomwTemplateParser: Port XomwPreprocessor classes as direct translation of MW code [#632]
This commit is contained in:
parent
17d7a7ebed
commit
7ad1291768
@ -28,6 +28,7 @@ public class Int_ {
|
|||||||
, Null = Int_.Min_value
|
, Null = Int_.Min_value
|
||||||
, Base1 = 1 // for super 1 lists / arrays; EX: PHP; [a, b, c]; [1] => a
|
, Base1 = 1 // for super 1 lists / arrays; EX: PHP; [a, b, c]; [1] => a
|
||||||
, Offset_1 = 1 // common symbol for + 1 after current pos; EX: String_.Mid(lhs + Offset_1, rhs)
|
, Offset_1 = 1 // common symbol for + 1 after current pos; EX: String_.Mid(lhs + Offset_1, rhs)
|
||||||
|
, Zero = 0
|
||||||
;
|
;
|
||||||
|
|
||||||
public static int Cast(Object obj) {
|
public static int Cast(Object obj) {
|
||||||
|
@ -33,6 +33,7 @@ public class XophpArray implements Bry_bfr_able {
|
|||||||
int len = hash.Len();
|
int len = hash.Len();
|
||||||
return len == 0 ? null : ((XophpArrayItm)hash.Get_at(len - 1)).Val();
|
return len == 0 ? null : ((XophpArrayItm)hash.Get_at(len - 1)).Val();
|
||||||
}
|
}
|
||||||
|
public boolean Eq_to_new() {return hash.Count() == 0;}// same as "array === []"
|
||||||
public void unset(int key) {unset(Int_.To_str(key));}
|
public void unset(int key) {unset(Int_.To_str(key));}
|
||||||
public void unset(String key) {
|
public void unset(String key) {
|
||||||
hash.Del(key);
|
hash.Del(key);
|
||||||
@ -103,9 +104,17 @@ public class XophpArray implements Bry_bfr_able {
|
|||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
public void Concat_str(int i, String s) {
|
||||||
|
this.Set(i, this.Get_at_str(i) + s);
|
||||||
|
}
|
||||||
|
public XophpArray Get_at_ary_or_null(int i) {
|
||||||
|
Object rv = Get_at(i);
|
||||||
|
return Type_.Eq_by_obj(rv, XophpArray.class) ? (XophpArray)rv : null;
|
||||||
|
}
|
||||||
public XophpArray Get_at_ary(int i) {return (XophpArray)Get_at(i);}
|
public XophpArray Get_at_ary(int i) {return (XophpArray)Get_at(i);}
|
||||||
public String Get_at_str(int i) {return (String)Get_at(i);}
|
public boolean Get_at_bool(int i) {return Bool_.Cast(Get_at(i));}
|
||||||
public int Get_at_int(int i) {return Int_.Cast(Get_at(i));}
|
public int Get_at_int(int i) {return Int_.Cast(Get_at(i));}
|
||||||
|
public String Get_at_str(int i) {return (String)Get_at(i);}
|
||||||
public Object Get_at(int i) {
|
public Object Get_at(int i) {
|
||||||
if (i < 0 || i >= hash.Len()) return null;
|
if (i < 0 || i >= hash.Len()) return null;
|
||||||
XophpArrayItm itm = (XophpArrayItm)hash.Get_at(i);
|
XophpArrayItm itm = (XophpArrayItm)hash.Get_at(i);
|
||||||
@ -123,10 +132,15 @@ public class XophpArray implements Bry_bfr_able {
|
|||||||
}
|
}
|
||||||
public Object Get_by_obj(Object key) {return Get_by(Object_.Xto_str_strict_or_null(key));}
|
public Object Get_by_obj(Object key) {return Get_by(Object_.Xto_str_strict_or_null(key));}
|
||||||
public Object Get_by(int key) {return Get_by(Int_.To_str(key));}
|
public Object Get_by(int key) {return Get_by(Int_.To_str(key));}
|
||||||
|
public boolean Get_by_bool_or(String key, boolean or) {Object rv = this.Get_by(key); return rv == null ? or : Bool_.Cast(rv);}
|
||||||
public boolean Get_by_bool(String key) {return Bool_.Cast(this.Get_by(key));}
|
public boolean Get_by_bool(String key) {return Bool_.Cast(this.Get_by(key));}
|
||||||
|
public int Get_by_int_or(String key, int or) {Object rv = this.Get_by(key); return rv == null ? or : Int_.Cast(rv);}
|
||||||
public int Get_by_int(String key) {return Int_.Cast(this.Get_by(key));}
|
public int Get_by_int(String key) {return Int_.Cast(this.Get_by(key));}
|
||||||
|
public XophpArray Get_by_ary_or(String key, XophpArray or) {Object rv = this.Get_by(key); return rv == null ? or : (XophpArray)rv;}
|
||||||
public XophpArray Get_by_ary(String key) {return (XophpArray)this.Get_by(key);}
|
public XophpArray Get_by_ary(String key) {return (XophpArray)this.Get_by(key);}
|
||||||
public String Get_by_str(char key) {return (String)this.Get_by(Char_.To_str(key));}
|
public String Get_by_str(char key) {return (String)this.Get_by(Char_.To_str(key));}
|
||||||
|
public String Get_by_str(int key) {return (String)this.Get_by(Int_.To_str(key));}
|
||||||
|
public String Get_by_str_or(String key, String or) {Object rv = this.Get_by(key); return rv == null ? or : (String)rv;}
|
||||||
public String Get_by_str(String key) {return (String)this.Get_by(key);}
|
public String Get_by_str(String key) {return (String)this.Get_by(key);}
|
||||||
public Object Get_by(String key) {
|
public Object Get_by(String key) {
|
||||||
XophpArrayItm itm = (XophpArrayItm)hash.Get_by(key);
|
XophpArrayItm itm = (XophpArrayItm)hash.Get_by(key);
|
||||||
@ -180,6 +194,35 @@ public class XophpArray implements Bry_bfr_able {
|
|||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@Override public boolean equals(Object obj) {
|
||||||
|
if (obj == null) return false;
|
||||||
|
if (!Type_.Eq_by_obj(obj, XophpArray.class)) return false;
|
||||||
|
XophpArray comp = (XophpArray)obj;
|
||||||
|
|
||||||
|
// compare lens
|
||||||
|
int this_len = this.Len();
|
||||||
|
int comp_len = comp.Len();
|
||||||
|
if (this_len != comp_len) return false;
|
||||||
|
|
||||||
|
// loop items
|
||||||
|
for (int i = 0; i < this_len; i++) {
|
||||||
|
XophpArrayItm this_itm = this.Get_at_itm(i);
|
||||||
|
XophpArrayItm comp_itm = comp.Get_at_itm(i);
|
||||||
|
if (!Object_.Eq(this_itm, comp_itm))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@Override public int hashCode() {
|
||||||
|
int rv = 0;
|
||||||
|
int len = this.Len();
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
XophpArrayItm itm = this.Get_at_itm(i);
|
||||||
|
rv = (31 * rv) + itm.hashCode();
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
public static XophpArray New(Object... vals) {
|
public static XophpArray New(Object... vals) {
|
||||||
XophpArray rv = new XophpArray();
|
XophpArray rv = new XophpArray();
|
||||||
for (Object val : vals)
|
for (Object val : vals)
|
||||||
|
@ -39,6 +39,36 @@ public class XophpArrayItm implements Bry_bfr_able {
|
|||||||
bfr.Add_obj(val).Add_byte_space();
|
bfr.Add_obj(val).Add_byte_space();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Override public boolean equals(Object obj) {
|
||||||
|
if (obj == null) return false;
|
||||||
|
XophpArrayItm comp = (XophpArrayItm)obj;
|
||||||
|
|
||||||
|
// compare key
|
||||||
|
if (key_is_int) {
|
||||||
|
if (this.key_as_int != comp.key_as_int)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!String_.Eq(this.key, comp.key))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compare val
|
||||||
|
if (this.val == null && comp.val != null)
|
||||||
|
return false;
|
||||||
|
else if (this.val != null && comp.val == null)
|
||||||
|
return false;
|
||||||
|
else if (this.val == null && comp.val == null)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return Object_.Eq(this.val, comp.val);
|
||||||
|
}
|
||||||
|
@Override public int hashCode() {
|
||||||
|
int rv = 0;
|
||||||
|
rv = (31 * rv) + (key_is_int ? key_as_int : key.hashCode());
|
||||||
|
rv = (31 * rv) + val.hashCode();
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
public static XophpArrayItm New_int(int key, Object val) {return new XophpArrayItm(Bool_.Y, key, Int_.To_str(key), val);}
|
public static XophpArrayItm New_int(int key, Object val) {return new XophpArrayItm(Bool_.Y, key, Int_.To_str(key), val);}
|
||||||
public static XophpArrayItm New_str(String key, Object val) {return new XophpArrayItm(Bool_.N, -1, key , val);}
|
public static XophpArrayItm New_str(String key, Object val) {return new XophpArrayItm(Bool_.N, -1, key , val);}
|
||||||
|
@ -152,6 +152,11 @@ public class XophpArray_ {
|
|||||||
public static boolean array_is_empty(Ordered_hash array) {
|
public static boolean array_is_empty(Ordered_hash array) {
|
||||||
return array.Len() == 0;
|
return array.Len() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean array_key_exists(String key, XophpArray array) {return array.Has(key);}
|
||||||
|
public static boolean array_key_exists(int key, XophpArray array) {return array.Has(Int_.To_str(key));}
|
||||||
|
|
||||||
|
public static void unset(XophpArray array, int i) {array.unset(i);}
|
||||||
public static void unset(Ordered_hash array, Object key) {
|
public static void unset(Ordered_hash array, Object key) {
|
||||||
array.Del(key);
|
array.Del(key);
|
||||||
}
|
}
|
||||||
@ -164,12 +169,6 @@ public class XophpArray_ {
|
|||||||
rv[i - 1] = ary[i];
|
rv[i - 1] = ary[i];
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
public static boolean in_array(String needle, String[] haystack) {
|
|
||||||
for (String hay : haystack)
|
|
||||||
if (String_.Eq(hay, needle))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// REF.PHP:https://www.php.net/manual/en/function.array-map.php
|
// REF.PHP:https://www.php.net/manual/en/function.array-map.php
|
||||||
public static XophpArray array_map(XophpCallbackOwner callback_owner, String method, XophpArray array) {
|
public static XophpArray array_map(XophpCallbackOwner callback_owner, String method, XophpArray array) {
|
||||||
@ -204,7 +203,47 @@ public class XophpArray_ {
|
|||||||
return sb.To_str_and_clear();
|
return sb.To_str_and_clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int count(XophpArray array) {
|
public static int count(XophpArray array) {return array.count();}
|
||||||
return array.count();
|
public static boolean count_bool(XophpArray array) {return array.count_bool();}
|
||||||
|
public static Object array_pop(XophpArray array) {return array.pop();}
|
||||||
|
public static boolean isset(XophpArray array, int key) {return XophpObject_.isset_obj(array.Get_at(key));}
|
||||||
|
public static boolean isset(XophpArray array, String key) {return XophpObject_.isset_obj(array.Get_by(key));}
|
||||||
|
public static boolean is_array(XophpArray array) {return array != null;}
|
||||||
|
|
||||||
|
// REF.PHP: https://www.php.net/manual/en/function.in-array.php
|
||||||
|
public static boolean in_array(Object needle, XophpArray haystack) {return in_array(needle, haystack, false);}
|
||||||
|
public static boolean in_array(Object needle, XophpArray haystack, boolean strict) {
|
||||||
|
// if strict, cache needleType
|
||||||
|
Class<?> needleType = null;
|
||||||
|
if (strict && needle != null) {
|
||||||
|
needleType = Type_.Type_by_obj(needle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop haystack to find match
|
||||||
|
int haystack_len = haystack.Len();
|
||||||
|
for (int i = 0; i < haystack_len; i++) {
|
||||||
|
Object val = haystack.Get_at(i);
|
||||||
|
|
||||||
|
// if strict, compare types
|
||||||
|
if (strict) {
|
||||||
|
if (needle != null && val == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (needle == null && val != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (needle != null && val != null) {
|
||||||
|
if (!Type_.Eq_by_obj(val, needleType)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compare objects
|
||||||
|
if (Object_.Eq(needle, val)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -257,6 +257,25 @@ public class XophpArray__tst { // REF:https://www.php.net/manual/en/function.arr
|
|||||||
, XophpArray_.implode(" ", orig)
|
, XophpArray_.implode(" ", orig)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@Test public void in_array() {
|
||||||
|
// PHP samples
|
||||||
|
XophpArray array;
|
||||||
|
// Example #1
|
||||||
|
array = XophpArray.New("Mac", "NT", "Irix", "Linux");
|
||||||
|
Gftest.Eq__bool(Bool_.Y, XophpArray_.in_array("Irix", array));
|
||||||
|
Gftest.Eq__bool(Bool_.N, XophpArray_.in_array("mac" , array));
|
||||||
|
|
||||||
|
// Example #2
|
||||||
|
array = XophpArray.New(12.4d, 1.13d);
|
||||||
|
Gftest.Eq__bool(Bool_.N, XophpArray_.in_array("12.4", array, true));
|
||||||
|
Gftest.Eq__bool(Bool_.Y, XophpArray_.in_array( 1.13d, array, true));
|
||||||
|
|
||||||
|
// Example #3
|
||||||
|
array = XophpArray.New(XophpArray.New('p', 'h'), XophpArray.New('p', 'r'), 'o');
|
||||||
|
Gftest.Eq__bool(Bool_.Y, XophpArray_.in_array(XophpArray.New('p', 'h'), array));
|
||||||
|
Gftest.Eq__bool(Bool_.N, XophpArray_.in_array(XophpArray.New('f', 'i'), array));
|
||||||
|
Gftest.Eq__bool(Bool_.Y, XophpArray_.in_array('o', array));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
class XophpArray__fxt {
|
class XophpArray__fxt {
|
||||||
public XophpArray Make() {return new XophpArray();}
|
public XophpArray Make() {return new XophpArray();}
|
||||||
|
@ -15,6 +15,7 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
|||||||
*/
|
*/
|
||||||
package gplx.xowa.mediawiki; import gplx.*; import gplx.xowa.*;
|
package gplx.xowa.mediawiki; import gplx.*; import gplx.xowa.*;
|
||||||
public class XophpBool_ {
|
public class XophpBool_ {
|
||||||
|
public static final boolean Null = false;
|
||||||
public static boolean is_true(byte[] val) {return val != null && is_true(String_.new_u8(val));}
|
public static boolean is_true(byte[] val) {return val != null && is_true(String_.new_u8(val));}
|
||||||
public static boolean is_true(String val) {
|
public static boolean is_true(String val) {
|
||||||
// REF: https://www.php.net/manual/en/language.types.boolean.php#language.types.boolean.casting
|
// REF: https://www.php.net/manual/en/language.types.boolean.php#language.types.boolean.casting
|
||||||
|
20
400_xowa/src/gplx/xowa/mediawiki/XophpDouble_.java
Normal file
20
400_xowa/src/gplx/xowa/mediawiki/XophpDouble_.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
package gplx.xowa.mediawiki; import gplx.*; import gplx.xowa.*;
|
||||||
|
public class XophpDouble_ {
|
||||||
|
public static int intval(double val) {return (int)val;}
|
||||||
|
}
|
||||||
|
|
@ -16,7 +16,8 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
|||||||
package gplx.xowa.mediawiki; import gplx.*; import gplx.xowa.*;
|
package gplx.xowa.mediawiki; import gplx.*; import gplx.xowa.*;
|
||||||
public class XophpInt_ {
|
public class XophpInt_ {
|
||||||
public static final int False = 0; // REF.PHP:https://www.php.net/manual/en/language.types.boolean.php
|
public static final int False = 0; // REF.PHP:https://www.php.net/manual/en/language.types.boolean.php
|
||||||
public static boolean is_true(int val) {return val != -1;} // handles code like "if ($var === false)" where var is an Object;
|
public static boolean is_true(int val) {return val != 0;} // handles code like "if ($var)" where var is an Object;
|
||||||
|
public static boolean is_false(int val) {return val < 0;} // handles XophpInt_.False as well as strpos.notFound (-1)
|
||||||
public static String strval(int number) {
|
public static String strval(int number) {
|
||||||
return Int_.To_str(number);
|
return Int_.To_str(number);
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ package gplx.xowa.mediawiki; import gplx.*; import gplx.xowa.*;
|
|||||||
public class XophpObject_ {
|
public class XophpObject_ {
|
||||||
public static final Object False = null; // handles code like "if ($var === false)" where var is an Object;
|
public static final Object False = null; // handles code like "if ($var === false)" where var is an Object;
|
||||||
public static boolean is_true(Object val) {return val != null;}
|
public static boolean is_true(Object val) {return val != null;}
|
||||||
|
public static boolean is_false(Object val) {return val == null;}
|
||||||
public static boolean is_null(Object val) {return val == null;}
|
public static boolean is_null(Object val) {return val == null;}
|
||||||
|
|
||||||
// REF.PHP:http://php.net/manual/en/function.empty.php
|
// REF.PHP:http://php.net/manual/en/function.empty.php
|
||||||
|
@ -17,8 +17,25 @@ package gplx.xowa.mediawiki; import gplx.*; import gplx.xowa.*;
|
|||||||
import gplx.langs.regxs.*;
|
import gplx.langs.regxs.*;
|
||||||
import gplx.core.strings.*; import gplx.core.primitives.*; import gplx.core.bits.*;
|
import gplx.core.strings.*; import gplx.core.primitives.*; import gplx.core.bits.*;
|
||||||
public class XophpRegex_ {
|
public class XophpRegex_ {
|
||||||
|
// REF.PHP: https://www.php.net/manual/en/function.preg-quote.php
|
||||||
|
// The special regular expression characters are:
|
||||||
|
private static final Hash_adp preg_quote_hash = Hash_adp_.New().Add_many_as_key_and_val
|
||||||
|
('.', '\\', '+', '*', '?', '[', '^', ']', '$', '(', ')', '{', '}', '=', '!', '<', '>', '|', ':', '-', '#');
|
||||||
|
public static String preg_quote(String str, String delimiter) {// NOTE: "String delimiter" not used b/c Java / XO does not allow symbolic quotes; EX: "/abc/i"
|
||||||
|
String_bldr sb = String_bldr_.new_();
|
||||||
|
int len = String_.Len(str);
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
char c = String_.CharAt(str, i);
|
||||||
|
if (preg_quote_hash.Has(c)) {
|
||||||
|
sb.Add("\\");
|
||||||
|
}
|
||||||
|
sb.Add(c);
|
||||||
|
}
|
||||||
|
return sb.To_str_and_clear();
|
||||||
|
}
|
||||||
public static boolean preg_match_bool(Regx_adp pattern, int modifier, String subject) {return preg_match_bool(pattern, modifier, subject, null, 0, 0);}
|
public static boolean preg_match_bool(Regx_adp pattern, int modifier, String subject) {return preg_match_bool(pattern, modifier, subject, null, 0, 0);}
|
||||||
public static boolean preg_match_bool(Regx_adp pattern, String subject, XophpArray matches, int flags, int offset) {return preg_match(pattern, MODIFIER_NONE, subject, matches, flags, offset) == FOUND;}
|
public static boolean preg_match_bool(Regx_adp pattern, String subject, XophpArray matches, int flags, int offset) {return preg_match(pattern, MODIFIER_NONE, subject, matches, flags, offset) == FOUND;}
|
||||||
|
public static boolean preg_match_bool(String pattern, int modifier, String subject, XophpArray matches, int flags, int offset) {return preg_match(Regx_adp_.new_(pattern), modifier, subject, matches, flags, offset) == FOUND;}
|
||||||
public static boolean preg_match_bool(Regx_adp pattern, int modifier, String subject, XophpArray matches, int flags, int offset) {return preg_match(pattern, modifier, subject, matches, flags, offset) == FOUND;}
|
public static boolean preg_match_bool(Regx_adp pattern, int modifier, String subject, XophpArray matches, int flags, int offset) {return preg_match(pattern, modifier, subject, matches, flags, offset) == FOUND;}
|
||||||
public static int preg_match(Regx_adp pattern, String subject) {return preg_match(pattern, MODIFIER_NONE, subject, null, 0, 0);}
|
public static int preg_match(Regx_adp pattern, String subject) {return preg_match(pattern, MODIFIER_NONE, subject, null, 0, 0);}
|
||||||
public static int preg_match(Regx_adp pattern, int modifier, String subject) {return preg_match(pattern, modifier, subject, null, 0, 0);}
|
public static int preg_match(Regx_adp pattern, int modifier, String subject) {return preg_match(pattern, modifier, subject, null, 0, 0);}
|
||||||
@ -61,8 +78,8 @@ public class XophpRegex_ {
|
|||||||
private static void preg_match_fill(String subject, XophpArray matches, int flags, Regx_match match, String match_str, Regx_group[] grps, int grps_len) {
|
private static void preg_match_fill(String subject, XophpArray matches, int flags, Regx_match match, String match_str, Regx_group[] grps, int grps_len) {
|
||||||
for (int i = 0; i < grps_len; i++) {
|
for (int i = 0; i < grps_len; i++) {
|
||||||
Regx_group grp = grps[i];
|
Regx_group grp = grps[i];
|
||||||
if (!grp.Rslt()) continue; // ignore non matches in group; EX: "1" and "^-?(([0-9]+)(?:\\.([0-9]+))?)" returns a match=false for group(2)
|
// TOMBSTONE: if (!grp.Rslt()) continue; // ignore non matches in group; EX: "1" and "^-?(([0-9]+)(?:\\.([0-9]+))?)" returns a match=false for group(2)
|
||||||
String grp_match = grp.Val();
|
String grp_match = grp.Rslt() ? grp.Val() : "";
|
||||||
if (flags == PREG_OFFSET_CAPTURE) {
|
if (flags == PREG_OFFSET_CAPTURE) {
|
||||||
matches.Add(XophpArray.New(grp_match, grp.Bgn()));
|
matches.Add(XophpArray.New(grp_match, grp.Bgn()));
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,10 @@ public class XophpRegex__tst {
|
|||||||
.Add("baz")
|
.Add("baz")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@Test public void preg_quote() {
|
||||||
|
Gftest.Eq__str("abc", XophpRegex_.preg_quote("abc", "/"));
|
||||||
|
Gftest.Eq__str("\\.\\\\\\+\\*\\?\\[\\^\\]\\$\\(\\)\\{\\}\\=\\!\\<\\>\\|\\:\\-\\#", XophpRegex_.preg_quote(".\\+*?[^]$(){}=!<>|:-#", "/"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
class XophpRegex__fxt {
|
class XophpRegex__fxt {
|
||||||
private String_bldr print_php = null;//String_bldr_.new_();
|
private String_bldr print_php = null;//String_bldr_.new_();
|
||||||
|
21
400_xowa/src/gplx/xowa/mediawiki/XophpStringRef.java
Normal file
21
400_xowa/src/gplx/xowa/mediawiki/XophpStringRef.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
package gplx.xowa.mediawiki; import gplx.*; import gplx.xowa.*;
|
||||||
|
public class XophpStringRef {
|
||||||
|
private String val;
|
||||||
|
public XophpStringRef(String val) {this.val = val;}
|
||||||
|
public String Get() {return val;}
|
||||||
|
}
|
@ -18,9 +18,13 @@ import gplx.core.btries.*;
|
|||||||
import gplx.core.intls.*;
|
import gplx.core.intls.*;
|
||||||
import gplx.objects.strings.unicodes.*;
|
import gplx.objects.strings.unicodes.*;
|
||||||
import gplx.core.primitives.*;
|
import gplx.core.primitives.*;
|
||||||
|
import gplx.objects.strings.bfrs.*;
|
||||||
public class XophpString_ implements XophpCallbackOwner {
|
public class XophpString_ implements XophpCallbackOwner {
|
||||||
public static final String False = null;
|
public static final String False = null;
|
||||||
public static boolean is_true(String s) {return s != null;} // handles code like "if ($var)" where var is an Object;
|
public static boolean is_true (String s) {return s != null;} // handles code like "if ($var)" where var is an Object;
|
||||||
|
public static boolean is_false(String s) {return s == null;}
|
||||||
|
public static boolean eq(String lhs, String rhs) {return String_.Eq(lhs, rhs);}
|
||||||
|
public static boolean eq_not(String lhs, String rhs) {return !String_.Eq(lhs, rhs);}
|
||||||
|
|
||||||
// REF.PHP: https://www.php.net/manual/en/function.strpos.php
|
// REF.PHP: https://www.php.net/manual/en/function.strpos.php
|
||||||
public static int strpos(String haystack, String needle) {return strpos(haystack, needle, 0);}
|
public static int strpos(String haystack, String needle) {return strpos(haystack, needle, 0);}
|
||||||
@ -80,16 +84,36 @@ public class XophpString_ implements XophpCallbackOwner {
|
|||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
public static int strspn(String subject, Hash_adp mask, int start) {return strspn(subject, mask, start, Int_.Null);}
|
public static int strspn(String subject, Hash_adp mask, int start) {return strspn(subject, mask, start, Int_.Zero);}
|
||||||
public static int strspn(String subject, Hash_adp mask, int start, int length) {
|
public static int strspn(String subject, Hash_adp mask, int start, int length) {
|
||||||
int subject_len = String_.Len(subject);
|
int subject_len = String_.Len(subject);
|
||||||
|
start = strspn__start(start, subject_len);
|
||||||
// get subject_end
|
int subject_end = strspn__subject_end(start, length, subject_len);
|
||||||
|
return strspn__rslt(Bool_.Y, subject, mask, start, subject_end);
|
||||||
|
}
|
||||||
|
// REF.PHP:https://www.php.net/manual/en/function.strcspn.php
|
||||||
|
public static int strcspn(String subject, Hash_adp mask) {return strcspn(subject, mask, Int_.Zero, Int_.Zero);}
|
||||||
|
public static int strcspn(String subject, Hash_adp mask, int start) {return strcspn(subject, mask, start, Int_.Zero);}
|
||||||
|
public static int strcspn(String subject, Hash_adp mask, int start, int length) {
|
||||||
|
int subject_len = String_.Len(subject);
|
||||||
|
start = strspn__start(start, subject_len);
|
||||||
|
int subject_end = strspn__subject_end(start, length, subject_len);
|
||||||
|
return strspn__rslt(Bool_.N, subject, mask, start, subject_end);
|
||||||
|
}
|
||||||
|
private static int strspn__start(int start, int subject_len) {
|
||||||
|
if (start < 0) { // adjust start if -1
|
||||||
|
start = subject_len + start;
|
||||||
|
if (start < 0)
|
||||||
|
start = 0;
|
||||||
|
}
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
private static int strspn__subject_end(int start, int length, int subject_len) {
|
||||||
int subject_end = 0;
|
int subject_end = 0;
|
||||||
if (length == Int_.Null) {
|
if (length == Int_.Zero) {
|
||||||
subject_end = subject_len;
|
subject_end = subject_len;
|
||||||
}
|
}
|
||||||
else if (length < 0) {
|
else if (length < Int_.Zero) {
|
||||||
subject_end = subject_len + length; // If length is given and is negative, then subject will be examined from the starting position up to length characters from the end of subject.
|
subject_end = subject_len + length; // If length is given and is negative, then subject will be examined from the starting position up to length characters from the end of subject.
|
||||||
if (subject_end < start)
|
if (subject_end < start)
|
||||||
subject_end = start;
|
subject_end = start;
|
||||||
@ -99,9 +123,11 @@ public class XophpString_ implements XophpCallbackOwner {
|
|||||||
if (subject_end > subject_len)
|
if (subject_end > subject_len)
|
||||||
subject_end = subject_len;
|
subject_end = subject_len;
|
||||||
}
|
}
|
||||||
|
return subject_end;
|
||||||
|
}
|
||||||
|
private static int strspn__rslt(boolean is_strspn, String subject, Hash_adp mask, int start, int subject_end) {
|
||||||
// loop subject until encountering character not in mask
|
// loop subject until encountering character not in mask
|
||||||
int rv = 0;
|
int strspn_rv = 0;
|
||||||
int i = start;
|
int i = start;
|
||||||
while (i < subject_end) {
|
while (i < subject_end) {
|
||||||
char subject_char = String_.CharAt(subject, i);
|
char subject_char = String_.CharAt(subject, i);
|
||||||
@ -117,14 +143,21 @@ public class XophpString_ implements XophpCallbackOwner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mask.Has(mask_key)) {
|
if (mask.Has(mask_key)) {
|
||||||
rv++;
|
if (is_strspn) {
|
||||||
|
strspn_rv++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
break;
|
if (is_strspn) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
return rv;
|
return is_strspn ? strspn_rv : i - start;
|
||||||
}
|
}
|
||||||
public static int strspn_fwd__ary(byte[] src, boolean[] find, int bgn, int max, int src_len) {
|
public static int strspn_fwd__ary(byte[] src, boolean[] find, int bgn, int max, int src_len) {
|
||||||
if (max == -1) max = src_len;
|
if (max == -1) max = src_len;
|
||||||
@ -389,17 +422,15 @@ public class XophpString_ implements XophpCallbackOwner {
|
|||||||
rv[rv_idx] = trim_pos;
|
rv[rv_idx] = trim_pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static String str_repeat(String val, int count) {
|
// REF.PHP: https://www.php.net/manual/en/function.str-repeat.php
|
||||||
int val_len = String_.Len(val);
|
public static String str_repeat(String input, int multiplier) {
|
||||||
int chry_len = val_len * count;
|
String_bfr sb = new String_bfr();
|
||||||
char[] chry = new char[chry_len];
|
for (int i = 0; i < multiplier; i++) {
|
||||||
for (int i = 0; i < count; i++) {
|
sb.Add(input);
|
||||||
for (int j = 0; j < val_len; j++) {
|
|
||||||
chry[(i * val_len) + j] = String_.CharAt(val, j);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return String_.new_charAry_(chry, 0, chry_len);
|
return sb.To_str_and_clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean is_string(Object o) {
|
public static boolean is_string(Object o) {
|
||||||
return String_.as_(o) != null;
|
return String_.as_(o) != null;
|
||||||
}
|
}
|
||||||
@ -512,6 +543,26 @@ public class XophpString_ implements XophpCallbackOwner {
|
|||||||
return b >= 128 && b <= 255;
|
return b >= 128 && b <= 255;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// REF.PHP: https://www.php.net/manual/en/function.strrev.php
|
||||||
|
public static String strrev(String src) {
|
||||||
|
String_bfr sb = new String_bfr();
|
||||||
|
Ustring usrc = Ustring_.New_codepoints(src);
|
||||||
|
int usrc_len = usrc.Len_in_data();
|
||||||
|
for (int i = usrc_len - 1; i > -1; i--) {
|
||||||
|
int c = usrc.Get_data(i);
|
||||||
|
sb.Add_char_by_code(c);
|
||||||
|
}
|
||||||
|
return sb.To_str_and_clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String Char_as_str(String s, int idx) {
|
||||||
|
return Char_.To_str(String_.CharAt(s, idx));
|
||||||
|
}
|
||||||
|
public static boolean Char_eq(String s, int idx, String comp) {
|
||||||
|
return String_.Eq(Char_as_str(s, idx), comp);
|
||||||
|
}
|
||||||
|
|
||||||
public Object Callback(String method, Object... args) {
|
public Object Callback(String method, Object... args) {
|
||||||
if (String_.Eq(method, "strtoupper")) {
|
if (String_.Eq(method, "strtoupper")) {
|
||||||
String val = (String)args[0];
|
String val = (String)args[0];
|
||||||
|
@ -60,12 +60,6 @@ public class XophpString__tst {
|
|||||||
fxt.Test__strpos("aba", "a", 1, 2);
|
fxt.Test__strpos("aba", "a", 1, 2);
|
||||||
fxt.Test__strpos("aba", "a", -2, 2);
|
fxt.Test__strpos("aba", "a", -2, 2);
|
||||||
}
|
}
|
||||||
@Test public void strspn() {
|
|
||||||
fxt.Test__strspn("42 is the answer to the 128th question", fxt.Init__strspn_hash("1234567890"), 0, Int_.Min_value, 2);
|
|
||||||
fxt.Test__strspn("foo", fxt.Init__strspn_hash("o"), 0, Int_.Min_value, 0);
|
|
||||||
fxt.Test__strspn("foo", fxt.Init__strspn_hash("o"), 1, 2, 2);
|
|
||||||
fxt.Test__strspn("foo", fxt.Init__strspn_hash("o"), 1, 1, 1);
|
|
||||||
}
|
|
||||||
@Test public void rtrim() {
|
@Test public void rtrim() {
|
||||||
// pad is 0, 1 char
|
// pad is 0, 1 char
|
||||||
fxt.Test__rtrim("0100", "", "0100"); // empty pad returns String
|
fxt.Test__rtrim("0100", "", "0100"); // empty pad returns String
|
||||||
@ -151,6 +145,36 @@ public class XophpString__tst {
|
|||||||
fxt.Test__Fmt("a$0b", "a$0b", "z"); // invalid identifier
|
fxt.Test__Fmt("a$0b", "a$0b", "z"); // invalid identifier
|
||||||
fxt.Test__Fmt("a0", "a$xyz0b", "0"); // long identifier
|
fxt.Test__Fmt("a0", "a$xyz0b", "0"); // long identifier
|
||||||
}
|
}
|
||||||
|
@Test public void strrev() {
|
||||||
|
fxt.Test__strrev("", "");
|
||||||
|
fxt.Test__strrev("Hello world!", "!dlrow olleH");
|
||||||
|
fxt.Test__strrev("☆❤world", "dlrow❤☆");
|
||||||
|
fxt.Test__strrev("a¢€𤭢b", "b𤭢€¢a");
|
||||||
|
}
|
||||||
|
@Test public void str_repeat() {
|
||||||
|
fxt.Test__str_repeat("-=", 10, "-=-=-=-=-=-=-=-=-=-=");
|
||||||
|
}
|
||||||
|
@Test public void strspn() {
|
||||||
|
fxt.Test__strspn(1, "<-", "abc", "abc", -1);
|
||||||
|
|
||||||
|
// PHP samples
|
||||||
|
fxt.Test__strspn(2, "<-", "42 is the answer to the 128th question", "1234567890");
|
||||||
|
fxt.Test__strspn(0, "<-", "foo", "o");
|
||||||
|
fxt.Test__strspn(2, "<-", "foo", "o", 1, 2);
|
||||||
|
fxt.Test__strspn(1, "<-", "foo", "o", 1, 1);
|
||||||
|
}
|
||||||
|
@Test public void strcspn() {
|
||||||
|
fxt.Test__strcspn(3, "abc", "x", 0);
|
||||||
|
fxt.Test__strcspn(3, "abc", "x", -5);
|
||||||
|
|
||||||
|
// PHP samples
|
||||||
|
fxt.Test__strcspn(0, "abcd", "apple");
|
||||||
|
fxt.Test__strcspn(0, "abcd", "banana");
|
||||||
|
fxt.Test__strcspn(2, "hello", "l");
|
||||||
|
fxt.Test__strcspn(2, "hello", "world");
|
||||||
|
fxt.Test__strcspn(5, "abcdhelloabcd", "abcd", -9);
|
||||||
|
fxt.Test__strcspn(4, "abcdhelloabcd", "abcd", -9, -5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
class XophpString__fxt {
|
class XophpString__fxt {
|
||||||
public void Test_strspn_fwd__byte(String src_str, byte find, int bgn, int max, int expd) {
|
public void Test_strspn_fwd__byte(String src_str, byte find, int bgn, int max, int expd) {
|
||||||
@ -191,8 +215,10 @@ class XophpString__fxt {
|
|||||||
Gftest.Eq__int(expd, XophpString_.strpos(haystack, needle, offset));
|
Gftest.Eq__int(expd, XophpString_.strpos(haystack, needle, offset));
|
||||||
}
|
}
|
||||||
public Hash_adp Init__strspn_hash(String mask) {return XophpString_.strspn_hash(mask);}
|
public Hash_adp Init__strspn_hash(String mask) {return XophpString_.strspn_hash(mask);}
|
||||||
public void Test__strspn(String subject, Hash_adp mask, int start, int length, int expd) {
|
public void Test__strspn(int expd, String ignore, String subject, String mask) {Test__strspn(expd, ignore, subject, mask, Int_.Zero, Int_.Zero);}
|
||||||
int actl = XophpString_.strspn(subject, mask, start, length);
|
public void Test__strspn(int expd, String ignore, String subject, String mask, int start) {Test__strspn(expd, ignore, subject, mask, start, Int_.Zero);}
|
||||||
|
public void Test__strspn(int expd, String ignore, String subject, String mask, int start, int length) {
|
||||||
|
int actl = XophpString_.strspn(subject, XophpString_.strspn_hash(mask), start, length);
|
||||||
Gftest.Eq__int(expd, actl);
|
Gftest.Eq__int(expd, actl);
|
||||||
}
|
}
|
||||||
public void Test__rtrim(String str, String character_mask, String expd) {
|
public void Test__rtrim(String str, String character_mask, String expd) {
|
||||||
@ -222,4 +248,15 @@ class XophpString__fxt {
|
|||||||
public void Test__Fmt(String expd, String fmt, Object... args) {
|
public void Test__Fmt(String expd, String fmt, Object... args) {
|
||||||
Gftest.Eq__str(expd, XophpString_.Fmt(fmt, args));
|
Gftest.Eq__str(expd, XophpString_.Fmt(fmt, args));
|
||||||
}
|
}
|
||||||
|
public void Test__strrev(String src, String expd) {
|
||||||
|
Gftest.Eq__str(expd, XophpString_.strrev(src));
|
||||||
|
}
|
||||||
|
public void Test__str_repeat(String input, int multiplier, String expd) {
|
||||||
|
Gftest.Eq__str(expd, XophpString_.str_repeat(input, multiplier));
|
||||||
|
}
|
||||||
|
public void Test__strcspn(int expd, String subject, String mask) {Test__strcspn(expd, subject, mask, Int_.Zero, Int_.Zero);}
|
||||||
|
public void Test__strcspn(int expd, String subject, String mask, int start) {Test__strcspn(expd, subject, mask, start, Int_.Zero);}
|
||||||
|
public void Test__strcspn(int expd, String subject, String mask, int start, int length) {
|
||||||
|
Gftest.Eq__int(expd, XophpString_.strcspn(subject, XophpString_.strspn_hash(mask), start, length));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,6 @@ public class XophpType_ {
|
|||||||
return Type_.Eq_by_obj(o, XophpArray.class);
|
return Type_.Eq_by_obj(o, XophpArray.class);
|
||||||
}
|
}
|
||||||
public static boolean instance_of(Object o, Class<?> t) {
|
public static boolean instance_of(Object o, Class<?> t) {
|
||||||
return Type_.Eq_by_obj(o, t);
|
return Type_.Eq_by_obj(o, t) || Type_.Is_assignable_from_by_obj(o, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ class JCContentHandler extends TextContentHandler { /**
|
|||||||
* @param String $modelId
|
* @param String $modelId
|
||||||
*/
|
*/
|
||||||
public void __construct(String modelId, JCSingleton singleton) {
|
public void __construct(String modelId, JCSingleton singleton) {
|
||||||
super.__construct(modelId, XomwDefines.CONTENT_FORMAT_JSON, CONTENT_FORMAT_JSON_PRETTY);
|
super.__construct(modelId, XophpArray.New(XomwDefines.CONTENT_FORMAT_JSON, CONTENT_FORMAT_JSON_PRETTY));
|
||||||
this.singleton = singleton;
|
this.singleton = singleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3036,7 +3036,7 @@ public class XomwDefaultSettings {
|
|||||||
// /**
|
// /**
|
||||||
// * Whether to enable language variant conversion.
|
// * Whether to enable language variant conversion.
|
||||||
// */
|
// */
|
||||||
// $wgDisableLangConversion = false;
|
public static boolean wgDisableLangConversion = false;
|
||||||
//
|
//
|
||||||
// /**
|
// /**
|
||||||
// * Whether to enable language variant conversion for links.
|
// * Whether to enable language variant conversion for links.
|
||||||
@ -4146,19 +4146,19 @@ public class XomwDefaultSettings {
|
|||||||
// * When the limit is exceeded, an exception is thrown.
|
// * When the limit is exceeded, an exception is thrown.
|
||||||
// */
|
// */
|
||||||
// $wgMaxGeneratedPPNodeCount = 1000000;
|
// $wgMaxGeneratedPPNodeCount = 1000000;
|
||||||
//
|
|
||||||
// /**
|
/**
|
||||||
// * Maximum recursion depth for templates within templates.
|
* Maximum recursion depth for templates within templates.
|
||||||
// * The current parser adds two levels to the PHP call stack for each template,
|
* The current parser adds two levels to the PHP call stack for each template,
|
||||||
// * and xdebug limits the call stack to 100 by default. So this should hopefully
|
* and xdebug limits the call stack to 100 by default. So this should hopefully
|
||||||
// * stop the parser before it hits the xdebug limit.
|
* stop the parser before it hits the xdebug limit.
|
||||||
// */
|
*/
|
||||||
// $wgMaxTemplateDepth = 40;
|
public static final int wgMaxTemplateDepth = 40;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see $wgMaxTemplateDepth
|
* @see $wgMaxTemplateDepth
|
||||||
*/
|
*/
|
||||||
public static int wgMaxPPExpandDepth = 40;
|
public static final int wgMaxPPExpandDepth = 40;
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
// * URL schemes that should be recognized as valid by wfParseUrl().
|
// * URL schemes that should be recognized as valid by wfParseUrl().
|
||||||
|
@ -252,7 +252,8 @@ public class XomwTitle {
|
|||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
* @return Title|null Title or null on an error.
|
* @return Title|null Title or null on an error.
|
||||||
*/
|
*/
|
||||||
public static XomwTitle newFromText(XomwEnv env, byte[] text) {return newFromText(env, text, XomwDefines.NS_MAIN);}
|
public static XomwTitle newFromText(XomwEnv env, byte[] text) {return newFromText(env, text, XomwDefines.NS_MAIN);}
|
||||||
|
public static XomwTitle newFromText(XomwEnv env, String text, int defaultNamespace) {return newFromText(env, Bry_.new_u8(text));}
|
||||||
private static XomwTitle newFromText(XomwEnv env, byte[] text, int defaultNamespace) {
|
private static XomwTitle newFromText(XomwEnv env, byte[] text, int defaultNamespace) {
|
||||||
// DWIM: Integers can be passed in here when page titles are used as array keys.
|
// DWIM: Integers can be passed in here when page titles are used as array keys.
|
||||||
// XO.MW.SKIP:STRONGCAST
|
// XO.MW.SKIP:STRONGCAST
|
||||||
@ -1454,6 +1455,7 @@ public class XomwTitle {
|
|||||||
}
|
}
|
||||||
return this.mPrefixedText;
|
return this.mPrefixedText;
|
||||||
}
|
}
|
||||||
|
public String getPrefixedTextStr() {return String_.new_u8(getPrefixedText());}
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
// * Return a String representation of this title
|
// * Return a String representation of this title
|
||||||
|
@ -358,7 +358,7 @@ public abstract class ContentHandler {
|
|||||||
/**
|
/**
|
||||||
* @var String[]
|
* @var String[]
|
||||||
*/
|
*/
|
||||||
protected String[] mSupportedFormats;
|
protected XophpArray mSupportedFormats;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor, initializing the ContentHandler instance with its model ID
|
* Constructor, initializing the ContentHandler instance with its model ID
|
||||||
@ -369,7 +369,7 @@ public abstract class ContentHandler {
|
|||||||
* @param String[] $formats List for supported serialization formats
|
* @param String[] $formats List for supported serialization formats
|
||||||
* (typically as MIME types)
|
* (typically as MIME types)
|
||||||
*/
|
*/
|
||||||
@gplx.Virtual public void __construct(String modelId, String... formats) {
|
@gplx.Virtual public void __construct(String modelId, XophpArray formats) {
|
||||||
this.mModelID = modelId;
|
this.mModelID = modelId;
|
||||||
this.mSupportedFormats = formats;
|
this.mSupportedFormats = formats;
|
||||||
}
|
}
|
||||||
@ -495,7 +495,7 @@ public abstract class ContentHandler {
|
|||||||
*
|
*
|
||||||
* @return String[] List of serialization formats as MIME type like strings
|
* @return String[] List of serialization formats as MIME type like strings
|
||||||
*/
|
*/
|
||||||
public String[] getSupportedFormats() {
|
public XophpArray getSupportedFormats() {
|
||||||
return this.mSupportedFormats;
|
return this.mSupportedFormats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,13 +14,11 @@ GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
|||||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
*/
|
*/
|
||||||
package gplx.xowa.mediawiki.includes.content; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*;
|
package gplx.xowa.mediawiki.includes.content; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*;
|
||||||
public class TextContentHandler extends ContentHandler { // @codingStandardsIgnoreStart bug 57585
|
public class TextContentHandler extends ContentHandler { public void __construct() {this.__construct(XomwDefines.CONTENT_MODEL_TEXT, XophpArray.New(XomwDefines.CONTENT_FORMAT_TEXT));}
|
||||||
public void __construct() {this.__construct(XomwDefines.CONTENT_MODEL_TEXT, XomwDefines.CONTENT_FORMAT_TEXT);}
|
@Override public void __construct(String modelId, XophpArray formats) {
|
||||||
@Override public void __construct(String modelId, String... formats) {
|
|
||||||
super.__construct(modelId, formats);
|
super.__construct(modelId, formats);
|
||||||
}
|
}
|
||||||
// @codingStandardsIgnoreEnd
|
|
||||||
//
|
|
||||||
// /**
|
// /**
|
||||||
// * Returns the content's text as-is.
|
// * Returns the content's text as-is.
|
||||||
// *
|
// *
|
||||||
|
@ -143,7 +143,7 @@ public class XomwParser implements XomwParserIface {
|
|||||||
// public mFunctionHooks = [];
|
// public mFunctionHooks = [];
|
||||||
// public mFunctionSynonyms = [ 0 => [], 1 => [] ];
|
// public mFunctionSynonyms = [ 0 => [], 1 => [] ];
|
||||||
// public mFunctionTagHooks = [];
|
// public mFunctionTagHooks = [];
|
||||||
// public mStripList = [];
|
public XophpArray mStripList = XophpArray.New();
|
||||||
// public mDefaultStripList = [];
|
// public mDefaultStripList = [];
|
||||||
// public mVarCache = [];
|
// public mVarCache = [];
|
||||||
// public mImageParams = [];
|
// public mImageParams = [];
|
||||||
@ -295,7 +295,7 @@ public class XomwParser implements XomwParserIface {
|
|||||||
// XomwParser.EXT_LINK_ADDR .
|
// XomwParser.EXT_LINK_ADDR .
|
||||||
// XomwParser.EXT_LINK_URL_CLASS . '*)\p{Zs}*([^\]\\x00-\\x08\\x0a-\\x1F]*?)\]/Su';
|
// XomwParser.EXT_LINK_URL_CLASS . '*)\p{Zs}*([^\]\\x00-\\x08\\x0a-\\x1F]*?)\]/Su';
|
||||||
|
|
||||||
this.mPreprocessorClass = XomwPreprocessor_DOM.Instance;
|
this.mPreprocessorClass = XomwPreprocessor_Hash.Instance;
|
||||||
// if (isset($conf['preprocessorClass'])) {
|
// if (isset($conf['preprocessorClass'])) {
|
||||||
// this.mPreprocessorClass = $conf['preprocessorClass'];
|
// this.mPreprocessorClass = $conf['preprocessorClass'];
|
||||||
// } elseif (defined('HPHP_VERSION')) {
|
// } elseif (defined('HPHP_VERSION')) {
|
||||||
@ -1096,15 +1096,15 @@ public class XomwParser implements XomwParserIface {
|
|||||||
// }
|
// }
|
||||||
// return $stripped;
|
// return $stripped;
|
||||||
// }
|
// }
|
||||||
//
|
|
||||||
// /**
|
/**
|
||||||
// * Get a list of strippable XML-like elements
|
* Get a list of strippable XML-like elements
|
||||||
// *
|
*
|
||||||
// * @return array
|
* @return array
|
||||||
// */
|
*/
|
||||||
// public function getStripList() {
|
public XophpArray getStripList() {
|
||||||
// return this.mStripList;
|
return this.mStripList;
|
||||||
// }
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an item to the strip state
|
* Add an item to the strip state
|
||||||
@ -1147,8 +1147,8 @@ public class XomwParser implements XomwParserIface {
|
|||||||
* @return String
|
* @return String
|
||||||
*/
|
*/
|
||||||
// isMain=tru
|
// isMain=tru
|
||||||
public void internalParse(XomwParserBfr pbfr, XomwParserCtx pctx, byte[] text) {internalParse(pbfr, pctx, text, true, false);}
|
public void internalParse(XomwParserBfr pbfr, XomwParserCtx pctx, byte[] text) {internalParse(pbfr, pctx, text, true, null);}
|
||||||
public void internalParse(XomwParserBfr pbfr, XomwParserCtx pctx, byte[] text, boolean isMain, boolean frame) {
|
public void internalParse(XomwParserBfr pbfr, XomwParserCtx pctx, byte[] text, boolean isMain, XomwPPFrame frame) {
|
||||||
pbfr.Init(text);
|
pbfr.Init(text);
|
||||||
// $origText = text;
|
// $origText = text;
|
||||||
|
|
||||||
@ -1206,6 +1206,69 @@ public class XomwParser implements XomwParserIface {
|
|||||||
// $text = $this->formatHeadings($text, $origText, $isMain);
|
// $text = $this->formatHeadings($text, $origText, $isMain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String internalParse(String text, boolean isMain, XomwPPFrame frame) { // isMain=true; frame=false;
|
||||||
|
// String origText = text;
|
||||||
|
|
||||||
|
// Avoid PHP 7.1 warning from passing this by reference
|
||||||
|
// XomwParser parser = this;
|
||||||
|
|
||||||
|
// Hook to suspend the parser in this state
|
||||||
|
// if (!Hooks::run("ParserBeforeInternalParse", [ &parser, &text, &this.mStripState ])) {
|
||||||
|
// return text;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if frame is provided, then use frame for replacing any variables
|
||||||
|
int flag = 0;
|
||||||
|
if (XophpObject_.is_true(frame)) {
|
||||||
|
// use frame depth to infer how include/noinclude tags should be handled
|
||||||
|
// depth=0 means this is the top-level document; otherwise it's an included document
|
||||||
|
if (!XophpInt_.is_true(frame.depth)) {
|
||||||
|
flag = 0;
|
||||||
|
} else {
|
||||||
|
flag = XomwParser.PTD_FOR_INCLUSION;
|
||||||
|
}
|
||||||
|
XomwPPNode dom = this.preprocessToDom(text, flag);
|
||||||
|
text = frame.expand(dom);
|
||||||
|
} else {
|
||||||
|
// if frame is not provided, then use old-style replaceVariables
|
||||||
|
// text = this.replaceVariables(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hooks::run("InternalParseBeforeSanitize", [ &parser, &text, &this.mStripState ]);
|
||||||
|
// text = Sanitizer::removeHTMLtags(
|
||||||
|
// text,
|
||||||
|
// [ this, "attributeStripCallback" ],
|
||||||
|
// false,
|
||||||
|
// array_keys(this.mTransparentTagHooks),
|
||||||
|
// [],
|
||||||
|
// [ this, "addTrackingCategory" ]
|
||||||
|
// );
|
||||||
|
// Hooks::run("InternalParseBeforeLinks", [ &parser, &text, &this.mStripState ]);
|
||||||
|
|
||||||
|
// Tables need to come after variable replacement for things to work
|
||||||
|
// properly; putting them before other transformations should keep
|
||||||
|
// exciting things like link expansions from showing up in surprising
|
||||||
|
// places.
|
||||||
|
// text = this.doTableStuff(text);
|
||||||
|
//
|
||||||
|
// text = preg_replace("/(^|\n)-----* /", "\\1<hr />", text);
|
||||||
|
//
|
||||||
|
// text = this.doDoubleUnderscore(text);
|
||||||
|
//
|
||||||
|
// text = this.doHeadings(text);
|
||||||
|
// text = this.replaceInternalLinks(text);
|
||||||
|
// text = this.doAllQuotes(text);
|
||||||
|
// text = this.replaceExternalLinks(text);
|
||||||
|
//
|
||||||
|
// // replaceInternalLinks may sometimes leave behind
|
||||||
|
// // absolute URLs, which have to be masked to hide them from replaceExternalLinks
|
||||||
|
// text = str_replace(self::MARKER_PREFIX . "NOPARSE", "", text);
|
||||||
|
//
|
||||||
|
// text = this.doMagicLinks(text);
|
||||||
|
// text = this.formatHeadings(text, origText, isMain);
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Helper function for parse() that transforms half-parsed HTML into fully
|
* Helper function for parse() that transforms half-parsed HTML into fully
|
||||||
* parsed HTML.
|
* parsed HTML.
|
||||||
@ -2286,329 +2349,356 @@ public class XomwParser implements XomwParserIface {
|
|||||||
// this.addTrackingCategory("$limitationType-category");
|
// this.addTrackingCategory("$limitationType-category");
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// /**
|
// MW.SRC:1.33.1
|
||||||
// * Return the text of a template, after recursively
|
/**
|
||||||
// * replacing any variables or templates within the template.
|
* Return the text of a template, after recursively
|
||||||
// *
|
* replacing any variables or templates within the template.
|
||||||
// * @param array $piece The parts of the template
|
*
|
||||||
// * $piece['title']: the title, i.e. the part before the |
|
* @param array $piece The parts of the template
|
||||||
// * $piece['parts']: the parameter array
|
* $piece['title']: the title, i.e. the part before the |
|
||||||
// * $piece['lineStart']: whether the brace was at the start of a line
|
* $piece['parts']: the parameter array
|
||||||
// * @param PPFrame $frame The current frame, contains template arguments
|
* $piece['lineStart']: whether the brace was at the start of a line
|
||||||
// * @throws Exception
|
* @param PPFrame $frame The current frame, contains template arguments
|
||||||
// * @return String The text of the template
|
* @throws Exception
|
||||||
// */
|
* @return String The text of the template
|
||||||
|
*/
|
||||||
public XophpArray braceSubstitution(XophpArray piece, XomwPPFrame frame) {
|
public XophpArray braceSubstitution(XophpArray piece, XomwPPFrame frame) {
|
||||||
//
|
// Flags
|
||||||
// // Flags
|
|
||||||
//
|
// text has been filled
|
||||||
// // $text has been filled
|
boolean found = false;
|
||||||
// $found = false;
|
// wiki markup in text should be escaped
|
||||||
// // wiki markup in $text should be escaped
|
boolean nowiki = false;
|
||||||
// $nowiki = false;
|
// text is HTML, armour it against wikitext transformation
|
||||||
// // $text is HTML, armour it against wikitext transformation
|
boolean isHTML = false;
|
||||||
// $isHTML = false;
|
// Force interwiki transclusion to be done in raw mode not rendered
|
||||||
// // Force interwiki transclusion to be done in raw mode not rendered
|
boolean forceRawInterwiki = false;
|
||||||
// $forceRawInterwiki = false;
|
// text is a DOM node needing expansion in a child frame
|
||||||
// // $text is a DOM node needing expansion in a child frame
|
boolean isChildObj = false;
|
||||||
// $isChildObj = false;
|
// text is a DOM node needing expansion in the current frame
|
||||||
// // $text is a DOM node needing expansion in the current frame
|
boolean isLocalObj = false;
|
||||||
// $isLocalObj = false;
|
|
||||||
//
|
// Title Object, where text came from
|
||||||
// // Title Object, where $text came from
|
XomwTitle title = null;
|
||||||
// $title = false;
|
|
||||||
//
|
// part1 is the bit before the first |, and must contain only title characters.
|
||||||
// // $part1 is the bit before the first |, and must contain only title characters.
|
// Various prefixes will be stripped from it later.
|
||||||
// // Various prefixes will be stripped from it later.
|
String titleWithSpaces = frame.expand(piece.Get_by("title"));
|
||||||
// $titleWithSpaces = $frame->expand($piece['title']);
|
String part1 = XophpString_.trim(titleWithSpaces);
|
||||||
// $part1 = trim($titleWithSpaces);
|
String titleText = XophpString_.False;
|
||||||
// $titleText = false;
|
|
||||||
//
|
// Original title text preserved for various purposes
|
||||||
// // Original title text preserved for various purposes
|
String originalTitle = part1;
|
||||||
// $originalTitle = $part1;
|
|
||||||
//
|
// args is a list of argument nodes, starting from index 0, not including part1
|
||||||
// // $args is a list of argument nodes, starting from index 0, not including $part1
|
// @todo FIXME: If piece["parts"] is null then the call to getLength()
|
||||||
// // @todo FIXME: If piece['parts'] is null then the call to getLength()
|
// below won"t work b/c this args isn"t an Object
|
||||||
// // below won't work b/c this $args isn't an Object
|
XomwPPNode args = (piece.Get_by("parts") == null) ? new XomwPPNode_Hash_Array(XophpArray.New()) : (XomwPPNode_Hash_Array)piece.Get_by("parts");
|
||||||
// $args = (null == $piece['parts']) ? [] : $piece['parts'];
|
|
||||||
//
|
// boolean profileSection = XophpBool_.Null; // profile templates
|
||||||
// $profileSection = null; // profile templates
|
|
||||||
//
|
String text = null;
|
||||||
// // SUBST
|
// SUBST
|
||||||
// if (!$found) {
|
if (!found) {
|
||||||
// $substMatch = this.mSubstWords->matchStartAndRemove($part1);
|
// substMatch = this.mSubstWords.matchStartAndRemove(part1);
|
||||||
//
|
//
|
||||||
// // Possibilities for substMatch: "subst", "safesubst" or FALSE
|
// // Possibilities for substMatch: "subst", "safesubst" or FALSE
|
||||||
// // Decide whether to expand template or keep wikitext as-is.
|
// // Decide whether to expand template or keep wikitext as-is.
|
||||||
// if (this.ot['wiki']) {
|
// if (this.ot["wiki"]) {
|
||||||
// if ($substMatch === false) {
|
// if (substMatch === false) {
|
||||||
// $literal = true; // literal when in PST with no prefix
|
// literal = true; # literal when in PST with no prefix
|
||||||
// } else {
|
// } else {
|
||||||
// $literal = false; // expand when in PST with subst: or safesubst:
|
// literal = false; # expand when in PST with subst: or safesubst:
|
||||||
// }
|
// }
|
||||||
// } else {
|
// } else {
|
||||||
// if ($substMatch == 'subst') {
|
// if (substMatch == "subst") {
|
||||||
// $literal = true; // literal when not in PST with plain subst:
|
// literal = true; # literal when not in PST with plain subst:
|
||||||
// } else {
|
// } else {
|
||||||
// $literal = false; // expand when not in PST with safesubst: or no prefix
|
// literal = false; # expand when not in PST with safesubst: or no prefix
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// if ($literal) {
|
// if (literal) {
|
||||||
// $text = $frame->virtualBracketedImplode('{{', '|', '}}', $titleWithSpaces, $args);
|
// text = frame.virtualBracketedImplode("{{", "|", "}}", titleWithSpaces, args);
|
||||||
// $isLocalObj = true;
|
// isLocalObj = true;
|
||||||
// $found = true;
|
// found = true;
|
||||||
// }
|
// }
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// // Variables
|
// // Variables
|
||||||
// if (!$found && $args->getLength() == 0) {
|
// if (!found && args.getLength() == 0) {
|
||||||
// $id = this.mVariables->matchStartToEnd($part1);
|
// id = this.mVariables.matchStartToEnd(part1);
|
||||||
// if ($id !== false) {
|
// if (id !== false) {
|
||||||
// $text = this.getVariableValue($id, $frame);
|
// text = this.getVariableValue(id, frame);
|
||||||
// if (MagicWord::getCacheTTL($id) > -1) {
|
// if (this.magicWordFactory.getCacheTTL(id) > -1) {
|
||||||
// this.mOutput->updateCacheExpiry(MagicWord::getCacheTTL($id));
|
// this.mOutput.updateCacheExpiry(
|
||||||
|
// this.magicWordFactory.getCacheTTL(id));
|
||||||
// }
|
// }
|
||||||
// $found = true;
|
// found = true;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// // MSG, MSGNW and RAW
|
// // MSG, MSGNW and RAW
|
||||||
// if (!$found) {
|
// if (!found) {
|
||||||
// // Check for MSGNW:
|
// // Check for MSGNW:
|
||||||
// mwMsgnw = MagicWord::get('msgnw');
|
// mwMsgnw = this.magicWordFactory.get("msgnw");
|
||||||
// if (mwMsgnw->matchStartAndRemove($part1)) {
|
// if (mwMsgnw.matchStartAndRemove(part1)) {
|
||||||
// $nowiki = true;
|
// nowiki = true;
|
||||||
// } else {
|
// } else {
|
||||||
// // Remove obsolete MSG:
|
// // Remove obsolete MSG:
|
||||||
// mwMsg = MagicWord::get('msg');
|
// mwMsg = this.magicWordFactory.get("msg");
|
||||||
// mwMsg->matchStartAndRemove($part1);
|
// mwMsg.matchStartAndRemove(part1);
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// // Check for RAW:
|
// // Check for RAW:
|
||||||
// mwRaw = MagicWord::get('raw');
|
// mwRaw = this.magicWordFactory.get("raw");
|
||||||
// if (mwRaw->matchStartAndRemove($part1)) {
|
// if (mwRaw.matchStartAndRemove(part1)) {
|
||||||
// $forceRawInterwiki = true;
|
// forceRawInterwiki = true;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
|
||||||
// // Parser functions
|
// Parser functions
|
||||||
// if (!$found) {
|
if (!found) {
|
||||||
// $colonPos = strpos($part1, ':');
|
int colonPos = XophpString_.strpos(part1, ":");
|
||||||
// if ($colonPos !== false) {
|
if (!XophpInt_.is_false(colonPos)) {
|
||||||
// $func = substr($part1, 0, $colonPos);
|
// String func = XophpString_.substr(part1, 0, colonPos);
|
||||||
// $funcArgs = [ trim(substr($part1, $colonPos + 1)) ];
|
XophpArray funcArgs = XophpArray.New(XophpString_.trim(XophpString_.substr(part1, colonPos + 1)));
|
||||||
// $argsLength = $args->getLength();
|
int argsLength = args.getLength();
|
||||||
// for ($i = 0; $i < $argsLength; $i++) {
|
for (int i = 0; i < argsLength; i++) {
|
||||||
// $funcArgs[] = $args->item($i);
|
funcArgs.Add(args.item(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
XophpArray result = XophpArray.New();
|
||||||
|
// result = this.callParserFunction(frame, func, funcArgs);
|
||||||
|
|
||||||
|
// Extract any forwarded flags
|
||||||
|
if (XophpArray_.isset(result, "title")) {
|
||||||
|
title = (XomwTitle)result.Get_by("title");
|
||||||
|
}
|
||||||
|
if (XophpArray_.isset(result, "found")) {
|
||||||
|
found = result.Get_by_bool("found");
|
||||||
|
}
|
||||||
|
if (XophpArray_.array_key_exists("text", result)) {
|
||||||
|
// a String or null
|
||||||
|
text = result.Get_by_str("text");
|
||||||
|
}
|
||||||
|
if (XophpArray_.isset(result, "nowiki")) {
|
||||||
|
nowiki = result.Get_by_bool("nowiki");
|
||||||
|
}
|
||||||
|
if (XophpArray_.isset(result, "isHTML")) {
|
||||||
|
isHTML = result.Get_by_bool("isHTML");
|
||||||
|
}
|
||||||
|
if (XophpArray_.isset(result, "forceRawInterwiki")) {
|
||||||
|
forceRawInterwiki = result.Get_by_bool("forceRawInterwiki");
|
||||||
|
}
|
||||||
|
if (XophpArray_.isset(result, "isChildObj")) {
|
||||||
|
isChildObj = result.Get_by_bool("isChildObj");
|
||||||
|
}
|
||||||
|
if (XophpArray_.isset(result, "isLocalObj")) {
|
||||||
|
isLocalObj = result.Get_by_bool("isLocalObj");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finish mangling title and then check for loops.
|
||||||
|
// Set title to a Title Object and titleText to the PDBK
|
||||||
|
if (!found) {
|
||||||
|
int ns = XomwDefines.NS_TEMPLATE;
|
||||||
|
// Split the title into page and subpage
|
||||||
|
// String subpage = "";
|
||||||
|
// String relative = this.maybeDoSubpageLink(part1, subpage);
|
||||||
|
String relative = "";
|
||||||
|
|
||||||
|
if (!String_.Eq(part1, relative)) {
|
||||||
|
part1 = relative;
|
||||||
|
ns = this.mTitle.getNamespace();
|
||||||
|
}
|
||||||
|
title = XomwTitle.newFromText(env, part1, ns);
|
||||||
|
if (XophpObject_.is_true(title)) {
|
||||||
|
titleText = title.getPrefixedTextStr();
|
||||||
|
// Check for language variants if the template is not found
|
||||||
|
// if (this.getTargetLanguage().hasVariants() && title.getArticleID() == 0) {
|
||||||
|
// this.getTargetLanguage().findVariantLink(part1, title, true);
|
||||||
// }
|
// }
|
||||||
// try {
|
// Do recursion depth check
|
||||||
// $result = this.callParserFunction($frame, $func, $funcArgs);
|
int limit = this.mOptions.getMaxTemplateDepth();
|
||||||
// } catch (Exception $ex) {
|
if (frame.depth >= limit) {
|
||||||
// throw $ex;
|
found = true;
|
||||||
// }
|
// text = "<span class=\"error\">"
|
||||||
//
|
// + wfMessage("parser-template-recursion-depth-warning")
|
||||||
// // The interface for parser functions allows for extracting
|
// .numParams(limit).inContentLanguage().text()
|
||||||
// // flags into the local scope. Extract any forwarded flags
|
// + "</span>";
|
||||||
// // here.
|
}
|
||||||
// extract($result);
|
}
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
//
|
// Load from database
|
||||||
// // Finish mangling title and then check for loops.
|
if (!found && XophpObject_.is_true(title)) {
|
||||||
// // Set $title to a Title Object and $titleText to the PDBK
|
// profileSection = this.mProfiler.scopedProfileIn(title.getPrefixedDBkey());
|
||||||
// if (!$found) {
|
// if (!title.isExternal()) {
|
||||||
// $ns = NS_TEMPLATE;
|
// if (title.isSpecialPage()
|
||||||
// // Split the title into page and subpage
|
// && this.mOptions.getAllowSpecialInclusion()
|
||||||
// $subpage = '';
|
// && this.ot["html"]
|
||||||
// $relative = this.maybeDoSubpageLink($part1, $subpage);
|
|
||||||
// if ($part1 !== $relative) {
|
|
||||||
// $part1 = $relative;
|
|
||||||
// $ns = this.mTitle->getNamespace();
|
|
||||||
// }
|
|
||||||
// $title = Title::newFromText($part1, $ns);
|
|
||||||
// if ($title) {
|
|
||||||
// $titleText = $title->getPrefixedText();
|
|
||||||
// // Check for language variants if the template is not found
|
|
||||||
// if (this.getConverterLanguage()->hasVariants() && $title->getArticleID() == 0) {
|
|
||||||
// this.getConverterLanguage()->findVariantLink($part1, $title, true);
|
|
||||||
// }
|
|
||||||
// // Do recursion depth check
|
|
||||||
// $limit = this.mOptions->getMaxTemplateDepth();
|
|
||||||
// if ($frame->depth >= $limit) {
|
|
||||||
// $found = true;
|
|
||||||
// $text = '<span class="error">'
|
|
||||||
// . wfMessage('parser-template-recursion-depth-warning')
|
|
||||||
// ->numParams($limit)->inContentLanguage()->text()
|
|
||||||
// . '</span>';
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Load from database
|
|
||||||
// if (!$found && $title) {
|
|
||||||
// $profileSection = this.mProfiler->scopedProfileIn($title->getPrefixedDBkey());
|
|
||||||
// if (!$title->isExternal()) {
|
|
||||||
// if ($title->isSpecialPage()
|
|
||||||
// && this.mOptions->getAllowSpecialInclusion()
|
|
||||||
// && this.ot['html']
|
|
||||||
// ) {
|
// ) {
|
||||||
// $specialPage = SpecialPageFactory::getPage($title->getDBkey());
|
// specialPage = this.specialPageFactory.getPage(title.getDBkey());
|
||||||
// // Pass the template arguments as URL parameters.
|
// // Pass the template arguments as URL parameters.
|
||||||
// // "uselang" will have no effect since the Language Object
|
// // "uselang" will have no effect since the Language Object
|
||||||
// // is forced to the one defined in ParserOptions.
|
// // is forced to the one defined in ParserOptions.
|
||||||
// $pageArgs = [];
|
// pageArgs = [];
|
||||||
// $argsLength = $args->getLength();
|
// argsLength = args.getLength();
|
||||||
// for ($i = 0; $i < $argsLength; $i++) {
|
// for (i = 0; i < argsLength; i++) {
|
||||||
// $bits = $args->item($i)->splitArg();
|
// bits = args.item(i).splitArg();
|
||||||
// if (strval($bits['index']) === '') {
|
// if (strval(bits["index"]) === "") {
|
||||||
// $name = trim($frame->expand($bits['name'], PPFrame::STRIP_COMMENTS));
|
// name = trim(frame.expand(bits["name"], PPFrame::STRIP_COMMENTS));
|
||||||
// $value = trim($frame->expand($bits['value']));
|
// value = trim(frame.expand(bits["value"]));
|
||||||
// $pageArgs[$name] = $value;
|
// pageArgs[name] = value;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// // Create a new context to execute the special page
|
// // Create a new context to execute the special page
|
||||||
// $context = new RequestContext;
|
// context = new RequestContext;
|
||||||
// $context->setTitle($title);
|
// context.setTitle(title);
|
||||||
// $context->setRequest(new FauxRequest($pageArgs));
|
// context.setRequest(new FauxRequest(pageArgs));
|
||||||
// if ($specialPage && $specialPage->maxIncludeCacheTime() === 0) {
|
// if (specialPage && specialPage.maxIncludeCacheTime() === 0) {
|
||||||
// $context->setUser(this.getUser());
|
// context.setUser(this.getUser());
|
||||||
// } else {
|
// } else {
|
||||||
// // If this page is cached, then we better not be per user.
|
// // If this page is cached, then we better not be per user.
|
||||||
// $context->setUser(User::newFromName('127.0.0.1', false));
|
// context.setUser(User::newFromName("127.0.0.1", false));
|
||||||
// }
|
// }
|
||||||
// $context->setLanguage(this.mOptions->getUserLangObj());
|
// context.setLanguage(this.mOptions.getUserLangObj());
|
||||||
// $ret = SpecialPageFactory::capturePath(
|
// ret = this.specialPageFactory.capturePath(title, context, this.getLinkRenderer());
|
||||||
// $title, $context, this.getLinkRenderer());
|
// if (ret) {
|
||||||
// if ($ret) {
|
// text = context.getOutput().getHTML();
|
||||||
// $text = $context->getOutput()->getHTML();
|
// this.mOutput.addOutputPageMetadata(context.getOutput());
|
||||||
// this.mOutput->addOutputPageMetadata($context->getOutput());
|
// found = true;
|
||||||
// $found = true;
|
// isHTML = true;
|
||||||
// $isHTML = true;
|
// if (specialPage && specialPage.maxIncludeCacheTime() !== false) {
|
||||||
// if ($specialPage && $specialPage->maxIncludeCacheTime() !== false) {
|
// this.mOutput.updateRuntimeAdaptiveExpiry(
|
||||||
// this.mOutput->updateRuntimeAdaptiveExpiry(
|
// specialPage.maxIncludeCacheTime()
|
||||||
// $specialPage->maxIncludeCacheTime()
|
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// } elseif (MWNamespace::isNonincludable($title->getNamespace())) {
|
// } elseif (MWNamespace::isNonincludable(title.getNamespace())) {
|
||||||
// $found = false; // access denied
|
// found = false; # access denied
|
||||||
// wfDebug(__METHOD__ . ": template inclusion denied for " .
|
// wfDebug(__METHOD__ . ": template inclusion denied for " .
|
||||||
// $title->getPrefixedDBkey() . "\n");
|
// title.getPrefixedDBkey() . "\n");
|
||||||
// } else {
|
// } else {
|
||||||
// list($text, $title) = this.getTemplateDom($title);
|
// list(text, title) = this.getTemplateDom(title);
|
||||||
// if ($text !== false) {
|
// if (text !== false) {
|
||||||
// $found = true;
|
// found = true;
|
||||||
// $isChildObj = true;
|
// isChildObj = true;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// // If the title is valid but undisplayable, make a link to it
|
// // If the title is valid but undisplayable, make a link to it
|
||||||
// if (!$found && (this.ot['html'] || this.ot['pre'])) {
|
// if (!found && (this.ot["html"] || this.ot["pre"])) {
|
||||||
// $text = "[[:$titleText]]";
|
// text = "[[:titleText]]";
|
||||||
// $found = true;
|
// found = true;
|
||||||
// }
|
// }
|
||||||
// } elseif ($title->isTrans()) {
|
// } elseif (title.isTrans()) {
|
||||||
// // Interwiki transclusion
|
// // Interwiki transclusion
|
||||||
// if (this.ot['html'] && !$forceRawInterwiki) {
|
// if (this.ot["html"] && !forceRawInterwiki) {
|
||||||
// $text = this.interwikiTransclude($title, 'render');
|
// text = this.interwikiTransclude(title, "render");
|
||||||
// $isHTML = true;
|
// isHTML = true;
|
||||||
// } else {
|
// } else {
|
||||||
// $text = this.interwikiTransclude($title, 'raw');
|
// text = this.interwikiTransclude(title, "raw");
|
||||||
// // Preprocess it like a template
|
// // Preprocess it like a template
|
||||||
// $text = this.preprocessToDom($text, XomwParser.PTD_FOR_INCLUSION);
|
// text = this.preprocessToDom(text, self::PTD_FOR_INCLUSION);
|
||||||
// $isChildObj = true;
|
// isChildObj = true;
|
||||||
// }
|
// }
|
||||||
// $found = true;
|
// found = true;
|
||||||
// }
|
// }
|
||||||
//
|
|
||||||
// // Do infinite loop check
|
// Do infinite loop check
|
||||||
// // This has to be done after redirect resolution to avoid infinite loops via redirects
|
// This has to be done after redirect resolution to avoid infinite loops via redirects
|
||||||
// if (!$frame->loopCheck($title)) {
|
if (!frame.loopCheck(title)) {
|
||||||
// $found = true;
|
found = true;
|
||||||
// $text = '<span class="error">'
|
// text = "<span class=\"error\">"
|
||||||
// . wfMessage('parser-template-loop-warning', $titleText)->inContentLanguage()->text()
|
// + wfMessage("parser-template-loop-warning", titleText).inContentLanguage().text()
|
||||||
// . '</span>';
|
// + "</span>";
|
||||||
// wfDebug(__METHOD__ . ": template loop broken at '$titleText'\n");
|
// this.addTrackingCategory("template-loop-category");
|
||||||
|
// this.mOutput.addWarning(wfMessage("template-loop-warning",
|
||||||
|
// wfEscapeWikiText(titleText)).text());
|
||||||
|
// wfDebug(__METHOD__ . ": template loop broken at "titleText"\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we haven"t found text to substitute by now, we"re done
|
||||||
|
// Recover the source wikitext and return it
|
||||||
|
// if (!found) {
|
||||||
|
// text = frame.virtualBracketedImplode("{{", "|", "}}", titleWithSpaces, args);
|
||||||
|
// if (profileSection) {
|
||||||
|
// this.mProfiler.scopedProfileOut(profileSection);
|
||||||
// }
|
// }
|
||||||
|
// return ["Object", text];
|
||||||
// }
|
// }
|
||||||
//
|
|
||||||
// // If we haven't found text to substitute by now, we're done
|
// XomwPPFrame newFrame = null;
|
||||||
// // Recover the source wikitext and return it
|
|
||||||
// if (!$found) {
|
|
||||||
// $text = $frame->virtualBracketedImplode('{{', '|', '}}', $titleWithSpaces, $args);
|
|
||||||
// if ($profileSection) {
|
|
||||||
// this.mProfiler->scopedProfileOut($profileSection);
|
|
||||||
// }
|
|
||||||
// return [ 'Object' => $text ];
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Expand DOM-style return values in a child frame
|
// // Expand DOM-style return values in a child frame
|
||||||
// if ($isChildObj) {
|
// if (isChildObj) {
|
||||||
// // Clean up argument array
|
// // Clean up argument array
|
||||||
// $newFrame = $frame->newChild($args, $title);
|
// newFrame = frame.newChild(args, title);
|
||||||
//
|
//
|
||||||
// if ($nowiki) {
|
// if (nowiki) {
|
||||||
// $text = $newFrame->expand($text, PPFrame::RECOVER_ORIG);
|
// text = newFrame.expand(text, XomwPPFrame.RECOVER_ORIG);
|
||||||
// } elseif ($titleText !== false && $newFrame->isEmpty()) {
|
// } else if (!XophpString_.is_false(titleText) && newFrame.isEmpty()) {
|
||||||
// // Expansion is eligible for the empty-frame cache
|
// // Expansion is eligible for the empty-frame cache
|
||||||
// $text = $newFrame->cachedExpand($titleText, $text);
|
// text = newFrame.cachedExpand(titleText, text);
|
||||||
// } else {
|
// } else {
|
||||||
// // Uncached expansion
|
// // Uncached expansion
|
||||||
// $text = $newFrame->expand($text);
|
// text = newFrame.expand(text);
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// if ($isLocalObj && $nowiki) {
|
// if (isLocalObj && nowiki) {
|
||||||
// $text = $frame->expand($text, PPFrame::RECOVER_ORIG);
|
// text = frame.expand(text, PPFrame::RECOVER_ORIG);
|
||||||
// $isLocalObj = false;
|
// isLocalObj = false;
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// if ($profileSection) {
|
// if (profileSection) {
|
||||||
// this.mProfiler->scopedProfileOut($profileSection);
|
// this.mProfiler.scopedProfileOut(profileSection);
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// // Replace raw HTML by a placeholder
|
// // Replace raw HTML by a placeholder
|
||||||
// if ($isHTML) {
|
// if (isHTML) {
|
||||||
// $text = this.insertStripItem($text);
|
// text = this.insertStripItem(text);
|
||||||
// } elseif ($nowiki && (this.ot['html'] || this.ot['pre'])) {
|
// } elseif (nowiki && (this.ot["html"] || this.ot["pre"])) {
|
||||||
// // Escape nowiki-style return values
|
// // Escape nowiki-style return values
|
||||||
// $text = wfEscapeWikiText($text);
|
// text = wfEscapeWikiText(text);
|
||||||
// } elseif (is_string($text)
|
// } elseif (is_string(text)
|
||||||
// && !$piece['lineStart']
|
// && !piece["lineStart"]
|
||||||
// && preg_match('/^(?:{\\||:|;|#|\*)/', $text)
|
// && preg_match("/^(?:{\\||:|;|#|\*)/", text)
|
||||||
// ) {
|
// ) {
|
||||||
// // T2529: if the template begins with a table or block-level
|
// // T2529: if the template begins with a table or block-level
|
||||||
// // element, it should be treated as beginning a new line.
|
// // element, it should be treated as beginning a new line.
|
||||||
// // This behavior is somewhat controversial.
|
// // This behavior is somewhat controversial.
|
||||||
// $text = "\n" . $text;
|
// text = "\n" . text;
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// if (is_string($text) && !this.incrementIncludeSize('post-expand', strlen($text))) {
|
// if (is_string(text) && !this.incrementIncludeSize("post-expand", strlen(text))) {
|
||||||
// // Error, oversize inclusion
|
// // Error, oversize inclusion
|
||||||
// if ($titleText !== false) {
|
// if (titleText !== false) {
|
||||||
// // Make a working, properly escaped link if possible (T25588)
|
// // Make a working, properly escaped link if possible (T25588)
|
||||||
// $text = "[[:$titleText]]";
|
// text = "[[:titleText]]";
|
||||||
// } else {
|
// } else {
|
||||||
// // This will probably not be a working link, but at least it may
|
// // This will probably not be a working link, but at least it may
|
||||||
// // provide some hint of where the problem is
|
// // provide some hint of where the problem is
|
||||||
// preg_replace('/^:/', '', $originalTitle);
|
// preg_replace("/^:/", "", originalTitle);
|
||||||
// $text = "[[:$originalTitle]]";
|
// text = "[[:originalTitle]]";
|
||||||
// }
|
// }
|
||||||
// $text .= this.insertStripItem('<!-- WARNING: template omitted, '
|
// text .= this.insertStripItem("<!-- WARNING: template omitted, "
|
||||||
// . 'post-expand include size too large -->');
|
// . "post-expand include size too large -.");
|
||||||
// this.limitationWarn('post-expand-template-inclusion');
|
// this.limitationWarn("post-expand-template-inclusion");
|
||||||
// }
|
// }
|
||||||
//
|
|
||||||
// if ($isLocalObj) {
|
XophpArray ret;
|
||||||
// $ret = [ 'Object' => $text ];
|
if (isLocalObj) {
|
||||||
// } else {
|
ret = XophpArray.New("Object", text);
|
||||||
// $ret = [ 'text' => $text ];
|
} else {
|
||||||
// }
|
ret = XophpArray.New("text", text);
|
||||||
//
|
}
|
||||||
// return $ret;
|
Tfds.Write(nowiki, isHTML, forceRawInterwiki, isChildObj, isLocalObj, titleText, originalTitle);
|
||||||
return null;
|
return ret;
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// /**
|
// /**
|
||||||
// * Call a parser function and return an array with text and flags.
|
// * Call a parser function and return an array with text and flags.
|
||||||
// *
|
// *
|
||||||
|
@ -89,11 +89,11 @@ public class XomwParserOptions {
|
|||||||
*/
|
*/
|
||||||
private int mMaxPPExpandDepth;
|
private int mMaxPPExpandDepth;
|
||||||
|
|
||||||
// /**
|
/**
|
||||||
// * Maximum recursion depth for templates within templates
|
* Maximum recursion depth for templates within templates
|
||||||
// */
|
*/
|
||||||
// private $mMaxTemplateDepth;
|
private int mMaxTemplateDepth;
|
||||||
//
|
|
||||||
// /**
|
// /**
|
||||||
// * Maximum number of calls per parse to expensive parser functions
|
// * Maximum number of calls per parse to expensive parser functions
|
||||||
// */
|
// */
|
||||||
@ -288,10 +288,10 @@ public class XomwParserOptions {
|
|||||||
return this.mMaxPPExpandDepth;
|
return this.mMaxPPExpandDepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
// public function getMaxTemplateDepth() {
|
public int getMaxTemplateDepth() {
|
||||||
// return this.mMaxTemplateDepth;
|
return this.mMaxTemplateDepth;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// /* @since 1.20 */
|
// /* @since 1.20 */
|
||||||
// public function getExpensiveParserFunctionLimit() {
|
// public function getExpensiveParserFunctionLimit() {
|
||||||
// return this.mExpensiveParserFunctionLimit;
|
// return this.mExpensiveParserFunctionLimit;
|
||||||
@ -706,7 +706,7 @@ public class XomwParserOptions {
|
|||||||
this.mMaxPPNodeCount = XomwDefaultSettings.wgMaxPPNodeCount;
|
this.mMaxPPNodeCount = XomwDefaultSettings.wgMaxPPNodeCount;
|
||||||
// this.mMaxGeneratedPPNodeCount = $wgMaxGeneratedPPNodeCount;
|
// this.mMaxGeneratedPPNodeCount = $wgMaxGeneratedPPNodeCount;
|
||||||
this.mMaxPPExpandDepth = XomwDefaultSettings.wgMaxPPExpandDepth;
|
this.mMaxPPExpandDepth = XomwDefaultSettings.wgMaxPPExpandDepth;
|
||||||
// this.mMaxTemplateDepth = $wgMaxTemplateDepth;
|
this.mMaxTemplateDepth = XomwDefaultSettings.wgMaxTemplateDepth;
|
||||||
// this.mExpensiveParserFunctionLimit = $wgExpensiveParserFunctionLimit;
|
// this.mExpensiveParserFunctionLimit = $wgExpensiveParserFunctionLimit;
|
||||||
// this.mCleanSignatures = $wgCleanSignatures;
|
// this.mCleanSignatures = $wgCleanSignatures;
|
||||||
// this.mExternalLinkTarget = $wgExternalLinkTarget;
|
// this.mExternalLinkTarget = $wgExternalLinkTarget;
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
package gplx.xowa.mediawiki.includes.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*;
|
||||||
|
import org.junit.*;
|
||||||
|
public class XomwParser_internalParse_tst {
|
||||||
|
// private final XomwParser_fxt fxt = new XomwParser_fxt();
|
||||||
|
@Test public void Basic() {
|
||||||
|
// fxt.Test__internalParse(String_.Concat_lines_nl_skip_last
|
||||||
|
// ( "{{A}}"
|
||||||
|
// ), String_.Concat_lines_nl_skip_last
|
||||||
|
// ( ""
|
||||||
|
// ));
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,7 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
|||||||
*/
|
*/
|
||||||
package gplx.xowa.mediawiki.includes.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*;
|
package gplx.xowa.mediawiki.includes.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*;
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
import gplx.xowa.mediawiki.includes.parsers.preprocessors.*;
|
||||||
public class XomwParser_tst {
|
public class XomwParser_tst {
|
||||||
private final XomwParser_fxt fxt = new XomwParser_fxt();
|
private final XomwParser_fxt fxt = new XomwParser_fxt();
|
||||||
@Test public void Basic() {
|
@Test public void Basic() {
|
||||||
@ -75,4 +76,8 @@ class XomwParser_fxt {
|
|||||||
parser.internalParseHalfParsed(pbfr, pctx, true, true);
|
parser.internalParseHalfParsed(pbfr, pctx, true, true);
|
||||||
Tfds.Eq_str_lines(expd, pbfr.Rslt().To_str_and_clear(), src_str);
|
Tfds.Eq_str_lines(expd, pbfr.Rslt().To_str_and_clear(), src_str);
|
||||||
}
|
}
|
||||||
|
public void Test__internalParse(String src_str, String expd) {
|
||||||
|
String actl = parser.internalParse(src_str, false, new XomwPPFrame_Hash(new XomwPreprocessor_Hash(parser)));
|
||||||
|
Tfds.Eq_str_lines(expd, actl, src_str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ class XomwPreprocessor_DOM extends XomwPreprocessor { private final Bry_bfr
|
|||||||
int parts_len = parts.count();
|
int parts_len = parts.count();
|
||||||
for (int j = 0; j < parts_len; j++) {
|
for (int j = 0; j < parts_len; j++) {
|
||||||
XomwPPDPart_DOM part = (XomwPPDPart_DOM)parts.Get_at(j);
|
XomwPPDPart_DOM part = (XomwPPDPart_DOM)parts.Get_at(j);
|
||||||
if (part.eqpos != -1) {
|
if (part.eqpos != 0) {
|
||||||
byte[] part_bfr_bry = part.To_bry();
|
byte[] part_bfr_bry = part.To_bry();
|
||||||
tmp_bfr.Add_str_a7("<part><name>").Add_mid(part_bfr_bry, 0, part.eqpos);
|
tmp_bfr.Add_str_a7("<part><name>").Add_mid(part_bfr_bry, 0, part.eqpos);
|
||||||
tmp_bfr.Add_str_a7("</name>=<value>").Add_mid(part_bfr_bry, part.eqpos + 1, part.Len());
|
tmp_bfr.Add_str_a7("</name>=<value>").Add_mid(part_bfr_bry, part.eqpos + 1, part.Len());
|
||||||
|
@ -126,7 +126,7 @@ class XomwPreprocessor_Hash extends XomwPreprocessor { private XophpArray accum
|
|||||||
for (int j = 0; j < parts_len; j++) {
|
for (int j = 0; j < parts_len; j++) {
|
||||||
XomwPPDPart_Hash part = (XomwPPDPart_Hash)parts.Get_at(j);
|
XomwPPDPart_Hash part = (XomwPPDPart_Hash)parts.Get_at(j);
|
||||||
XophpArray part_out = (XophpArray)part.Accum_hash().Ary();
|
XophpArray part_out = (XophpArray)part.Accum_hash().Ary();
|
||||||
if (part.eqpos != -1) {
|
if (part.eqpos != 0) {
|
||||||
Object equalsNode = part_out.Get_at(part.eqpos);
|
Object equalsNode = part_out.Get_at(part.eqpos);
|
||||||
XophpArray nameNode = XophpArray.New("name" , XophpArray_.array_slice(part_out, 0, part.eqpos));
|
XophpArray nameNode = XophpArray.New("name" , XophpArray_.array_slice(part_out, 0, part.eqpos));
|
||||||
XophpArray valueNode = XophpArray.New("value", XophpArray_.array_slice(part_out, part.eqpos + 1));
|
XophpArray valueNode = XophpArray.New("value", XophpArray_.array_slice(part_out, part.eqpos + 1));
|
||||||
|
@ -22,36 +22,21 @@ public abstract class XomwPPDPart {
|
|||||||
/**
|
/**
|
||||||
* @var String Output accumulator String
|
* @var String Output accumulator String
|
||||||
*/
|
*/
|
||||||
// public final byte[] output;
|
public String output;
|
||||||
|
|
||||||
|
// REF.MW:https://manual.phpdoc.org/HTMLSmartyConverter/PHP/phpDocumentor/tutorial_tags.property.pkg.html
|
||||||
// Optional member variables:
|
// Optional member variables:
|
||||||
// eqpos Position of equals sign in output accumulator
|
// eqpos Position of equals sign in output accumulator
|
||||||
// commentEnd Past-the-end input pointer for the last comment encountered
|
// commentEnd Past-the-end input pointer for the last comment encountered
|
||||||
// visualEnd Past-the-end input pointer for the end of the accumulator minus comments
|
// visualEnd Past-the-end input pointer for the end of the accumulator minus comments
|
||||||
public int eqpos = -1;
|
public int eqpos;
|
||||||
public int commentEnd = -1;
|
public int commentEnd;
|
||||||
public int visualEnd = -1;
|
public int visualEnd;
|
||||||
|
|
||||||
public XomwPPDPart(String output) {
|
public XomwPPDPart(String output) {
|
||||||
// accum.Add_bry(Bry_.new_u8(output));
|
this.output = output;
|
||||||
// bfr = ((Xomw_prepro_accum__dom)accum).Bfr();
|
|
||||||
}
|
}
|
||||||
public abstract Xomw_prepro_accum Accum();
|
public abstract Xomw_prepro_accum Accum();
|
||||||
|
|
||||||
public abstract XomwPPDPart Make_new(String val);
|
public abstract XomwPPDPart Make_new(String val);
|
||||||
}
|
}
|
||||||
// class XomwPPDPart {
|
|
||||||
// /**
|
|
||||||
// * @var String Output accumulator String
|
|
||||||
// */
|
|
||||||
// public String output;
|
|
||||||
//
|
|
||||||
// // Optional member variables:
|
|
||||||
// // eqpos Position of equals sign in output accumulator
|
|
||||||
// // commentEnd Past-the-end input pointer for the last comment encountered
|
|
||||||
// // visualEnd Past-the-end input pointer for the end of the accumulator minus comments
|
|
||||||
//
|
|
||||||
// public XomwPPDPart(String output) {
|
|
||||||
// this.output = output;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
package gplx.xowa.mediawiki.includes.parsers.preprocessors; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*; import gplx.xowa.mediawiki.includes.parsers.*;
|
||||||
|
// MW.SRC:1.33
|
||||||
|
public class XomwPPDStack_Hash {
|
||||||
|
|
||||||
|
}
|
@ -32,6 +32,10 @@ public abstract class XomwPPFrame {
|
|||||||
/** This constant exists when $indexOffset is supported in newChild() */
|
/** This constant exists when $indexOffset is supported in newChild() */
|
||||||
public static final int SUPPORTS_INDEX_OFFSET = 1;
|
public static final int SUPPORTS_INDEX_OFFSET = 1;
|
||||||
|
|
||||||
|
// https://github.com/wikimedia/mediawiki/blob/ce615343ee8d192a65cf65f35f853c5ffcfad390/includes/parser/PPFrame.php#L25-L26
|
||||||
|
public int depth;
|
||||||
|
public XomwPPFrame parent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a child frame
|
* Create a child frame
|
||||||
*
|
*
|
||||||
@ -41,6 +45,7 @@ public abstract class XomwPPFrame {
|
|||||||
*
|
*
|
||||||
* @return PPFrame
|
* @return PPFrame
|
||||||
*/
|
*/
|
||||||
|
public XomwPPFrame newChild(Object args, XomwTitle title) {return newChild(args, title, 0);}
|
||||||
@gplx.Virtual public XomwPPFrame newChild(Object args, XomwTitle title, int indexOffset) {return null;}
|
@gplx.Virtual public XomwPPFrame newChild(Object args, XomwTitle title, int indexOffset) {return null;}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,6 +55,7 @@ public abstract class XomwPPFrame {
|
|||||||
* @param int $flags
|
* @param int $flags
|
||||||
* @return String
|
* @return String
|
||||||
*/
|
*/
|
||||||
|
public String cachedExpand(String key, XomwPPNode root) {return cachedExpand(key, root, 0);}
|
||||||
@gplx.Virtual public String cachedExpand(String key, XomwPPNode root, int flags) {return null;}
|
@gplx.Virtual public String cachedExpand(String key, XomwPPNode root, int flags) {return null;}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,7 +64,8 @@ public abstract class XomwPPFrame {
|
|||||||
* @param int $flags
|
* @param int $flags
|
||||||
* @return String
|
* @return String
|
||||||
*/
|
*/
|
||||||
@gplx.Virtual public String expand(XomwPPNode root, int flags) {return null;}
|
@gplx.Virtual public String expand(Object root) {return expand(root, 0);}
|
||||||
|
@gplx.Virtual public String expand(Object root, int flags) {return null;}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implode with flags for expand()
|
* Implode with flags for expand()
|
||||||
|
@ -20,7 +20,7 @@ import gplx.core.bits.*;
|
|||||||
* An expansion frame, used as a context to expand the result of preprocessToObj()
|
* An expansion frame, used as a context to expand the result of preprocessToObj()
|
||||||
* @ingroup Parser
|
* @ingroup Parser
|
||||||
*/
|
*/
|
||||||
class XomwPPFrame_Hash extends XomwPPFrame { /**
|
public class XomwPPFrame_Hash extends XomwPPFrame { /**
|
||||||
* @var Parser
|
* @var Parser
|
||||||
*/
|
*/
|
||||||
public XomwParser parser;
|
public XomwParser parser;
|
||||||
@ -46,7 +46,7 @@ class XomwPPFrame_Hash extends XomwPPFrame { /**
|
|||||||
* Recursion depth of this frame, top = 0
|
* Recursion depth of this frame, top = 0
|
||||||
* Note that this is NOT the same as expansion depth in expand()
|
* Note that this is NOT the same as expansion depth in expand()
|
||||||
*/
|
*/
|
||||||
public int depth;
|
@gplx.New public int depth;
|
||||||
|
|
||||||
private boolean volatile_bool;
|
private boolean volatile_bool;
|
||||||
private int ttl;
|
private int ttl;
|
||||||
@ -64,7 +64,7 @@ class XomwPPFrame_Hash extends XomwPPFrame { /**
|
|||||||
this.preprocessor = preprocessor;
|
this.preprocessor = preprocessor;
|
||||||
this.parser = preprocessor.Parser();
|
this.parser = preprocessor.Parser();
|
||||||
this.title = this.parser.mTitle;
|
this.title = this.parser.mTitle;
|
||||||
this.titleCache = XophpArray.New().Add(XophpObject_.is_true(this.title) ? this.title.getPrefixedDBkeyStr() : XophpString_.False);
|
this.titleCache = XophpArray.New(XophpObject_.is_true(this.title) ? this.title.getPrefixedDBkeyStr() : XophpString_.False);
|
||||||
this.loopCheckHash = XophpArray.New();
|
this.loopCheckHash = XophpArray.New();
|
||||||
this.depth = 0;
|
this.depth = 0;
|
||||||
this.childExpansionCache = XophpArray.New();
|
this.childExpansionCache = XophpArray.New();
|
||||||
@ -105,11 +105,11 @@ class XomwPPFrame_Hash extends XomwPPFrame { /**
|
|||||||
// Numbered parameter
|
// Numbered parameter
|
||||||
int index = bits.Get_by_int("index") - indexOffset;
|
int index = bits.Get_by_int("index") - indexOffset;
|
||||||
if (namedArgs.isset(index) || numberedArgs.isset(index)) {
|
if (namedArgs.isset(index) || numberedArgs.isset(index)) {
|
||||||
// this.parser.getOutput().addWarning(wfMessage('duplicate-args-warning',
|
// this.parser.getOutput().addWarning(wfMessage('duplicate-args-warning',
|
||||||
// wfEscapeWikiText(this.title),
|
// wfEscapeWikiText(this.title),
|
||||||
// wfEscapeWikiText(title),
|
// wfEscapeWikiText(title),
|
||||||
// wfEscapeWikiText(index)).text());
|
// wfEscapeWikiText(index)).text());
|
||||||
// this.parser.addTrackingCategory('duplicate-args-category');
|
// this.parser.addTrackingCategory('duplicate-args-category');
|
||||||
}
|
}
|
||||||
numberedArgs.Set(index, bits.Get_by("value"));
|
numberedArgs.Set(index, bits.Get_by("value"));
|
||||||
namedArgs.unset(index);
|
namedArgs.unset(index);
|
||||||
@ -117,11 +117,11 @@ class XomwPPFrame_Hash extends XomwPPFrame { /**
|
|||||||
// Named parameter
|
// Named parameter
|
||||||
String name = String_.Trim(this.expand(bits.Get_by("name"), XomwPPFrame.STRIP_COMMENTS));
|
String name = String_.Trim(this.expand(bits.Get_by("name"), XomwPPFrame.STRIP_COMMENTS));
|
||||||
if (namedArgs.isset(name) || numberedArgs.isset(name)) {
|
if (namedArgs.isset(name) || numberedArgs.isset(name)) {
|
||||||
// this.parser.getOutput().addWarning(wfMessage('duplicate-args-warning',
|
// this.parser.getOutput().addWarning(wfMessage('duplicate-args-warning',
|
||||||
// wfEscapeWikiText(this.title),
|
// wfEscapeWikiText(this.title),
|
||||||
// wfEscapeWikiText(title),
|
// wfEscapeWikiText(title),
|
||||||
// wfEscapeWikiText(name)).text());
|
// wfEscapeWikiText(name)).text());
|
||||||
// this.parser.addTrackingCategory('duplicate-args-category');
|
// this.parser.addTrackingCategory('duplicate-args-category');
|
||||||
}
|
}
|
||||||
namedArgs.Set(name, bits.Get_by("value"));
|
namedArgs.Set(name, bits.Get_by("value"));
|
||||||
numberedArgs.unset(name);
|
numberedArgs.unset(name);
|
||||||
@ -151,23 +151,23 @@ class XomwPPFrame_Hash extends XomwPPFrame { /**
|
|||||||
* @param int $flags
|
* @param int $flags
|
||||||
* @return String
|
* @return String
|
||||||
*/
|
*/
|
||||||
public String expand(Object root, int flags) {
|
@Override public String expand(Object root, int flags) {
|
||||||
if (XophpString_.is_string(root)) {
|
if (XophpString_.is_string(root)) {
|
||||||
return (String)root;
|
return (String)root;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (++this.parser.mPPNodeCount > this.parser.mOptions.getMaxPPNodeCount()) {
|
if (++this.parser.mPPNodeCount > this.parser.mOptions.getMaxPPNodeCount()) {
|
||||||
// this.parser.limitationWarn('node-count-exceeded',
|
// this.parser.limitationWarn('node-count-exceeded',
|
||||||
// this.parser.mPPNodeCount,
|
// this.parser.mPPNodeCount,
|
||||||
// this.parser.mOptions.getMaxPPNodeCount()
|
// this.parser.mOptions.getMaxPPNodeCount()
|
||||||
// );
|
// );
|
||||||
return "<span class=\"error\">Node-count limit exceeded</span>";
|
return "<span class=\"error\">Node-count limit exceeded</span>";
|
||||||
}
|
}
|
||||||
if (expansionDepth > this.parser.mOptions.getMaxPPExpandDepth()) {
|
if (expansionDepth > this.parser.mOptions.getMaxPPExpandDepth()) {
|
||||||
// this.parser.limitationWarn('expansion-depth-exceeded',
|
// this.parser.limitationWarn('expansion-depth-exceeded',
|
||||||
// expansionDepth,
|
// expansionDepth,
|
||||||
// this.parser.mOptions.getMaxPPExpandDepth()
|
// this.parser.mOptions.getMaxPPExpandDepth()
|
||||||
// );
|
// );
|
||||||
return "<span class=\"error\">Expansion depth limit exceeded</span>";
|
return "<span class=\"error\">Expansion depth limit exceeded</span>";
|
||||||
}
|
}
|
||||||
++expansionDepth;
|
++expansionDepth;
|
||||||
@ -396,7 +396,7 @@ class XomwPPFrame_Hash extends XomwPPFrame { /**
|
|||||||
root = (XophpArray)((XomwPPNode_Hash_Array)root_obj).value;
|
root = (XophpArray)((XomwPPNode_Hash_Array)root_obj).value;
|
||||||
}
|
}
|
||||||
if (!XophpType_.is_array(root_obj)) {
|
if (!XophpType_.is_array(root_obj)) {
|
||||||
root = XophpArray.New().Add(root_obj);
|
root = XophpArray.New(root_obj);
|
||||||
}
|
}
|
||||||
int root_len = root.Len();
|
int root_len = root.Len();
|
||||||
for (int j = 0; j < root_len; j++) {
|
for (int j = 0; j < root_len; j++) {
|
||||||
@ -428,7 +428,7 @@ class XomwPPFrame_Hash extends XomwPPFrame { /**
|
|||||||
root = ((XomwPPNode_Hash_Array)rootObj).value;
|
root = ((XomwPPNode_Hash_Array)rootObj).value;
|
||||||
}
|
}
|
||||||
if (!XophpArray.is_array(rootObj)) {
|
if (!XophpArray.is_array(rootObj)) {
|
||||||
root = XophpArray.New().Add(root);
|
root = XophpArray.New(root);
|
||||||
}
|
}
|
||||||
int rootLen = root.count();
|
int rootLen = root.count();
|
||||||
for (int i = 0; i < rootLen; i++) {
|
for (int i = 0; i < rootLen; i++) {
|
||||||
@ -462,7 +462,7 @@ class XomwPPFrame_Hash extends XomwPPFrame { /**
|
|||||||
root = ((XomwPPNode_Hash_Array)rootObj).value;
|
root = ((XomwPPNode_Hash_Array)rootObj).value;
|
||||||
}
|
}
|
||||||
if (!XophpArray.is_array(rootObj)) {
|
if (!XophpArray.is_array(rootObj)) {
|
||||||
root = XophpArray.New().Add(root);
|
root = XophpArray.New(root);
|
||||||
}
|
}
|
||||||
int rootLen = root.count();
|
int rootLen = root.count();
|
||||||
for (int i = 0; i < rootLen; i++) {
|
for (int i = 0; i < rootLen; i++) {
|
||||||
|
@ -365,7 +365,7 @@ public class XomwPPNode_Hash_Tree extends XomwPPNode { public final String na
|
|||||||
*/
|
*/
|
||||||
public static XophpArray splitRawTemplate(XophpArray children) {
|
public static XophpArray splitRawTemplate(XophpArray children) {
|
||||||
XophpArray parts = XophpArray.New();
|
XophpArray parts = XophpArray.New();
|
||||||
XophpArray bits = XophpArray.New().Add("lineStart" , "");
|
XophpArray bits = XophpArray.New("lineStart" , "");
|
||||||
int len = children.count();
|
int len = children.count();
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
Object childObj = children.Get_at(i);
|
Object childObj = children.Get_at(i);
|
||||||
|
@ -19,7 +19,7 @@ package gplx.xowa.mediawiki.includes.parsers.preprocessors; import gplx.*; impor
|
|||||||
// * @ingroup Parser
|
// * @ingroup Parser
|
||||||
// */
|
// */
|
||||||
class XomwPPTemplateFrame_Hash extends XomwPPFrame_Hash { public XophpArray numberedArgs, namedArgs;
|
class XomwPPTemplateFrame_Hash extends XomwPPFrame_Hash { public XophpArray numberedArgs, namedArgs;
|
||||||
public XomwPPFrame_Hash parent;
|
@gplx.New public XomwPPFrame_Hash parent;
|
||||||
public XophpArray numberedExpansionCache, namedExpansionCache;
|
public XophpArray numberedExpansionCache, namedExpansionCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
package gplx.xowa.mediawiki.includes.parsers.preprocessors_new; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*; import gplx.xowa.mediawiki.includes.parsers.*;
|
||||||
|
// MW.SRC:1.33
|
||||||
|
public abstract class XomwPPDPart {
|
||||||
|
/**
|
||||||
|
* @var String Output accumulator String
|
||||||
|
*/
|
||||||
|
public XophpArray output;
|
||||||
|
|
||||||
|
// REF.MW:https://manual.phpdoc.org/HTMLSmartyConverter/PHP/phpDocumentor/tutorial_tags.property.pkg.html
|
||||||
|
// Optional member variables:
|
||||||
|
// eqpos Position of equals sign in output accumulator
|
||||||
|
// commentEnd Past-the-end input pointer for the last comment encountered
|
||||||
|
// visualEnd Past-the-end input pointer for the end of the accumulator minus comments
|
||||||
|
public int eqpos;
|
||||||
|
public int commentEnd;
|
||||||
|
public int visualEnd;
|
||||||
|
|
||||||
|
public void ctor_XomwPPDPart(XophpArray output) {
|
||||||
|
this.output = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XomwPPDPart New() {return New("");}
|
||||||
|
public abstract XomwPPDPart New(String val);
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
package gplx.xowa.mediawiki.includes.parsers.preprocessors_new; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*; import gplx.xowa.mediawiki.includes.parsers.*;
|
||||||
|
/**
|
||||||
|
* @ingroup Parser
|
||||||
|
*/
|
||||||
|
public class XomwPPDPart_Hash extends XomwPPDPart {
|
||||||
|
public XomwPPDPart_Hash(String output) {
|
||||||
|
XophpArray accum;
|
||||||
|
if (XophpString_.eq_not(output, "")) {
|
||||||
|
accum = XophpArray.New(output);
|
||||||
|
} else {
|
||||||
|
accum = XophpArray.New();
|
||||||
|
}
|
||||||
|
this.ctor_XomwPPDPart(accum);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XomwPPDPart New(String val) {return new XomwPPDPart_Hash(val);}
|
||||||
|
|
||||||
|
public static final XomwPPDPart_Hash Instance = new XomwPPDPart_Hash("");
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
package gplx.xowa.mediawiki.includes.parsers.preprocessors_new; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*; import gplx.xowa.mediawiki.includes.parsers.*;
|
||||||
|
// MW.SRC:1.33
|
||||||
|
import gplx.xowa.mediawiki.includes.exception.*;
|
||||||
|
/**
|
||||||
|
* Stack class to help Preprocessor::preprocessToObj()
|
||||||
|
* @ingroup Parser
|
||||||
|
*/
|
||||||
|
public class XomwPPDStack {
|
||||||
|
public XophpArray stack;
|
||||||
|
public XophpArray rootAccum;
|
||||||
|
public XophpArray accum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var PPDStack
|
||||||
|
*/
|
||||||
|
public XomwPPDStackElement top;
|
||||||
|
// public out;
|
||||||
|
public XomwPPDStackElement elementClass;
|
||||||
|
|
||||||
|
// public static false = false;
|
||||||
|
private final XomwPPDPart partClass;
|
||||||
|
|
||||||
|
public XomwPPDStack(XomwPPDPart partClass) {
|
||||||
|
this.stack = XophpArray.New();
|
||||||
|
this.top = null;
|
||||||
|
this.rootAccum = XophpArray.New("");
|
||||||
|
this.accum = this.rootAccum; // =&
|
||||||
|
|
||||||
|
this.partClass = partClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public int count() {
|
||||||
|
return XophpArray_.count(this.stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
public XophpArray getAccum() { // &getAccum
|
||||||
|
return this.accum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return boolean|PPDPart
|
||||||
|
*/
|
||||||
|
public XomwPPDPart getCurrentPart() {
|
||||||
|
if (XophpObject_.is_false(this.top)) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return this.top.getCurrentPart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void push(Object data) {
|
||||||
|
if (XophpType_.instance_of(data, XomwPPDStackElement.class)) {
|
||||||
|
this.stack.Add(data);
|
||||||
|
} else {
|
||||||
|
XophpArray array = (XophpArray)data;
|
||||||
|
this.stack.Add(elementClass.New(partClass, array.Get_by_str("open"), array.Get_by_str("close"), array.Get_by_ary_or("parts", null), array.Get_by_int_or("count", 0), array.Get_by_bool_or("lineStart", false), array.Get_by_int_or("startPos", 0)));
|
||||||
|
}
|
||||||
|
this.top = (XomwPPDStackElement)this.stack.Get_at(XophpArray_.count(this.stack) - 1);
|
||||||
|
this.accum = this.top.getAccum(); //=&
|
||||||
|
}
|
||||||
|
|
||||||
|
public XomwPPDStackElement pop() {
|
||||||
|
if (this.stack.Eq_to_new()) {
|
||||||
|
throw XomwMWException.New_by_method_obj(this, "pop", ": no elements remaining");
|
||||||
|
}
|
||||||
|
XomwPPDStackElement temp = (XomwPPDStackElement)XophpArray_.array_pop(this.stack);
|
||||||
|
|
||||||
|
if (XophpArray_.count_bool(this.stack)) {
|
||||||
|
this.top = (XomwPPDStackElement)this.stack.Get_at(XophpArray_.count(this.stack) - 1);
|
||||||
|
this.accum = this.top.getAccum(); // =&
|
||||||
|
} else {
|
||||||
|
this.top = null;
|
||||||
|
this.accum = this.rootAccum; // =&
|
||||||
|
}
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPart() {addPart("");}
|
||||||
|
public void addPart(String s) {
|
||||||
|
this.top.addPart(s);
|
||||||
|
this.accum = this.top.getAccum(); // =&
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public XophpArray getFlags() {
|
||||||
|
if (this.stack.Eq_to_new()) {
|
||||||
|
return XophpArray.New()
|
||||||
|
.Add("findEquals", false)
|
||||||
|
.Add("findPipe", false)
|
||||||
|
.Add("inHeading", false)
|
||||||
|
;
|
||||||
|
} else {
|
||||||
|
return this.top.getFlags();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
package gplx.xowa.mediawiki.includes.parsers.preprocessors_new; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*; import gplx.xowa.mediawiki.includes.parsers.*;
|
||||||
|
// MW.SRC:1.33
|
||||||
|
/**
|
||||||
|
* Stack cl+ass to help Preprocessor::preprocessToObj()
|
||||||
|
* @ingroup Parser
|
||||||
|
*/
|
||||||
|
public abstract class XomwPPDStackElement {
|
||||||
|
/**
|
||||||
|
* @var String Opening character (\n for heading)
|
||||||
|
*/
|
||||||
|
public String open;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var String Matching closing character
|
||||||
|
*/
|
||||||
|
public String close;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var String Saved prefix that may affect later processing,
|
||||||
|
* e.g. to differentiate `-{{{{` and `{{{{` after later seeing `}}}`.
|
||||||
|
*/
|
||||||
|
public String savedPrefix = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int Number of opening characters found (number of "=" for heading)
|
||||||
|
*/
|
||||||
|
public int count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var PPDPart[] Array of PPDPart objects describing pipe-separated parts.
|
||||||
|
*/
|
||||||
|
public XophpArray parts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var boolean True if the open char appeared at the start of the input line.
|
||||||
|
* Not set for headings.
|
||||||
|
*/
|
||||||
|
public boolean lineStart;
|
||||||
|
|
||||||
|
public XomwPPDPart partClass;// = new XomwPPDPart("");
|
||||||
|
|
||||||
|
public int startPos; // XO.NOTE: added from Preprocessor_Hash; assume this is magic property somewhere
|
||||||
|
|
||||||
|
public XomwPPDStackElement(XomwPPDPart partClass, String open, String close, XophpArray parts, int count, boolean lineStart, int startPos) {
|
||||||
|
this.partClass = partClass;
|
||||||
|
this.parts = parts == null ? XophpArray.New(partClass.New()) : parts;
|
||||||
|
|
||||||
|
// XO.NOTE: PHP does XophpArray.New().Add("open", open)... but PHP does reflection-like assignment of array members to class members;
|
||||||
|
// EX: foreach (item in data) {item.key = item.val;}
|
||||||
|
this.open = open;
|
||||||
|
this.close = close;
|
||||||
|
this.count = count;
|
||||||
|
this.lineStart = lineStart;
|
||||||
|
this.startPos = startPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XophpArray getAccum() {
|
||||||
|
return (XophpArray)((XomwPPDPart)(this.parts.Get_at(XophpArray_.count(this.parts) - 1))).output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPart(String s) { // s = ""
|
||||||
|
XomwPPDPart clz = this.partClass;
|
||||||
|
this.parts.Add(clz.New(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return PPDPart
|
||||||
|
*/
|
||||||
|
public XomwPPDPart getCurrentPart() {
|
||||||
|
return (XomwPPDPart)this.parts.Get_at(XophpArray_.count(this.parts) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public XophpArray getFlags() {
|
||||||
|
int partCount = XophpArray_.count(this.parts);
|
||||||
|
boolean findPipe = !String_.Eq(this.open, "\n") && !String_.Eq(this.open, "[");
|
||||||
|
return XophpArray.New()
|
||||||
|
.Add("findPipe", findPipe)
|
||||||
|
.Add("findEquals", findPipe && partCount > 1 && !XophpObject_.isset_obj(((XomwPPDPart)this.parts.Get_at(partCount - 1)).eqpos))
|
||||||
|
.Add("inHeading", String_.Eq(this.open, "\n"))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the output String that would result if the close is not found.
|
||||||
|
*
|
||||||
|
* @param boolean|int $openingCount
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
// Used by XomwPPDStackElement_DOM
|
||||||
|
// public String breakSyntax(int openingCount) { // openingCount = false
|
||||||
|
// String s = null;
|
||||||
|
// if (String_.Eq(this.open, "\n")) {
|
||||||
|
// s = this.savedPrefix + ((XomwPPDPart)this.parts.Get_at(0)).output;
|
||||||
|
// } else {
|
||||||
|
// if (XophpInt_.is_false(openingCount)) {
|
||||||
|
// openingCount = this.count;
|
||||||
|
// }
|
||||||
|
// s = XophpString_.substr(this.open, 0, -1);
|
||||||
|
// s += XophpString_.str_repeat(
|
||||||
|
// XophpString_.substr(this.open, -1),
|
||||||
|
// openingCount - XophpString_.strlen(s)
|
||||||
|
// );
|
||||||
|
// s = this.savedPrefix + s;
|
||||||
|
// boolean first = true;
|
||||||
|
// int parts_len = this.parts.Len();
|
||||||
|
// for (int i = 0; i < parts_len; i++) {
|
||||||
|
// XomwPPDPart part = (XomwPPDPart)this.parts.Get_at(i);
|
||||||
|
// if (first) {
|
||||||
|
// first = false;
|
||||||
|
// } else {
|
||||||
|
// s += '|';
|
||||||
|
// }
|
||||||
|
// s += part.output;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return s;
|
||||||
|
// }
|
||||||
|
|
||||||
|
public abstract XomwPPDStackElement New(XomwPPDPart partClass, String open, String close, XophpArray parts, int count, boolean lineStart, int startPos);
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
package gplx.xowa.mediawiki.includes.parsers.preprocessors_new; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*; import gplx.xowa.mediawiki.includes.parsers.*;
|
||||||
|
// MW.SRC:1.33
|
||||||
|
class XomwPPDStackElement_Hash extends XomwPPDStackElement {
|
||||||
|
public XomwPPDStackElement_Hash(XomwPPDPart partClass, String open, String close, XophpArray parts, int count, boolean lineStart, int startPos) {super(partClass, open, close, parts, count, lineStart, startPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the accumulator that would result if the close is not found.
|
||||||
|
*
|
||||||
|
* @param int|boolean $openingCount
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public XophpArray breakSyntax() {return breakSyntax(0);}
|
||||||
|
public XophpArray breakSyntax(int openingCount) {
|
||||||
|
XophpArray accum;
|
||||||
|
if (String_.Eq(this.open, "\n")) {
|
||||||
|
accum = XophpArray_.array_merge(XophpArray.New(this.savedPrefix), XophpArray.New(((XomwPPDPart)this.parts.Get_at(0)).output));
|
||||||
|
} else {
|
||||||
|
if (XophpInt_.is_false(openingCount)) {
|
||||||
|
openingCount = this.count;
|
||||||
|
}
|
||||||
|
String s = XophpString_.substr(this.open, 0, -1);
|
||||||
|
s += XophpString_.str_repeat(
|
||||||
|
XophpString_.substr(this.open, -1),
|
||||||
|
openingCount - XophpString_.strlen(s)
|
||||||
|
);
|
||||||
|
accum = XophpArray.New(this.savedPrefix + s);
|
||||||
|
int lastIndex = 0;
|
||||||
|
boolean first = true;
|
||||||
|
int parts_len = this.parts.Len();
|
||||||
|
for (int i = 0; i < parts_len; i++) {
|
||||||
|
XomwPPDPart part = (XomwPPDPart)this.parts.Get_at(i);
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
} else if (XophpType_.is_string(accum.Get_at(lastIndex))) {
|
||||||
|
accum.Concat_str(lastIndex, "|");
|
||||||
|
} else {
|
||||||
|
accum.Set(++lastIndex, "|");
|
||||||
|
}
|
||||||
|
|
||||||
|
XophpArray partOutput = part.output;
|
||||||
|
int partOutputLen = partOutput.Len();
|
||||||
|
for (int j = 0; j < partOutputLen; j++) {
|
||||||
|
Object node = partOutput.Get_at(j);
|
||||||
|
if (XophpType_.is_string(node) && XophpType_.is_string(accum.Get_at(lastIndex))) {
|
||||||
|
accum.Concat_str(lastIndex, (String)node);
|
||||||
|
} else {
|
||||||
|
accum.Set(++lastIndex, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return accum;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XomwPPDStackElement New(XomwPPDPart partClass, String open, String close, XophpArray parts, int count, boolean lineStart, int startPos) {return new XomwPPDStackElement_Hash(partClass, open, close, parts, count, lineStart, startPos);}
|
||||||
|
|
||||||
|
public static final XomwPPDStackElement_Hash Prototype = new XomwPPDStackElement_Hash(new XomwPPDPart_Hash(""), null, null, null, 0, false, 0);
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
package gplx.xowa.mediawiki.includes.parsers.preprocessors_new; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*; import gplx.xowa.mediawiki.includes.parsers.*;
|
||||||
|
// MW.SRC:1.33
|
||||||
|
/**
|
||||||
|
* Stack cl+ass to help Preprocessor::preprocessToObj()
|
||||||
|
* @ingroup Parser
|
||||||
|
*/
|
||||||
|
public class XomwPPDStack_Hash extends XomwPPDStack {
|
||||||
|
public XomwPPDStack_Hash(XomwPPDPart partClass) {super(partClass);
|
||||||
|
this.elementClass = XomwPPDStackElement_Hash.Prototype;
|
||||||
|
// this.rootAccum = XophpArray.New(); // XO.NOTE: PHP does accum &= rootAccum, so doing "this.rootAccum = XophpArray.New()" will also do "accum = this.rootAccum" automatically
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,205 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
package gplx.xowa.mediawiki.includes.parsers.preprocessors_new; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*; import gplx.xowa.mediawiki.includes.parsers.*;
|
||||||
|
// MW.FILE:Preprocessor
|
||||||
|
/**
|
||||||
|
* @ingroup Parser
|
||||||
|
*/
|
||||||
|
// XOWA: TODO: change VIRTUAL back to ABSTRACT; WHEN: after adding _DOM classes
|
||||||
|
public abstract class XomwPPFrame {
|
||||||
|
public static final int NO_ARGS = 1;
|
||||||
|
public static final int NO_TEMPLATES = 2;
|
||||||
|
public static final int STRIP_COMMENTS = 4;
|
||||||
|
public static final int NO_IGNORE = 8;
|
||||||
|
public static final int RECOVER_COMMENTS = 16;
|
||||||
|
public static final int NO_TAGS = 32;
|
||||||
|
|
||||||
|
public static final int RECOVER_ORIG = 59; // = 1|2|8|16|32 no constant expression support in PHP yet
|
||||||
|
|
||||||
|
/** This constant exists when $indexOffset is supported in newChild() */
|
||||||
|
public static final int SUPPORTS_INDEX_OFFSET = 1;
|
||||||
|
|
||||||
|
// https://github.com/wikimedia/mediawiki/blob/ce615343ee8d192a65cf65f35f853c5ffcfad390/includes/parser/PPFrame.php#L25-L26
|
||||||
|
public int depth;
|
||||||
|
public XomwPPFrame parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a child frame
|
||||||
|
*
|
||||||
|
* @param array|boolean $args
|
||||||
|
* @param boolean|Title $title
|
||||||
|
* @param int $indexOffset A number subtracted from the index attributes of the arguments
|
||||||
|
*
|
||||||
|
* @return PPFrame
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public XomwPPFrame newChild(Object args, XomwTitle title, int indexOffset) {return null;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expand a document tree node, caching the result on its parent with the given key
|
||||||
|
* @param String|int $key
|
||||||
|
* @param String|PPNode $root
|
||||||
|
* @param int $flags
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public String cachedExpand(String key, XomwPPNode root, int flags) {return null;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expand a document tree node
|
||||||
|
* @param String|PPNode $root
|
||||||
|
* @param int $flags
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public String expand(Object root) {return expand(root, 0);}
|
||||||
|
@gplx.Virtual public String expand(Object root, int flags) {return null;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implode with flags for expand()
|
||||||
|
* @param String $sep
|
||||||
|
* @param int $flags
|
||||||
|
* @param String|PPNode $args,...
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public String implodeWithFlags(String sep, int flags, Object... args) {return null;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implode with no flags specified
|
||||||
|
* @param String $sep
|
||||||
|
* @param String|PPNode $args,...
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public String implode(String sep, Object... args) {return null;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes an Object that, when expand()ed, will be the same as one obtained
|
||||||
|
* with implode()
|
||||||
|
* @param String $sep
|
||||||
|
* @param String|PPNode $args,...
|
||||||
|
* @return PPNode
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public XomwPPNode virtualImplode(String sep, Object... args) {return null;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual implode with brackets
|
||||||
|
* @param String $start
|
||||||
|
* @param String $sep
|
||||||
|
* @param String $end
|
||||||
|
* @param String|PPNode $args,...
|
||||||
|
* @return PPNode
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public XomwPPNode virtualBracketedImplode(String start, String sep, String end, Object... args) {return null;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if there are no arguments in this frame
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public boolean isEmpty() {return false;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all arguments of this frame
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public XophpArray getArguments() {return null;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all numbered arguments of this frame
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public XophpArray getNumberedArguments() {return null;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all named arguments of this frame
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public XophpArray getNamedArguments() {return null;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an argument to this frame by name
|
||||||
|
* @param int|String $name
|
||||||
|
* @return String|boolean
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public String getArgument(String name) {return null;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the infinite loop check is OK, false if a loop is detected
|
||||||
|
*
|
||||||
|
* @param Title $title
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public boolean loopCheck(XomwTitle title) {return false;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the frame is a template frame
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public boolean isTemplate() {return false;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the "volatile" flag.
|
||||||
|
*
|
||||||
|
* Note that this is somewhat of a "hack" in order to make extensions
|
||||||
|
* with side effects (such as Cite) work with the PHP parser. New
|
||||||
|
* extensions should be written in a way that they do not need this
|
||||||
|
* function, because other parsers (such as Parsoid) are not guaranteed
|
||||||
|
* to respect it, and it may be removed in the future.
|
||||||
|
*
|
||||||
|
* @param boolean $flag
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public void setVolatile(boolean flag) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the "volatile" flag.
|
||||||
|
*
|
||||||
|
* Callers should avoid caching the result of an expansion if it has the
|
||||||
|
* volatile flag set.
|
||||||
|
*
|
||||||
|
* @see self::setVolatile()
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public boolean isVolatile() {return false;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the TTL of the frame's output.
|
||||||
|
*
|
||||||
|
* This is the maximum amount of time, in seconds, that this frame's
|
||||||
|
* output should be cached for. A value of null indicates that no
|
||||||
|
* maximum has been specified.
|
||||||
|
*
|
||||||
|
* Note that this TTL only applies to caching frames as parts of pages.
|
||||||
|
* It is not relevant to caching the entire rendered output of a page.
|
||||||
|
*
|
||||||
|
* @return int|null
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public int getTTL() {return 0;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the TTL of the output of this frame and all of its ancestors.
|
||||||
|
* Has no effect if the new TTL is greater than the one already set.
|
||||||
|
* Note that it is the caller's responsibility to change the cache
|
||||||
|
* expiry of the page as a whole, if such behavior is desired.
|
||||||
|
*
|
||||||
|
* @see self::getTTL()
|
||||||
|
* @param int $ttl
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public void setTTL(int ttl) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a title of frame
|
||||||
|
*
|
||||||
|
* @return Title
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public XomwTitle getTitle() {return null;}
|
||||||
|
}
|
@ -0,0 +1,638 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
package gplx.xowa.mediawiki.includes.parsers.preprocessors_new; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*; import gplx.xowa.mediawiki.includes.parsers.*;
|
||||||
|
import gplx.xowa.mediawiki.includes.exception.*;
|
||||||
|
import gplx.core.bits.*;
|
||||||
|
/**
|
||||||
|
* An expansion frame, used as a context to expand the result of preprocessToObj()
|
||||||
|
* @ingroup Parser
|
||||||
|
*/
|
||||||
|
public class XomwPPFrame_Hash extends XomwPPFrame { // /**
|
||||||
|
// * @var Parser
|
||||||
|
// */
|
||||||
|
// public XomwParser parser;
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * @var Preprocessor
|
||||||
|
// */
|
||||||
|
// public XomwPreprocessor preprocessor;
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * @var Title
|
||||||
|
// */
|
||||||
|
// public XomwTitle title;
|
||||||
|
// public XophpArray titleCache;
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Hashtable listing templates which are disallowed for expansion in this frame,
|
||||||
|
// * having been encountered previously in parent frames.
|
||||||
|
// */
|
||||||
|
// public XophpArray loopCheckHash;
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Recursion depth of this frame, top = 0
|
||||||
|
// * Note that this is NOT the same as expansion depth in expand()
|
||||||
|
// */
|
||||||
|
// @gplx.New public int depth;
|
||||||
|
//
|
||||||
|
// private boolean volatile_bool;
|
||||||
|
// private int ttl;
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * @var array
|
||||||
|
// */
|
||||||
|
// public XophpArray childExpansionCache;
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Construct a new preprocessor frame.
|
||||||
|
// * @param Preprocessor preprocessor The parent preprocessor
|
||||||
|
// */
|
||||||
|
public XomwPPFrame_Hash(XomwPreprocessor preprocessor) {
|
||||||
|
// this.preprocessor = preprocessor;
|
||||||
|
// this.parser = preprocessor.Parser();
|
||||||
|
// this.title = this.parser.mTitle;
|
||||||
|
// this.titleCache = XophpArray.New(XophpObject_.is_true(this.title) ? this.title.getPrefixedDBkeyStr() : XophpString_.False);
|
||||||
|
// this.loopCheckHash = XophpArray.New();
|
||||||
|
// this.depth = 0;
|
||||||
|
// this.childExpansionCache = XophpArray.New();
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Create a new child frame
|
||||||
|
// * $args is optionally a multi-root PPNode or array containing the template arguments
|
||||||
|
// *
|
||||||
|
// * @param array|boolean|PPNode_Hash_Array $args
|
||||||
|
// * @param Title|boolean $title
|
||||||
|
// * @param int $indexOffset
|
||||||
|
// * @throws MWException
|
||||||
|
// * @return PPTemplateFrame_Hash
|
||||||
|
// */
|
||||||
|
// public override XomwPPFrame newChild(Object argsObj, XomwTitle title, int indexOffset) {
|
||||||
|
// XophpArray namedArgs = XophpArray.New();
|
||||||
|
// XophpArray numberedArgs = XophpArray.New();
|
||||||
|
// if (!XophpObject_.is_true(title)) {
|
||||||
|
// title = this.title;
|
||||||
|
// }
|
||||||
|
// if (XophpObject_.is_true(argsObj)) {
|
||||||
|
// XophpArray args = null;
|
||||||
|
// if (Type_.Eq_by_obj(argsObj, typeof(XomwPPNode_Hash_Array))) {
|
||||||
|
// args = ((XomwPPNode_Hash_Array)argsObj).value;
|
||||||
|
// } else if (!XophpArray.is_array(argsObj)) {
|
||||||
|
// throw XomwMWException.New_by_method(typeof(XomwPPFrame_Hash), "newChild", ": args must be array or PPNode_Hash_Array");
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// args = (XophpArray)argsObj;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// int argsLen = args.count();
|
||||||
|
// for (int i = 0; i < argsLen; i++) {
|
||||||
|
// XomwPPNode arg = (XomwPPNode)args.Get_at(i);
|
||||||
|
// XophpArray bits = arg.splitArg();
|
||||||
|
// if (bits.Has("index")) {
|
||||||
|
// // Numbered parameter
|
||||||
|
// int index = bits.Get_by_int("index") - indexOffset;
|
||||||
|
// if (namedArgs.isset(index) || numberedArgs.isset(index)) {
|
||||||
|
// // this.parser.getOutput().addWarning(wfMessage('duplicate-args-warning',
|
||||||
|
// // wfEscapeWikiText(this.title),
|
||||||
|
// // wfEscapeWikiText(title),
|
||||||
|
// // wfEscapeWikiText(index)).text());
|
||||||
|
// // this.parser.addTrackingCategory('duplicate-args-category');
|
||||||
|
// }
|
||||||
|
// numberedArgs.Set(index, bits.Get_by("value"));
|
||||||
|
// namedArgs.unset(index);
|
||||||
|
// } else {
|
||||||
|
// // Named parameter
|
||||||
|
// String name = String_.Trim(this.expand(bits.Get_by("name"), XomwPPFrame.STRIP_COMMENTS));
|
||||||
|
// if (namedArgs.isset(name) || numberedArgs.isset(name)) {
|
||||||
|
// // this.parser.getOutput().addWarning(wfMessage('duplicate-args-warning',
|
||||||
|
// // wfEscapeWikiText(this.title),
|
||||||
|
// // wfEscapeWikiText(title),
|
||||||
|
// // wfEscapeWikiText(name)).text());
|
||||||
|
// // this.parser.addTrackingCategory('duplicate-args-category');
|
||||||
|
// }
|
||||||
|
// namedArgs.Set(name, bits.Get_by("value"));
|
||||||
|
// numberedArgs.unset(name);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return new XomwPPTemplateFrame_Hash(this.preprocessor, this, numberedArgs, namedArgs, title);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * @throws MWException
|
||||||
|
// * @param String|int $key
|
||||||
|
// * @param String|PPNode $root
|
||||||
|
// * @param int $flags
|
||||||
|
// * @return String
|
||||||
|
// */
|
||||||
|
// public String cachedExpand(String key, Object root, int flags) { // DEFAULT:flags=0
|
||||||
|
// // we don't have a parent, so we don't have a cache
|
||||||
|
// return this.expand(root, flags);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private static int expansionDepth = 0; // MW.GLOBAL:expand
|
||||||
|
// private static int expand_flags_default = 0;
|
||||||
|
// /**
|
||||||
|
// * @throws MWException
|
||||||
|
// * @param String|PPNode $root
|
||||||
|
// * @param int $flags
|
||||||
|
// * @return String
|
||||||
|
// */
|
||||||
|
// public override String expand(Object root, int flags) {
|
||||||
|
// if (XophpString_.is_string(root)) {
|
||||||
|
// return (String)root;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (++this.parser.mPPNodeCount > this.parser.mOptions.getMaxPPNodeCount()) {
|
||||||
|
// // this.parser.limitationWarn('node-count-exceeded',
|
||||||
|
// // this.parser.mPPNodeCount,
|
||||||
|
// // this.parser.mOptions.getMaxPPNodeCount()
|
||||||
|
// // );
|
||||||
|
// return "<span class=\"error\">Node-count limit exceeded</span>";
|
||||||
|
// }
|
||||||
|
// if (expansionDepth > this.parser.mOptions.getMaxPPExpandDepth()) {
|
||||||
|
// // this.parser.limitationWarn('expansion-depth-exceeded',
|
||||||
|
// // expansionDepth,
|
||||||
|
// // this.parser.mOptions.getMaxPPExpandDepth()
|
||||||
|
// // );
|
||||||
|
// return "<span class=\"error\">Expansion depth limit exceeded</span>";
|
||||||
|
// }
|
||||||
|
// ++expansionDepth;
|
||||||
|
// if (expansionDepth > this.parser.mHighestExpansionDepth) {
|
||||||
|
// this.parser.mHighestExpansionDepth = expansionDepth;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// XophpArray outStack = XophpArray.New("", "");
|
||||||
|
// XophpArray iteratorStack = XophpArray.New(XophpObject_.False, root);
|
||||||
|
// XophpArray indexStack = XophpArray.New(0, 0);
|
||||||
|
//
|
||||||
|
// while (iteratorStack.count() > 1) {
|
||||||
|
// int level = outStack.count() - 1;
|
||||||
|
// Object iteratorNode = iteratorStack.Get_at(level);
|
||||||
|
// String outItm = outStack.Get_at_str(level);
|
||||||
|
// int index = indexStack.Get_at_int(level);
|
||||||
|
// Object contextNode;
|
||||||
|
// if (XophpArray.is_array(iteratorNode)) {
|
||||||
|
// XophpArray iteratorNodeArray = (XophpArray)iteratorNode;
|
||||||
|
// if (index >= iteratorNodeArray.count()) {
|
||||||
|
// // All done with this iterator
|
||||||
|
// iteratorStack.Set(level, XophpObject_.False);
|
||||||
|
// contextNode = XophpObject_.False;
|
||||||
|
// } else {
|
||||||
|
// contextNode = iteratorNodeArray.Get_at(index);
|
||||||
|
// index++;
|
||||||
|
// }
|
||||||
|
// } else if (Type_.Eq_by_obj(iteratorNode, typeof(XomwPPNode_Hash_Array))) {
|
||||||
|
// XomwPPNode_Hash_Array iteratorNodeHashArray = (XomwPPNode_Hash_Array)iteratorNode;
|
||||||
|
// if (index >= iteratorNodeHashArray.getLength()) {
|
||||||
|
// // All done with this iterator
|
||||||
|
// iteratorStack.Set(level, XophpObject_.False);
|
||||||
|
// contextNode = XophpObject_.False;
|
||||||
|
// } else {
|
||||||
|
// contextNode = iteratorNodeHashArray.item(index);
|
||||||
|
// index++;
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// // Copy to contextNode and then delete from iterator stack,
|
||||||
|
// // because this is not an iterator but we do have to execute it once
|
||||||
|
// contextNode = iteratorStack.Get_at(level);
|
||||||
|
// iteratorStack.Set(level, XophpObject_.False);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Object newIterator = XophpObject_.False;
|
||||||
|
// String contextName = XophpString_.False;
|
||||||
|
// XophpArray contextChildren = XophpArray.False;
|
||||||
|
//
|
||||||
|
// if (!XophpObject_.is_true(contextNode)) {
|
||||||
|
// // nothing to do
|
||||||
|
// } else if (XophpString_.is_string(contextNode)) {
|
||||||
|
// outItm += (String)contextNode;
|
||||||
|
// } else if (Type_.Eq_by_obj(contextNode, typeof(XomwPPNode_Hash_Array))) {
|
||||||
|
// newIterator = contextNode;
|
||||||
|
// } else if (Type_.Eq_by_obj(contextNode, typeof(XomwPPNode_Hash_Attr))) {
|
||||||
|
// // No output
|
||||||
|
// } else if (Type_.Eq_by_obj(contextNode, typeof(XomwPPNode_Hash_Text))) {
|
||||||
|
// outItm += ((XomwPPNode_Hash_Text)contextNode).value;
|
||||||
|
// } else if (Type_.Eq_by_obj(contextNode, typeof(XomwPPNode_Hash_Tree))) {
|
||||||
|
// XomwPPNode_Hash_Tree contextNodeHashTree = (XomwPPNode_Hash_Tree)contextNode;
|
||||||
|
// contextName = contextNodeHashTree.name;
|
||||||
|
// contextChildren = contextNodeHashTree.getRawChildren();
|
||||||
|
// } else if (XophpArray.is_array(contextNode)) {
|
||||||
|
// XophpArray contextNodeArray = (XophpArray)contextNode;
|
||||||
|
// // Node descriptor array
|
||||||
|
// if (contextNodeArray.count() != 2) {
|
||||||
|
// throw XomwMWException.New_by_method(typeof(XomwPPFrame_Hash), "expand",
|
||||||
|
// ": found an array where a node descriptor should be");
|
||||||
|
// }
|
||||||
|
// contextName = (String)contextNodeArray.Get_at(0);
|
||||||
|
// contextChildren = contextNodeArray.Get_at_ary(1);
|
||||||
|
// } else {
|
||||||
|
// throw XomwMWException.New_by_method(typeof(XomwPPFrame_Hash), "expand", ": Invalid parameter type");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Handle node descriptor array or tree Object
|
||||||
|
// if (!XophpString_.is_true(contextName)) {
|
||||||
|
// // Not a node, already handled above
|
||||||
|
// } else if (String_.CharAt(contextName, 0) == '@') {
|
||||||
|
// // Attribute: no output
|
||||||
|
// } else if (String_.Eq(contextName, "template")) {
|
||||||
|
// // Double-brace expansion
|
||||||
|
// XophpArray bits = XomwPPNode_Hash_Tree.splitRawTemplate(contextChildren);
|
||||||
|
// if (Bitmask_.Has_int(flags, XomwPPFrame.NO_TEMPLATES)) {
|
||||||
|
// newIterator = this.virtualBracketedImplode(
|
||||||
|
// "{{", "|", "}}",
|
||||||
|
// bits.Get_by("title"),
|
||||||
|
// bits.Get_by("parts")
|
||||||
|
// );
|
||||||
|
// } else {
|
||||||
|
// XophpArray ret = this.parser.braceSubstitution(bits, this);
|
||||||
|
// if (ret.isset(Object_.Cls_val_name)) {// NOTE: using Cls_val_name b/c of transpilation and Object . Object
|
||||||
|
// newIterator = ret.Get_by(Object_.Cls_val_name);
|
||||||
|
// } else {
|
||||||
|
// outItm += ret.Get_by_str("text");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else if (String_.Eq(contextName, "tplarg")) {
|
||||||
|
// // Triple-brace expansion
|
||||||
|
// XophpArray bits = XomwPPNode_Hash_Tree.splitRawTemplate(contextChildren);
|
||||||
|
// if (Bitmask_.Has_int(flags, XomwPPFrame.NO_ARGS)) {
|
||||||
|
// newIterator = this.virtualBracketedImplode(
|
||||||
|
// "{{{", "|", "}}}",
|
||||||
|
// bits.Get_by("title"),
|
||||||
|
// bits.Get_by("parts")
|
||||||
|
// );
|
||||||
|
// } else {
|
||||||
|
// XophpArray ret = this.parser.argSubstitution(bits, this);
|
||||||
|
// if (ret.isset(Object_.Cls_val_name)) {// NOTE: using Cls_val_name b/c of transpilation and Object . Object
|
||||||
|
// newIterator = ret.Get_by("Object");
|
||||||
|
// } else {
|
||||||
|
// outItm += ret.Get_by_str("text");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else if (String_.Eq(contextName, "comment")) {
|
||||||
|
// // HTML-style comment
|
||||||
|
// // Remove it in HTML, pre+remove and STRIP_COMMENTS modes
|
||||||
|
// // Not in RECOVER_COMMENTS mode (msgnw) though.
|
||||||
|
// if ((this.parser.ot.Has("html"))
|
||||||
|
// || (this.parser.ot.Has("pre") && this.parser.mOptions.getRemoveComments())
|
||||||
|
// || (Bitmask_.Has_int(flags, XomwPPFrame.STRIP_COMMENTS))
|
||||||
|
// && !(Bitmask_.Has_int(flags, XomwPPFrame.RECOVER_COMMENTS))
|
||||||
|
// ) {
|
||||||
|
// outItm += ""; // XOWA: no purpose?
|
||||||
|
// } else if (this.parser.ot.Has("wiki") && !(Bitmask_.Has_int(flags, XomwPPFrame.RECOVER_COMMENTS))) {
|
||||||
|
// // Add a strip marker in PST mode so that pstPass2() can
|
||||||
|
// // run some old-fashioned regexes on the result.
|
||||||
|
// // Not in RECOVER_COMMENTS mode (extractSections) though.
|
||||||
|
// outItm += this.parser.insertStripItem(contextChildren.Get_at_str(0));
|
||||||
|
// } else {
|
||||||
|
// // Recover the literal comment in RECOVER_COMMENTS and pre+no-remove
|
||||||
|
// outItm += contextChildren.Get_at_str(0);
|
||||||
|
// }
|
||||||
|
// } else if (String_.Eq(contextName, "ignore")) {
|
||||||
|
// // Output suppression used by <includeonly> etc.
|
||||||
|
// // OT_WIKI will only respect <ignore> in substed templates.
|
||||||
|
// // The other output types respect it unless NO_IGNORE is set.
|
||||||
|
// // extractSections() sets NO_IGNORE and so never respects it.
|
||||||
|
//// if ((!XophpObject_.isset(this.parent) && this.parser.ot.Has("wiki")) // this.parent doesn't exist?
|
||||||
|
// if ((this.parser.ot.Has("wiki"))
|
||||||
|
// || (Bitmask_.Has_int(flags, XomwPPFrame.NO_IGNORE))
|
||||||
|
// ) {
|
||||||
|
// outItm += contextChildren.Get_at_str(0);
|
||||||
|
// } else {
|
||||||
|
// // outItm .= '';
|
||||||
|
// }
|
||||||
|
// } else if (String_.Eq(contextName, "ext")) {
|
||||||
|
// // Extension tag
|
||||||
|
// XophpArray bits = XomwPPNode_Hash_Tree.splitRawExt(contextChildren)
|
||||||
|
// .Add("attr", null).Add("inner", null).Add("close", null);
|
||||||
|
// if (Bitmask_.Has_int(flags, XomwPPFrame.NO_TAGS)) {
|
||||||
|
// String s = '<' + ((XomwPPNode_Hash_Text)((XomwPPNode)bits.Get_by("name")).getFirstChild()).value;
|
||||||
|
// if (bits.Has("attr")) {
|
||||||
|
// s += ((XomwPPNode_Hash_Text)((XomwPPNode)bits.Get_by("attr")).getFirstChild()).value;
|
||||||
|
// }
|
||||||
|
// if (bits.Has("inner")) {
|
||||||
|
// s += '>' + ((XomwPPNode_Hash_Text)((XomwPPNode)bits.Get_by("inner")).getFirstChild()).value;
|
||||||
|
// if (bits.Has("close")) {
|
||||||
|
// s += ((XomwPPNode_Hash_Text)((XomwPPNode)bits.Get_by("close")).getFirstChild()).value;
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// s += "/>";
|
||||||
|
// }
|
||||||
|
// outItm += s;
|
||||||
|
// } else {
|
||||||
|
// outItm += this.parser.extensionSubstitution(bits, this);
|
||||||
|
// }
|
||||||
|
// } else if (String_.Eq(contextName, "h")) {
|
||||||
|
// // Heading
|
||||||
|
// if (this.parser.ot.Has("html")) {
|
||||||
|
// // Expand immediately and insert heading index marker
|
||||||
|
// String s = this.expand(contextChildren, flags);
|
||||||
|
// XophpArray bits = XomwPPNode_Hash_Tree.splitRawHeading(contextChildren);
|
||||||
|
// String titleText = this.title.getPrefixedDBkeyStr();
|
||||||
|
// this.parser.mHeadings.Add(titleText, bits.Get_by("i"));
|
||||||
|
// int serial = XophpArray_.count(this.parser.mHeadings) - 1;
|
||||||
|
// String marker = XomwParser.MARKER_PREFIX + "-h-" + Int_.To_str(serial) + "-" + XomwParser.MARKER_SUFFIX;
|
||||||
|
// s = XophpString_.substr(s, 0, bits.Get_by_int("level")) + marker + XophpString_.substr(s, bits.Get_by_int("level"));
|
||||||
|
// this.parser.mStripState.addGeneral(marker, "");
|
||||||
|
// outItm += s;
|
||||||
|
// } else {
|
||||||
|
// // Expand in virtual stack
|
||||||
|
// newIterator = contextChildren;
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// // Generic recursive expansion
|
||||||
|
// newIterator = contextChildren;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (XophpObject_.is_true(newIterator)) {
|
||||||
|
// outStack.Add("");
|
||||||
|
// iteratorStack.Add(newIterator);
|
||||||
|
// indexStack.Add(0);
|
||||||
|
// } else if (!XophpObject_.is_true(iteratorStack.Get_at(level))) {
|
||||||
|
// // Return accumulated value to parent
|
||||||
|
// // With tail recursion
|
||||||
|
// while (!XophpObject_.is_true(iteratorStack.Get_at(level)) && level > 0) {
|
||||||
|
// outStack.Itm_str_concat_end(level - 1, outItm);
|
||||||
|
// outStack.pop();
|
||||||
|
// iteratorStack.pop();
|
||||||
|
// indexStack.pop();
|
||||||
|
// level--;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// --expansionDepth;
|
||||||
|
// return outStack.Get_at_str(0);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * @param String $sep
|
||||||
|
// * @param int $flags
|
||||||
|
// * @param String|PPNode $args,...
|
||||||
|
// * @return String
|
||||||
|
// */
|
||||||
|
// public String implodeWithFlags(String sep, int flags, XophpArray args) {
|
||||||
|
// // args = XophpArray_.array_slice(func_get_args(), 2);
|
||||||
|
//
|
||||||
|
// boolean first = true;
|
||||||
|
// String s = "";
|
||||||
|
// int len = args.Len();
|
||||||
|
// for (int i = 0; i < len; i++) {
|
||||||
|
// Object root_obj = args.Get_at(i);
|
||||||
|
// XophpArray root = null;
|
||||||
|
// if (XophpType_.instance_of(root_obj, typeof(XomwPPNode_Hash_Array))) {
|
||||||
|
// root = (XophpArray)((XomwPPNode_Hash_Array)root_obj).value;
|
||||||
|
// }
|
||||||
|
// if (!XophpType_.is_array(root_obj)) {
|
||||||
|
// root = XophpArray.New(root_obj);
|
||||||
|
// }
|
||||||
|
// int root_len = root.Len();
|
||||||
|
// for (int j = 0; j < root_len; j++) {
|
||||||
|
// XomwPPNode node = (XomwPPNode)root.Get_at(j);
|
||||||
|
// if (first) {
|
||||||
|
// first = false;
|
||||||
|
// } else {
|
||||||
|
// s += sep;
|
||||||
|
// }
|
||||||
|
// s += this.expand(node, flags);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return s;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Implode with no flags specified
|
||||||
|
// * This previously called implodeWithFlags but has now been inlined to reduce stack depth
|
||||||
|
// * @param String $sep
|
||||||
|
// * @param String|PPNode $args,...
|
||||||
|
// * @return String
|
||||||
|
// */
|
||||||
|
// public override String implode(String sep, params Object[] args) {
|
||||||
|
// boolean first = true;
|
||||||
|
// String s = "";
|
||||||
|
// foreach (Object rootObj in args) {
|
||||||
|
// XophpArray root = null;
|
||||||
|
// if (Type_.Eq_by_obj(root, typeof(XomwPPNode_Hash_Array))) {
|
||||||
|
// root = ((XomwPPNode_Hash_Array)rootObj).value;
|
||||||
|
// }
|
||||||
|
// if (!XophpArray.is_array(rootObj)) {
|
||||||
|
// root = XophpArray.New(root);
|
||||||
|
// }
|
||||||
|
// int rootLen = root.count();
|
||||||
|
// for (int i = 0; i < rootLen; i++) {
|
||||||
|
// Object node = root.Get_at(i);
|
||||||
|
// if (first) {
|
||||||
|
// first = false;
|
||||||
|
// } else {
|
||||||
|
// s += sep;
|
||||||
|
// }
|
||||||
|
// s += this.expand(node, expand_flags_default);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return s;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Makes an Object that, when expand()ed, will be the same as one obtained
|
||||||
|
// * with implode()
|
||||||
|
// *
|
||||||
|
// * @param String $sep
|
||||||
|
// * @param String|PPNode $args,...
|
||||||
|
// * @return PPNode_Hash_Array
|
||||||
|
// */
|
||||||
|
// public override XomwPPNode virtualImplode(String sep, params Object[] args) {
|
||||||
|
// XophpArray outItm = XophpArray.New();
|
||||||
|
// boolean first = true;
|
||||||
|
//
|
||||||
|
// foreach (Object rootObj in args) {
|
||||||
|
// XophpArray root = null;
|
||||||
|
// if (Type_.Eq_by_obj(root, typeof(XomwPPNode_Hash_Array))) {
|
||||||
|
// root = ((XomwPPNode_Hash_Array)rootObj).value;
|
||||||
|
// }
|
||||||
|
// if (!XophpArray.is_array(rootObj)) {
|
||||||
|
// root = XophpArray.New(root);
|
||||||
|
// }
|
||||||
|
// int rootLen = root.count();
|
||||||
|
// for (int i = 0; i < rootLen; i++) {
|
||||||
|
// Object node = root.Get_at(i);
|
||||||
|
// if (first) {
|
||||||
|
// first = false;
|
||||||
|
// } else {
|
||||||
|
// outItm.Add(sep);
|
||||||
|
// }
|
||||||
|
// outItm.Add(node);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return new XomwPPNode_Hash_Array(outItm);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Virtual implode with brackets
|
||||||
|
// *
|
||||||
|
// * @param String $start
|
||||||
|
// * @param String $sep
|
||||||
|
// * @param String $end
|
||||||
|
// * @param String|PPNode $args,...
|
||||||
|
// * @return PPNode_Hash_Array
|
||||||
|
// */
|
||||||
|
// public override XomwPPNode virtualBracketedImplode(String start, String sep, String end, params Object[] args) {
|
||||||
|
// XophpArray outItm = XophpArray.New(start);
|
||||||
|
// boolean first = true;
|
||||||
|
//
|
||||||
|
// foreach (Object rootObj in args) {
|
||||||
|
// XophpArray root = null;
|
||||||
|
// if (Type_.Eq_by_obj(rootObj, typeof(XomwPPNode_Hash_Array))) {
|
||||||
|
// root = ((XomwPPNode_Hash_Array)rootObj).value;
|
||||||
|
// }
|
||||||
|
// if (!XophpArray.is_array(rootObj)) {
|
||||||
|
// root = XophpArray.New((String)rootObj);
|
||||||
|
// }
|
||||||
|
// int root_len = root.count();
|
||||||
|
// for (int i = 0; i < root_len; i++) {
|
||||||
|
// String node = root.Get_at_str(i);
|
||||||
|
// if (first) {
|
||||||
|
// first = false;
|
||||||
|
// } else {
|
||||||
|
// outItm.Add(sep);
|
||||||
|
// }
|
||||||
|
// outItm.Add(node);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// outItm.Add(end);
|
||||||
|
// return new XomwPPNode_Hash_Array(outItm);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public override String toString() {
|
||||||
|
// return "frame{}";
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * @param boolean $level
|
||||||
|
// * @return array|boolean|String
|
||||||
|
// */
|
||||||
|
// public String getPDBK(boolean level) { // DEFAULT:false
|
||||||
|
// if (level == false) {
|
||||||
|
// return this.title.getPrefixedDBkeyStr();
|
||||||
|
// } else {
|
||||||
|
// // return isset( $this->titleCache[$level] ) ? $this->titleCache[$level] : false;
|
||||||
|
// return this.titleCache.count() > 0 ? ((String)this.titleCache.Get_at(0)) : XophpString_.False;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * @return array
|
||||||
|
// */
|
||||||
|
// public override XophpArray getArguments() {
|
||||||
|
// return XophpArray.False;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * @return array
|
||||||
|
// */
|
||||||
|
// public override XophpArray getNumberedArguments() {
|
||||||
|
// return XophpArray.False;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * @return array
|
||||||
|
// */
|
||||||
|
// public override XophpArray getNamedArguments() {
|
||||||
|
// return XophpArray.False;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Returns true if there are no arguments in this frame
|
||||||
|
// *
|
||||||
|
// * @return boolean
|
||||||
|
// */
|
||||||
|
// public override boolean isEmpty() {
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * @param int|String $name
|
||||||
|
// * @return boolean Always false in this implementation.
|
||||||
|
// */
|
||||||
|
// public override String getArgument(String name) {
|
||||||
|
// return XophpString_.False;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Returns true if the infinite loop check is OK, false if a loop is detected
|
||||||
|
// *
|
||||||
|
// * @param Title $title
|
||||||
|
// *
|
||||||
|
// * @return boolean
|
||||||
|
// */
|
||||||
|
// public override boolean loopCheck(XomwTitle title) {
|
||||||
|
// return !this.loopCheckHash.isset(title.getPrefixedDBkeyStr());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Return true if the frame is a template frame
|
||||||
|
// *
|
||||||
|
// * @return boolean
|
||||||
|
// */
|
||||||
|
// public override boolean isTemplate() {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Get a title of frame
|
||||||
|
// *
|
||||||
|
// * @return Title
|
||||||
|
// */
|
||||||
|
// public override XomwTitle getTitle() {
|
||||||
|
// return this.title;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Set the volatile_bool flag
|
||||||
|
// *
|
||||||
|
// * @param boolean $flag
|
||||||
|
// */
|
||||||
|
// public override void setVolatile(boolean flag) { // DEFAULT: flag = true
|
||||||
|
// this.volatile_bool = flag;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Get the volatile_bool flag
|
||||||
|
// *
|
||||||
|
// * @return boolean
|
||||||
|
// */
|
||||||
|
// public override boolean isVolatile() {
|
||||||
|
// return this.volatile_bool;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Set the TTL
|
||||||
|
// *
|
||||||
|
// * @param int ttl
|
||||||
|
// */
|
||||||
|
// public override void setTTL(int val) {
|
||||||
|
// if (this.ttl == Int_.Null || val < this.ttl) {
|
||||||
|
// this.ttl = val;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Get the TTL
|
||||||
|
// *
|
||||||
|
// * @return int|null
|
||||||
|
// */
|
||||||
|
// public override int getTTL() {
|
||||||
|
// return this.ttl;
|
||||||
|
// }
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
package gplx.xowa.mediawiki.includes.parsers.preprocessors_new; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*; import gplx.xowa.mediawiki.includes.parsers.*;
|
||||||
|
// MW.FILE:Preprocessor
|
||||||
|
/**
|
||||||
|
* There are three types of nodes:
|
||||||
|
* * Tree nodes, which have a name and contain other nodes as children
|
||||||
|
* * Array nodes, which also contain other nodes but aren't considered part of a tree
|
||||||
|
* * Leaf nodes, which contain the actual data
|
||||||
|
*
|
||||||
|
* This interface provides access to the tree structure and to the contents of array nodes,
|
||||||
|
* but it does not provide access to the @gplx.Internal protected structure of leaf nodes. Access to leaf
|
||||||
|
* data is provided via two means:
|
||||||
|
* * PPFrame::expand(), which provides expanded text
|
||||||
|
* * The PPNode::split*() functions, which provide metadata about certain types of tree node
|
||||||
|
* @ingroup Parser
|
||||||
|
*/
|
||||||
|
public abstract class XomwPPNode {
|
||||||
|
/**
|
||||||
|
* Get an array-type node containing the children of this node.
|
||||||
|
* Returns false if this is not a tree node.
|
||||||
|
* @return PPNode
|
||||||
|
*/
|
||||||
|
public abstract XomwPPNode_Hash_Array getChildren();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the first child of a tree node. False if there isn't one.
|
||||||
|
*
|
||||||
|
* @return PPNode
|
||||||
|
*/
|
||||||
|
public abstract XomwPPNode getFirstChild();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next sibling of any node. False if there isn't one
|
||||||
|
* @return PPNode
|
||||||
|
*/
|
||||||
|
public abstract XomwPPNode getNextSibling();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all children of this tree node which have a given name.
|
||||||
|
* Returns an array-type node, or false if this is not a tree node.
|
||||||
|
* @param String $type
|
||||||
|
* @return boolean|PPNode
|
||||||
|
*/
|
||||||
|
public abstract XomwPPNode_Hash_Array getChildrenOfType(String type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the length of the array, or false if this is not an array-type node
|
||||||
|
*/
|
||||||
|
public abstract int getLength();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an item of an array-type node
|
||||||
|
* @param int $i
|
||||||
|
* @return boolean|PPNode
|
||||||
|
*/
|
||||||
|
public abstract XomwPPNode item(int i);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of this node. The following names are defined here:
|
||||||
|
*
|
||||||
|
* h A heading node.
|
||||||
|
* template A double-brace node.
|
||||||
|
* tplarg A triple-brace node.
|
||||||
|
* title The first argument to a template or tplarg node.
|
||||||
|
* part Subsequent arguments to a template or tplarg node.
|
||||||
|
* #nodelist An array-type node
|
||||||
|
*
|
||||||
|
* The subclass may define various other names for tree and leaf nodes.
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public abstract String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split a "<part>" node into an associative array containing:
|
||||||
|
* name PPNode name
|
||||||
|
* index String index
|
||||||
|
* value PPNode value
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public abstract XophpArray splitArg();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split an "<ext>" node into an associative array containing name, attr, inner and close
|
||||||
|
* All values in the resulting array are PPNodes. Inner and close are optional.
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public abstract XophpArray splitExt();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split an "<h>" node
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public abstract XophpArray splitHeading();
|
||||||
|
|
||||||
|
public abstract String toString();
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
package gplx.xowa.mediawiki.includes.parsers.preprocessors_new; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*; import gplx.xowa.mediawiki.includes.parsers.*;
|
||||||
|
import gplx.xowa.mediawiki.includes.exception.*;
|
||||||
|
// MW.FILE:Preprocessor_Hash
|
||||||
|
/**
|
||||||
|
* @ingroup Parser
|
||||||
|
*/
|
||||||
|
public class XomwPPNode_Hash_Array extends XomwPPNode { public XophpArray value;
|
||||||
|
|
||||||
|
public XomwPPNode_Hash_Array(XophpArray value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String toString() {
|
||||||
|
// return var_export($this, true);
|
||||||
|
return value.To_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public int getLength() {
|
||||||
|
return XophpArray_.count(this.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XomwPPNode item(int i) {
|
||||||
|
return (XomwPPNode)this.value.Get_at(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String getName() {
|
||||||
|
return "#nodelist";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XomwPPNode getNextSibling() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XomwPPNode_Hash_Array getChildren() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XomwPPNode getFirstChild() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XomwPPNode_Hash_Array getChildrenOfType(String name) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XophpArray splitArg() {
|
||||||
|
throw XomwMWException.New_by_method_obj(this, "splitArg", ": not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XophpArray splitExt() {
|
||||||
|
throw XomwMWException.New_by_method_obj(this, "splitExt", ": not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XophpArray splitHeading() {
|
||||||
|
throw XomwMWException.New_by_method_obj(this, "splitHeading", ": not supported");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
package gplx.xowa.mediawiki.includes.parsers.preprocessors_new; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*; import gplx.xowa.mediawiki.includes.parsers.*;
|
||||||
|
import gplx.xowa.mediawiki.includes.exception.*;
|
||||||
|
// MW.FILE:Preprocessor_Hash
|
||||||
|
/**
|
||||||
|
* @ingroup Parser
|
||||||
|
*/
|
||||||
|
public class XomwPPNode_Hash_Attr extends XomwPPNode { public String name, value;
|
||||||
|
private final XophpArray store;
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an Object using the data from $store[$index]. The rest of the
|
||||||
|
* store array can be accessed via getNextSibling().
|
||||||
|
*
|
||||||
|
* @param array $store
|
||||||
|
* @param integer $index
|
||||||
|
*/
|
||||||
|
public XomwPPNode_Hash_Attr(XophpArray store, int index) {
|
||||||
|
XophpArray descriptor = (XophpArray)store.Get_at(index);
|
||||||
|
String descriptor_name = descriptor.Get_at_str(XomwPPNode_Hash_Tree.NAME);
|
||||||
|
if (!(String_.CharAt(descriptor_name, 0) == '@')) {
|
||||||
|
throw Err_.new_wo_type("XomwPPNode_Hash_Attr.CTOR: invalid name in attribute descriptor");
|
||||||
|
}
|
||||||
|
this.name = String_.new_u8(XophpString_.substr(Bry_.new_u8(descriptor_name), 1));
|
||||||
|
XophpArray descriptor_children = (XophpArray)descriptor.Get_at(XomwPPNode_Hash_Tree.CHILDREN);
|
||||||
|
Object value_obj = descriptor_children.Get_at(0);
|
||||||
|
this.value = Type_.Eq_by_obj(value_obj, byte[].class) ? String_.new_u8((byte[])value_obj): value_obj.toString();
|
||||||
|
this.store = store;
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String toString() {
|
||||||
|
return String_.Format("<@{0}>{1}</@{0}>", this.name, Bry_.Escape_html(Bry_.new_u8(this.value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XomwPPNode getNextSibling() {
|
||||||
|
return XomwPPNode_Hash_Tree.factory(this.store, this.index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XomwPPNode_Hash_Array getChildren() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XomwPPNode getFirstChild() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XomwPPNode_Hash_Array getChildrenOfType(String name) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public int getLength() {
|
||||||
|
return XophpInt_.False;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XomwPPNode item(int i) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XophpArray splitArg() {
|
||||||
|
throw XomwMWException.New_by_method_obj(this, "splitArg", ": not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XophpArray splitExt() {
|
||||||
|
throw XomwMWException.New_by_method_obj(this, "splitExt", ": not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XophpArray splitHeading() {
|
||||||
|
throw XomwMWException.New_by_method_obj(this, "splitHeading", ": not supported");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
package gplx.xowa.mediawiki.includes.parsers.preprocessors_new; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*; import gplx.xowa.mediawiki.includes.parsers.*;
|
||||||
|
// MW.FILE:Preprocessor_Hash
|
||||||
|
/**
|
||||||
|
* @ingroup Parser
|
||||||
|
*/
|
||||||
|
import gplx.xowa.mediawiki.includes.exception.*;
|
||||||
|
public class XomwPPNode_Hash_Text extends XomwPPNode { public String value;
|
||||||
|
private final XophpArray store;
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an Object using the data from $store[$index]. The rest of the
|
||||||
|
* store array can be accessed via getNextSibling().
|
||||||
|
*
|
||||||
|
* @param array $store
|
||||||
|
* @param integer $index
|
||||||
|
*/
|
||||||
|
public XomwPPNode_Hash_Text(XophpArray store, int index) {
|
||||||
|
Object value_obj = store.Get_at(index);
|
||||||
|
if (!XophpType_.is_scalar(value_obj)) {
|
||||||
|
throw XomwMWException.New_by_method(XomwPPNode_Hash_Text.class, "CTOR", "given Object instead of String");
|
||||||
|
}
|
||||||
|
this.value = Object_.Xto_str_strict_or_null(value_obj);
|
||||||
|
this.store = store;
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String toString() {
|
||||||
|
return String_.new_u8(Bry_.Escape_html(Bry_.new_u8(this.value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XomwPPNode getNextSibling() {
|
||||||
|
return XomwPPNode_Hash_Tree.factory(this.store, this.index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XomwPPNode_Hash_Array getChildren() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XomwPPNode getFirstChild() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XomwPPNode_Hash_Array getChildrenOfType(String name) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public int getLength() {
|
||||||
|
return XophpInt_.False;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XomwPPNode item(int i) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String getName() {
|
||||||
|
return "#text";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XophpArray splitArg() {
|
||||||
|
throw XomwMWException.New_by_method_obj(this, "splitArg", ": not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XophpArray splitExt() {
|
||||||
|
throw XomwMWException.New_by_method_obj(this, "splitExt", ": not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XophpArray splitHeading() {
|
||||||
|
throw XomwMWException.New_by_method_obj(this, "splitHeading", ": not supported");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,392 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
package gplx.xowa.mediawiki.includes.parsers.preprocessors_new; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*; import gplx.xowa.mediawiki.includes.parsers.*;
|
||||||
|
// MW.FILE:Preprocessor_Hash
|
||||||
|
/**
|
||||||
|
* @ingroup Parser
|
||||||
|
*/
|
||||||
|
import gplx.xowa.mediawiki.includes.exception.*;
|
||||||
|
public class XomwPPNode_Hash_Tree extends XomwPPNode { public final String name;
|
||||||
|
/**
|
||||||
|
* The store array for children of this node. It is "raw" in the sense that
|
||||||
|
* nodes are two-element arrays ("descriptors") rather than PPNode_Hash_*
|
||||||
|
* objects.
|
||||||
|
*/
|
||||||
|
private XophpArray rawChildren;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The store array for the siblings of this node, including this node itself.
|
||||||
|
*/
|
||||||
|
private final XophpArray store;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The index into this.store which contains the descriptor of this node.
|
||||||
|
*/
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The offset of the name within descriptors, used in some places for
|
||||||
|
* readability.
|
||||||
|
*/
|
||||||
|
public static final int NAME = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The offset of the child list within descriptors, used in some places for
|
||||||
|
* readability.
|
||||||
|
*/
|
||||||
|
public static final int CHILDREN = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an Object using the data from store[index]. The rest of the
|
||||||
|
* store array can be accessed via getNextSibling().
|
||||||
|
*
|
||||||
|
* @param array store
|
||||||
|
* @param integer index
|
||||||
|
*/
|
||||||
|
public XomwPPNode_Hash_Tree(XophpArray store, int index) {
|
||||||
|
this.store = store;
|
||||||
|
this.index = index;
|
||||||
|
|
||||||
|
XophpArray list = this.store.Get_at_ary(index);
|
||||||
|
this.name = list.Get_at_str(0);
|
||||||
|
Object rawChildrenObj = list.Get_at(1);
|
||||||
|
if (XophpType_.To_type_id(rawChildrenObj) == Type_ids_.Id__array) {
|
||||||
|
this.rawChildren = (XophpArray)rawChildrenObj;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// this.rawChildren = ((Xomw_prepro_accum__hash)rawChildrenObj).Ary();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an appropriate PPNode_Hash_* Object with a class that depends
|
||||||
|
* on what is at the relevant store index.
|
||||||
|
*
|
||||||
|
* @param array store
|
||||||
|
* @param integer index
|
||||||
|
* @return PPNode_Hash_Tree|PPNode_Hash_Attr|PPNode_Hash_Text
|
||||||
|
*/
|
||||||
|
public static XomwPPNode factory(XophpArray store, int index) {
|
||||||
|
Object descriptor = store.Get_at(index);
|
||||||
|
if (!XophpObject_.isset_obj(descriptor)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
XophpType type = XophpType.New(descriptor);
|
||||||
|
if (type.is_string()) {
|
||||||
|
return new XomwPPNode_Hash_Text(store, index);
|
||||||
|
}
|
||||||
|
else if (type.is_array()) {
|
||||||
|
XophpArray descriptor_array = (XophpArray)descriptor;
|
||||||
|
String name = (String)(descriptor_array.Get_by(NAME));
|
||||||
|
if (String_.CharAt(name, 0) == '@') {
|
||||||
|
return new XomwPPNode_Hash_Attr(store, index);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return new XomwPPNode_Hash_Tree(store, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw XomwMWException.New_by_method(XomwPPNode_Hash_Tree.class, "factory", "invalid node descriptor");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a node to XML, for debugging
|
||||||
|
*/
|
||||||
|
@Override public String toString() {
|
||||||
|
String inner = "";
|
||||||
|
String attribs = "";
|
||||||
|
for (XomwPPNode node = this.getFirstChild(); node != null; node = node.getNextSibling()) {
|
||||||
|
if (Type_.Eq_by_obj(node, XomwPPNode_Hash_Attr.class)) {
|
||||||
|
XomwPPNode_Hash_Attr node_attr = (XomwPPNode_Hash_Attr)node;
|
||||||
|
attribs += " " + node_attr.name + "=\"" + String_.new_u8(Bry_.Escape_html(Bry_.new_u8(node_attr.value))) + "\"";
|
||||||
|
} else {
|
||||||
|
inner += node.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (String_.Eq(inner, "") && String_.Eq(name, "name")) {
|
||||||
|
return "<" + this.name + attribs + " />";
|
||||||
|
} else {
|
||||||
|
if (String_.Eq(name, "equals")) {
|
||||||
|
return inner;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return "<" + this.name + attribs + ">" + inner + "</" + this.name + ">";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return PPNode_Hash_Array
|
||||||
|
*/
|
||||||
|
@Override public XomwPPNode_Hash_Array getChildren() {
|
||||||
|
XophpArray children = XophpArray.New();
|
||||||
|
int rawChildrenLen = rawChildren.Len();
|
||||||
|
for (int i = 0; i < rawChildrenLen; i++) {
|
||||||
|
XophpArrayItm itm = rawChildren.Get_at_itm(i);
|
||||||
|
children.Add(XomwPPNode_Hash_Tree.factory(this.rawChildren, itm.Key_as_int()));
|
||||||
|
}
|
||||||
|
return new XomwPPNode_Hash_Array(children);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the first child, or false if there is none. Note that this will
|
||||||
|
* return a temporary proxy Object: different instances will be returned
|
||||||
|
* if this is called more than once on the same node.
|
||||||
|
*
|
||||||
|
* @return PPNode_Hash_Tree|PPNode_Hash_Attr|PPNode_Hash_Text|boolean
|
||||||
|
*/
|
||||||
|
@Override public XomwPPNode getFirstChild() {
|
||||||
|
if (!XophpArray_.isset(this.rawChildren, 0)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return factory(this.rawChildren, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next sibling, or false if there is none. Note that this will
|
||||||
|
* return a temporary proxy Object: different instances will be returned
|
||||||
|
* if this is called more than once on the same node.
|
||||||
|
*
|
||||||
|
* @return PPNode_Hash_Tree|PPNode_Hash_Attr|PPNode_Hash_Text|boolean
|
||||||
|
*/
|
||||||
|
@Override public XomwPPNode getNextSibling() {
|
||||||
|
return factory(this.store, this.index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array of the children with a given node name
|
||||||
|
*
|
||||||
|
* @param String name
|
||||||
|
* @return PPNode_Hash_Array
|
||||||
|
*/
|
||||||
|
@Override public XomwPPNode_Hash_Array getChildrenOfType(String name) {
|
||||||
|
XophpArray children = XophpArray.New();
|
||||||
|
int rawChildren_len = this.rawChildren.Len();
|
||||||
|
for (int idx = 0; idx < rawChildren_len; idx++) {
|
||||||
|
XophpArrayItm itm = this.rawChildren.Get_at_itm(idx);
|
||||||
|
Object child = itm.Val();
|
||||||
|
if (XophpType_.is_array(child) && String_.Eq(((XophpArray)child).Get_at_str(XomwPPNode_Hash_Tree.NAME), name)) {
|
||||||
|
children.Add(XomwPPNode_Hash_Tree.factory(this.rawChildren, itm.Key_as_int()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new XomwPPNode_Hash_Array(children);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the raw child array. For @gplx.Internal protected use.
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public XophpArray getRawChildren() {
|
||||||
|
return this.rawChildren;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
@Override public int getLength() {
|
||||||
|
return XophpInt_.False;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int i
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
@Override public XomwPPNode item(int i) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
@Override public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split a "<part>" node into an associative array containing:
|
||||||
|
* - name PPNode name
|
||||||
|
* - index String index
|
||||||
|
* - value PPNode value
|
||||||
|
*
|
||||||
|
* @throws MWException
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
@Override public XophpArray splitArg() {
|
||||||
|
return XomwPPNode_Hash_Tree.splitRawArg(this.rawChildren);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like splitArg() but for a raw child array. For @gplx.Internal protected use only.
|
||||||
|
*/
|
||||||
|
public static XophpArray splitRawArg(XophpArray children) {
|
||||||
|
XophpArray bits = XophpArray.New();
|
||||||
|
int childrenLen = children.Len();
|
||||||
|
for (int j = 0; j < childrenLen; j++) {
|
||||||
|
XophpArrayItm itm = children.Get_at_itm(j);
|
||||||
|
Object childObj = itm.Val();
|
||||||
|
if (!XophpType_.is_array(childObj)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
XophpArray child = (XophpArray)childObj;
|
||||||
|
int i = itm.Key_as_int();
|
||||||
|
if (String_.Eq(child.Get_at_str(XomwPPNode_Hash_Tree.NAME), "name")) {
|
||||||
|
bits.Set("name", new XomwPPNode_Hash_Tree(children, i));
|
||||||
|
if (XophpObject_.isset_obj(child.Get_at_ary(XomwPPNode_Hash_Tree.CHILDREN).Get_at_ary(0).Get_at(XomwPPNode_Hash_Tree.NAME))
|
||||||
|
&& String_.Eq(child.Get_at_ary(XomwPPNode_Hash_Tree.CHILDREN).Get_at_ary(0).Get_at_str(XomwPPNode_Hash_Tree.NAME), "@index")
|
||||||
|
) {
|
||||||
|
bits.Set("index", child.Get_at_ary(XomwPPNode_Hash_Tree.CHILDREN).Get_at_ary(0).Get_at_ary(XomwPPNode_Hash_Tree.CHILDREN).Get_at(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (String_.Eq(child.Get_at_str(XomwPPNode_Hash_Tree.NAME), "value")) {
|
||||||
|
bits.Set("value", new XomwPPNode_Hash_Tree(children, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!XophpObject_.isset_obj(bits.Get_by("name"))) {
|
||||||
|
throw XomwMWException.New_by_method(XomwPPNode_Hash_Tree.class, "splitRawArg", "Invalid brace node passed to " + "splitRawArg");
|
||||||
|
}
|
||||||
|
if (!XophpObject_.isset_obj(bits.Get_by("index"))) {
|
||||||
|
bits.Set("index", "");
|
||||||
|
}
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split an "<ext>" node into an associative array containing name, attr, inner and close
|
||||||
|
* All values in the resulting array are PPNodes. Inner and close are optional.
|
||||||
|
*
|
||||||
|
* @throws MWException
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
@Override public XophpArray splitExt() {
|
||||||
|
return XomwPPNode_Hash_Tree.splitRawExt(this.rawChildren);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like splitExt() but for a raw child array. For @gplx.Internal protected use only.
|
||||||
|
*/
|
||||||
|
public static XophpArray splitRawExt(XophpArray children) {
|
||||||
|
XophpArray bits = XophpArray.New();
|
||||||
|
int len = children.count();
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
Object childObj = children.Get_at(i);
|
||||||
|
if (!XophpArray.is_array(childObj)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
XophpArray child = (XophpArray)childObj;
|
||||||
|
String childName = child.Get_at_str(XomwPPNode_Hash_Tree.NAME);
|
||||||
|
if (String_.Eq(childName, "name")) {
|
||||||
|
bits.Add("name", new XomwPPNode_Hash_Tree(children, i));
|
||||||
|
}
|
||||||
|
else if (String_.Eq(childName, "attr")) {
|
||||||
|
bits.Add("attr", new XomwPPNode_Hash_Tree(children, i));
|
||||||
|
}
|
||||||
|
else if (String_.Eq(childName, "inner")) {
|
||||||
|
bits.Add("inner", new XomwPPNode_Hash_Tree(children, i));
|
||||||
|
}
|
||||||
|
else if (String_.Eq(childName, "close")) {
|
||||||
|
bits.Add("close", new XomwPPNode_Hash_Tree(children, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!bits.isset("name")) {
|
||||||
|
throw new XomwMWException("Invalid ext node passed to " + "splitRawExt");
|
||||||
|
}
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split an "<h>" node
|
||||||
|
*
|
||||||
|
* @throws MWException
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
@Override public XophpArray splitHeading() {
|
||||||
|
if (!String_.Eq(this.name, "h")) {
|
||||||
|
throw new XomwMWException("Invalid h node passed to " + "splitHeading");
|
||||||
|
}
|
||||||
|
return XomwPPNode_Hash_Tree.splitRawHeading(this.rawChildren);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like splitHeading() but for a raw child array. For @gplx.Internal protected use only.
|
||||||
|
*/
|
||||||
|
public static XophpArray splitRawHeading(XophpArray children) {
|
||||||
|
XophpArray bits = XophpArray.New();
|
||||||
|
int len = children.count();
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
Object childObj = children.Get_at(i);
|
||||||
|
if (!XophpArray.is_array(childObj)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
XophpArray child = (XophpArray)childObj;
|
||||||
|
String childName = child.Get_at_str(XomwPPNode_Hash_Tree.NAME);
|
||||||
|
XophpArray childChildren = child.Get_at_ary(XomwPPNode_Hash_Tree.CHILDREN);
|
||||||
|
if (String_.Eq(childName, "@i")) {
|
||||||
|
bits.Add("i", childChildren.Get_at(0));
|
||||||
|
} else if (String_.Eq(childName, "@level")) {
|
||||||
|
bits.Add("level", childChildren.Get_at(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!bits.isset("i")) {
|
||||||
|
throw new XomwMWException("Invalid h node passed to " + "splitRawHeading");
|
||||||
|
}
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split a "<template>" or "<tplarg>" node
|
||||||
|
*
|
||||||
|
* @throws MWException
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public XophpArray splitTemplate() {
|
||||||
|
return XomwPPNode_Hash_Tree.splitRawTemplate(this.rawChildren);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like splitTemplate() but for a raw child array. For @gplx.Internal protected use only.
|
||||||
|
*/
|
||||||
|
public static XophpArray splitRawTemplate(XophpArray children) {
|
||||||
|
XophpArray parts = XophpArray.New();
|
||||||
|
XophpArray bits = XophpArray.New("lineStart" , "");
|
||||||
|
int len = children.count();
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
Object childObj = children.Get_at(i);
|
||||||
|
if (!XophpArray.is_array(childObj)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
XophpArray child = (XophpArray)childObj;
|
||||||
|
String childName = child.Get_at_str(XomwPPNode_Hash_Tree.NAME);
|
||||||
|
XophpArray childChildren = child.Get_at_ary(XomwPPNode_Hash_Tree.CHILDREN);
|
||||||
|
if (String_.Eq(childName, "title")) {
|
||||||
|
bits.Add("title", new XomwPPNode_Hash_Tree(childChildren, i));
|
||||||
|
} else if (String_.Eq(childName, "part")) {
|
||||||
|
parts.Add(new XomwPPNode_Hash_Tree(childChildren, i));
|
||||||
|
} else if (String_.Eq(childName, "@lineStart")) {
|
||||||
|
bits.Add("lineStart", "1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!bits.isset("title")) {
|
||||||
|
throw new XomwMWException("Invalid node passed to " + "splitRawTemplate");
|
||||||
|
}
|
||||||
|
bits.Add("parts", new XomwPPNode_Hash_Array(parts));
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,206 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
//namespace gplx.xowa.mediawiki.includes.parsers.preprocessors_new {
|
||||||
|
// ///**
|
||||||
|
// // * Expansion frame with template arguments
|
||||||
|
// // * @ingroup Parser
|
||||||
|
// // */
|
||||||
|
// class XomwPPTemplateFrame_Hash : XomwPPFrame_Hash { // public XophpArray numberedArgs, namedArgs;
|
||||||
|
// @gplx.New public XomwPPFrame_Hash parent;
|
||||||
|
// public XophpArray numberedExpansionCache, namedExpansionCache;
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * @param Preprocessor $preprocessor
|
||||||
|
// * @param boolean|PPFrame $parent
|
||||||
|
// * @param array $numberedArgs
|
||||||
|
// * @param array $namedArgs
|
||||||
|
// * @param boolean|Title $title
|
||||||
|
// */
|
||||||
|
// // parent = false, numberedArgs = [], namedArgs = []; titl = false
|
||||||
|
// public XomwPPTemplateFrame_Hash(XomwPreprocessor preprocessor, XomwPPFrame_Hash parent, XophpArray numberedArgs,
|
||||||
|
// XophpArray namedArgs, XomwTitle title
|
||||||
|
// ) : super(preprocessor) {
|
||||||
|
// this.parent = parent;
|
||||||
|
// this.numberedArgs = numberedArgs;
|
||||||
|
// this.namedArgs = namedArgs;
|
||||||
|
// this.title = title;
|
||||||
|
// String pdbk = title != null ? title.getPrefixedDBkeyStr() : XophpString_.False;
|
||||||
|
// this.titleCache = parent.titleCache;
|
||||||
|
// this.titleCache.Add(pdbk);
|
||||||
|
// this.loopCheckHash = /*clone*/ parent.loopCheckHash;
|
||||||
|
// if (pdbk != XophpString_.False) {
|
||||||
|
// this.loopCheckHash.Add(pdbk, true);
|
||||||
|
// }
|
||||||
|
// this.depth = parent.depth + 1;
|
||||||
|
// this.numberedExpansionCache = this.namedExpansionCache = XophpArray.New();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public override String toString() {
|
||||||
|
// String s = "tplframe{";
|
||||||
|
// boolean first = true;
|
||||||
|
// XophpArray args = XophpArray_.array_add(this.numberedArgs, this.namedArgs);
|
||||||
|
// int args_len = args.count();
|
||||||
|
// for (int i = 0; i < args_len; i++) {
|
||||||
|
// XophpArrayItm itm = args.Get_at_itm(i);
|
||||||
|
// if (first) {
|
||||||
|
// first = false;
|
||||||
|
// } else {
|
||||||
|
// s += ", ";
|
||||||
|
// }
|
||||||
|
// s += "\"" + itm.Key() + "\":\"" +
|
||||||
|
// XophpString_.str_replace("\"", "\\\"", itm.Val().toString()) + "\"";
|
||||||
|
// }
|
||||||
|
// s += "}";
|
||||||
|
// return s;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * @throws MWException
|
||||||
|
// * @param String|int $key
|
||||||
|
// * @param String|PPNode $root
|
||||||
|
// * @param int $flags
|
||||||
|
// * @return String
|
||||||
|
// */
|
||||||
|
// public override String cachedExpand(String key, XomwPPNode root, int flags) { // flags = 0
|
||||||
|
// if (XophpObject_.isset_obj(this.parent.childExpansionCache.Get_by(key))) {
|
||||||
|
// return this.parent.childExpansionCache.Get_by_str(key);
|
||||||
|
// }
|
||||||
|
// String retval = this.expand(root, flags);
|
||||||
|
// if (!this.isVolatile()) {
|
||||||
|
// this.parent.childExpansionCache.Set(key, retval);
|
||||||
|
// }
|
||||||
|
// return retval;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Returns true if there are no arguments in this frame
|
||||||
|
// *
|
||||||
|
// * @return boolean
|
||||||
|
// */
|
||||||
|
// public override boolean isEmpty() {
|
||||||
|
// return !this.numberedArgs.count_bool() && !this.namedArgs.count_bool();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * @return array
|
||||||
|
// */
|
||||||
|
// public override XophpArray getArguments() {
|
||||||
|
// XophpArray arguments = XophpArray.New();
|
||||||
|
// XophpArray merged = XophpArray_.array_merge(
|
||||||
|
// XophpArray_.array_keys(this.numberedArgs),
|
||||||
|
// XophpArray_.array_keys(this.namedArgs));
|
||||||
|
// int merged_len = merged.count();
|
||||||
|
// for (int i = 0; i < merged_len; i++) {
|
||||||
|
// String key = merged.Get_at_str(i);
|
||||||
|
// arguments.Set(key, this.getArgument(key));
|
||||||
|
// }
|
||||||
|
// return arguments;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * @return array
|
||||||
|
// */
|
||||||
|
// public override XophpArray getNumberedArguments() {
|
||||||
|
// XophpArray arguments = XophpArray.New();
|
||||||
|
// XophpArray temp = XophpArray_.array_keys(this.numberedArgs);
|
||||||
|
// int temp_len = temp.count();
|
||||||
|
// for (int i = 0; i < temp_len; i++) {
|
||||||
|
// String key = temp.Get_at_str(i);
|
||||||
|
// arguments.Set(key, this.getArgument(key));
|
||||||
|
// }
|
||||||
|
// return arguments;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * @return array
|
||||||
|
// */
|
||||||
|
// public override XophpArray getNamedArguments() {
|
||||||
|
// XophpArray arguments = XophpArray.New();
|
||||||
|
// XophpArray temp = XophpArray_.array_keys(this.namedArgs);
|
||||||
|
// int temp_len = temp.count();
|
||||||
|
// for (int i = 0; i < temp_len; i++) {
|
||||||
|
// String key = temp.Get_at_str(i);
|
||||||
|
// arguments.Set(key, this.getArgument(key));
|
||||||
|
// }
|
||||||
|
// return arguments;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * @param int $index
|
||||||
|
// * @return String|boolean
|
||||||
|
// */
|
||||||
|
// public String getNumberedArgument(int index) {
|
||||||
|
// if (!XophpObject_.isset_obj(this.numberedArgs.Get_at(index))) {
|
||||||
|
// return XophpString_.False;
|
||||||
|
// }
|
||||||
|
// if (!XophpObject_.isset_obj(this.numberedExpansionCache.Get_at(index))) {
|
||||||
|
// // No trimming for unnamed arguments
|
||||||
|
// this.numberedExpansionCache.Set(index, this.parent.expand(
|
||||||
|
// (XomwPPNode)this.numberedArgs.Get_at(index),
|
||||||
|
// XomwPPFrame.STRIP_COMMENTS
|
||||||
|
// ));
|
||||||
|
// }
|
||||||
|
// return this.numberedExpansionCache.Get_at_str(index);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * @param String $name
|
||||||
|
// * @return String|boolean
|
||||||
|
// */
|
||||||
|
// public String getNamedArgument(String name) {
|
||||||
|
// if (!XophpObject_.isset_obj(this.namedArgs.Get_by_str(name))) {
|
||||||
|
// return XophpString_.False;
|
||||||
|
// }
|
||||||
|
// if (!XophpObject_.isset_obj(this.namedExpansionCache.Get_by_str(name))) {
|
||||||
|
// // Trim named arguments post-expand, for backwards compatibility
|
||||||
|
// this.namedExpansionCache.Set(name, XophpString_.trim(
|
||||||
|
// this.parent.expand((XomwPPNode)this.namedArgs.Get_by(name), XomwPPFrame.STRIP_COMMENTS)));
|
||||||
|
// }
|
||||||
|
// return this.namedExpansionCache.Get_by_str(name);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * @param int|String $name
|
||||||
|
// * @return String|boolean
|
||||||
|
// */
|
||||||
|
// public String getArgument(Object name) {
|
||||||
|
// String text = this.getNumberedArgument((int)name);
|
||||||
|
// if (String_.Eq(text, XophpString_.False)) {
|
||||||
|
// text = this.getNamedArgument((String)name);
|
||||||
|
// }
|
||||||
|
// return text;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Return true if the frame is a template frame
|
||||||
|
// *
|
||||||
|
// * @return boolean
|
||||||
|
// */
|
||||||
|
// public override boolean isTemplate() {
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public override void setVolatile(boolean flag) { // flag = true
|
||||||
|
// super.setVolatile(flag);
|
||||||
|
// this.parent.setVolatile(flag);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public override void setTTL(int ttl) {
|
||||||
|
// super.setTTL(ttl);
|
||||||
|
// this.parent.setTTL(ttl);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
package gplx.xowa.mediawiki.includes.parsers.preprocessors_new; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*; import gplx.xowa.mediawiki.includes.parsers.*;
|
||||||
|
// MW.SRC:1.33
|
||||||
|
import gplx.core.btries.*;
|
||||||
|
import gplx.xowa.mediawiki.includes.parsers.preprocessors.*;
|
||||||
|
/**
|
||||||
|
* @ingroup Parser
|
||||||
|
*/
|
||||||
|
public abstract class XomwPreprocessor {
|
||||||
|
|
||||||
|
public static final int CACHE_VERSION = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array Brace matching rules.
|
||||||
|
*/
|
||||||
|
protected XophpArray rules = XophpArray.New()
|
||||||
|
.Add("{", XophpArray.New()
|
||||||
|
.Add("end", "}")
|
||||||
|
.Add("names", XophpArray.New()
|
||||||
|
.Add(2, "template")
|
||||||
|
.Add(3, "tplarg")
|
||||||
|
)
|
||||||
|
.Add("min", 2)
|
||||||
|
.Add("max", 3)
|
||||||
|
)
|
||||||
|
.Add("[", XophpArray.New()
|
||||||
|
.Add("end", "]")
|
||||||
|
.Add("names", XophpArray.New()
|
||||||
|
.Add(2, null)
|
||||||
|
)
|
||||||
|
.Add("min", 2)
|
||||||
|
.Add("max", 2)
|
||||||
|
)
|
||||||
|
.Add("-{", XophpArray.New()
|
||||||
|
.Add("end", "}-")
|
||||||
|
.Add("names", XophpArray.New()
|
||||||
|
.Add(2, null)
|
||||||
|
)
|
||||||
|
.Add("min", 2)
|
||||||
|
.Add("max", 2)
|
||||||
|
)
|
||||||
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a document tree in the cache.
|
||||||
|
*
|
||||||
|
* @param String $text
|
||||||
|
* @param int $flags
|
||||||
|
* @param String $tree
|
||||||
|
*/
|
||||||
|
protected void cacheSetTree(String text, int flags, String tree) {
|
||||||
|
// config = RequestContext::getMain()->getConfig();
|
||||||
|
//
|
||||||
|
// length = strlen(text);
|
||||||
|
// threshold = config->get("PreprocessorCacheThreshold");
|
||||||
|
// if (threshold === false || length < threshold || length > 1e6) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// cache = ObjectCache::getLocalClusterInstance();
|
||||||
|
// key = cache->makeKey(
|
||||||
|
// defined("static::CACHE_PREFIX") ? static::CACHE_PREFIX : static::class,
|
||||||
|
// md5(text), flags);
|
||||||
|
// value = sprintf("%08d", static::CACHE_VERSION) . tree;
|
||||||
|
//
|
||||||
|
// cache->set(key, value, 86400);
|
||||||
|
//
|
||||||
|
// LoggerFactory::getInstance("Preprocessor")
|
||||||
|
// ->info("Cached preprocessor output (key: key)");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to load a precomputed document tree for some given wikitext
|
||||||
|
* from the cache.
|
||||||
|
*
|
||||||
|
* @param String $text
|
||||||
|
* @param int $flags
|
||||||
|
* @return PPNode_Hash_Tree|boolean
|
||||||
|
*/
|
||||||
|
protected XomwPPNode_Hash_Tree cacheGetTree(String text, int flags) {
|
||||||
|
// $config = RequestContext::getMain()->getConfig();
|
||||||
|
//
|
||||||
|
// $length = strlen($text);
|
||||||
|
// $threshold = $config->get('PreprocessorCacheThreshold');
|
||||||
|
// if ($threshold === false || $length < $threshold || $length > 1e6) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// $cache = ObjectCache::getLocalClusterInstance();
|
||||||
|
//
|
||||||
|
// $key = $cache->makeKey(
|
||||||
|
// defined('static::CACHE_PREFIX') ? static::CACHE_PREFIX : static::class,
|
||||||
|
// md5($text), $flags);
|
||||||
|
//
|
||||||
|
// $value = $cache->get($key);
|
||||||
|
// if (!$value) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// $version = intval(substr($value, 0, 8));
|
||||||
|
// if ($version !== static::CACHE_VERSION) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// LoggerFactory::getInstance('Preprocessor')
|
||||||
|
// ->info("Loaded preprocessor output from cache (key: $key)");
|
||||||
|
//
|
||||||
|
// return substr($value, 8);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new top-level frame for expansion of a page
|
||||||
|
*
|
||||||
|
* @return PPFrame
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public XomwPPFrame newFrame() {return null;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new custom frame for programmatic use of parameter replacement
|
||||||
|
* as used in some extensions.
|
||||||
|
*
|
||||||
|
* @param array $args
|
||||||
|
*
|
||||||
|
* @return PPFrame
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public XomwPPFrame newCustomFrame(XophpArray args) {return null;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new custom node for programmatic use of parameter replacement
|
||||||
|
* as used in some extensions.
|
||||||
|
*
|
||||||
|
* @param array $values
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public XomwPPNode newPartNodeArray(XophpArray values) {return null;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preprocess text to a PPNode
|
||||||
|
*
|
||||||
|
* @param String $text
|
||||||
|
* @param int $flags
|
||||||
|
*
|
||||||
|
* @return PPNode
|
||||||
|
*/
|
||||||
|
@gplx.Virtual public XomwPPNode preprocessToObj(String text, int flags) {return null;} // flags = 0
|
||||||
|
|
||||||
|
@gplx.Virtual public String preprocessToDbg(String src, boolean for_inclusion) {return null;}
|
||||||
|
}
|
@ -0,0 +1,828 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
package gplx.xowa.mediawiki.includes.parsers.preprocessors_new; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*; import gplx.xowa.mediawiki.includes.parsers.*;
|
||||||
|
// MW.SRC:1.33
|
||||||
|
import gplx.core.bits.*;
|
||||||
|
import gplx.langs.regxs.*;
|
||||||
|
import gplx.xowa.mediawiki.includes.exception.*;
|
||||||
|
import gplx.xowa.mediawiki.includes.parsers.preprocessors.*;
|
||||||
|
/**
|
||||||
|
* Differences from DOM schema:
|
||||||
|
* * attribute nodes are children
|
||||||
|
* * "<h>" nodes that aren"t at the top are replaced with <possible-h>
|
||||||
|
*
|
||||||
|
* Nodes are stored in a recursive array data structure. A node store is an
|
||||||
|
* array where each element may be either a scalar (representing a text node)
|
||||||
|
* or a "descriptor", which is a two-element array where the first element is
|
||||||
|
* the node name and the second element is the node store for the children.
|
||||||
|
*
|
||||||
|
* Attributes are represented as children that have a node name starting with
|
||||||
|
* "@", and a single text node child.
|
||||||
|
*
|
||||||
|
* @todo: Consider replacing descriptor arrays with objects of a new cl+ass.
|
||||||
|
* Benchmark and measure resulting memory impact.
|
||||||
|
*
|
||||||
|
* @ingroup Parser
|
||||||
|
*/
|
||||||
|
public class XomwPreprocessor_Hash extends XomwPreprocessor {
|
||||||
|
/**
|
||||||
|
* @var Parser
|
||||||
|
*/
|
||||||
|
public XomwParser parser;
|
||||||
|
|
||||||
|
public static final String CACHE_PREFIX = "preprocess-hash";
|
||||||
|
@gplx.New public static final int CACHE_VERSION = 2;
|
||||||
|
|
||||||
|
public XomwPreprocessor_Hash(XomwParser parser) {
|
||||||
|
this.parser = parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return PPFrame_Hash
|
||||||
|
*/
|
||||||
|
@Override public XomwPPFrame newFrame() {
|
||||||
|
// return new XomwPPFrame_Hash(this);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $args
|
||||||
|
* @return PPCustomFrame_Hash
|
||||||
|
*/
|
||||||
|
// public XomwPPCustomFrame_Hash newCustomFrame(XophpArray args) {
|
||||||
|
// return new XomwPPCustomFrame_Hash(this, args);
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $values
|
||||||
|
* @return PPNode_Hash_Array
|
||||||
|
*/
|
||||||
|
@Override public XomwPPNode newPartNodeArray(XophpArray values) {
|
||||||
|
XophpArray list = XophpArray.New();
|
||||||
|
|
||||||
|
// foreach ($values as $k => $val) {
|
||||||
|
// if (is_int($k)) {
|
||||||
|
// $store = [ [ "part", [
|
||||||
|
// [ "name", [ [ "@index", [ $k ] ] ] ],
|
||||||
|
// [ "value", [ strval($val) ] ],
|
||||||
|
// ] ] ];
|
||||||
|
// } else {
|
||||||
|
// $store = [ [ "part", [
|
||||||
|
// [ "name", [ strval($k) ] ],
|
||||||
|
// "=",
|
||||||
|
// [ "value", [ strval($val) ] ],
|
||||||
|
// ] ] ];
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// $list[] = new PPNode_Hash_Tree($store, 0);
|
||||||
|
// }
|
||||||
|
|
||||||
|
XomwPPNode_Hash_Array node = new XomwPPNode_Hash_Array(list);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Hash_adp strspn_hash__eq = XophpString_.strspn_hash("=");
|
||||||
|
private static final Hash_adp strspn_hash__ws_tab = XophpString_.strspn_hash(" \t");
|
||||||
|
/**
|
||||||
|
* Preprocess some wikitext and return the document tree.
|
||||||
|
*
|
||||||
|
* @param String $text The text to parse
|
||||||
|
* @param int $flags Bitwise combination of:
|
||||||
|
* Parser::PTD_FOR_INCLUSION Handle "<noinclude>" and "<includeonly>" as if the text is being
|
||||||
|
* included. Default is to assume a direct page view.
|
||||||
|
*
|
||||||
|
* The generated DOM tree must depend only on the input text and the flags.
|
||||||
|
* The DOM tree must be the same in OT_HTML and OT_WIKI mode, to avoid a regression of T6899.
|
||||||
|
*
|
||||||
|
* Any flag added to the $flags parameter here, or any other parameter liable to cause a
|
||||||
|
* change in the DOM tree for a given text, must be passed through the section identifier
|
||||||
|
* in the section edit link and thus back to extractSections().
|
||||||
|
*
|
||||||
|
* @throws MWException
|
||||||
|
* @return PPNode_Hash_Tree
|
||||||
|
*/
|
||||||
|
@Override public XomwPPNode preprocessToObj(String text, int flags) { // flags = 0;
|
||||||
|
// global wgDisableLangConversion;
|
||||||
|
|
||||||
|
// tree = this.cacheGetTree(text, flags);
|
||||||
|
// if (tree !== false) {
|
||||||
|
// store = json_decode(tree);
|
||||||
|
// if (is_array(store)) {
|
||||||
|
// return new PPNode_Hash_Tree(store, 0);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
int forInclusion = flags & XomwParser.PTD_FOR_INCLUSION;
|
||||||
|
|
||||||
|
XophpArray xmlishElements = this.parser.getStripList();
|
||||||
|
XophpArray xmlishAllowMissingEndTag = XophpArray.New("includeonly", "noinclude", "onlyinclude");
|
||||||
|
boolean enableOnlyinclude = false;
|
||||||
|
XophpArray ignoredTags, ignoredElements;
|
||||||
|
if (XophpInt_.is_true(forInclusion)) {
|
||||||
|
ignoredTags = XophpArray.New("includeonly", "/includeonly");
|
||||||
|
ignoredElements = XophpArray.New("noinclude");
|
||||||
|
xmlishElements.Add("noinclude");
|
||||||
|
if (XophpString_.strpos(text, "<onlyinclude>") != -1
|
||||||
|
&& XophpString_.strpos(text, "</onlyinclude>") != -1
|
||||||
|
) {
|
||||||
|
enableOnlyinclude = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ignoredTags = XophpArray.New("noinclude", "/noinclude", "onlyinclude", "/onlyinclude");
|
||||||
|
ignoredElements = XophpArray.New("includeonly");
|
||||||
|
xmlishElements.Add("includeonly");
|
||||||
|
}
|
||||||
|
String xmlishRegex = XophpArray_.implode("|", XophpArray_.array_merge(xmlishElements, ignoredTags));
|
||||||
|
|
||||||
|
// Use "A" modifier (anchored) instead of "^", because ^ doesn"t work with an offset
|
||||||
|
Regx_adp elementsRegex = XophpRegex_.Pattern("(" + xmlishRegex + ")(?:\\s|\\/>|>)|(!--)", XophpRegex_.MODIFIER_i | XophpRegex_.MODIFIER_A);
|
||||||
|
|
||||||
|
XomwPPDStack_Hash stack = new XomwPPDStack_Hash(XomwPPDPart_Hash.Instance);
|
||||||
|
|
||||||
|
String searchBase = "[{<\n";
|
||||||
|
if (!XomwDefaultSettings.wgDisableLangConversion) {
|
||||||
|
searchBase += "-";
|
||||||
|
}
|
||||||
|
|
||||||
|
// For fast reverse searches
|
||||||
|
String revText = XophpString_.strrev(text);
|
||||||
|
int lengthText = XophpString_.strlen(text);
|
||||||
|
|
||||||
|
// Input pointer, starts out pointing to a pseudo-newline before the start
|
||||||
|
int i = 0;
|
||||||
|
// Current accumulator. See the doc comment for Preprocessor_Hash for the format.
|
||||||
|
XophpArray accum = stack.getAccum(); // =&
|
||||||
|
// True to find equals signs in arguments
|
||||||
|
boolean findEquals = false;
|
||||||
|
// True to take notice of pipe characters
|
||||||
|
boolean findPipe = false;
|
||||||
|
int headingIndex = 1;
|
||||||
|
// True if i is inside a possible heading
|
||||||
|
boolean inHeading = false;
|
||||||
|
// True if there are no more greater-than (>) signs right of i
|
||||||
|
boolean noMoreGT = false;
|
||||||
|
// Map of tag name => true if there are no more closing tags of given type right of i
|
||||||
|
XophpArray noMoreClosingTag = XophpArray.New();
|
||||||
|
// True to ignore all input up to the next <onlyinclude>
|
||||||
|
boolean findOnlyinclude = enableOnlyinclude;
|
||||||
|
// Do a line-start run without outputting an LF character
|
||||||
|
boolean fakeLineStart = true;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// // this.memCheck(); // XO.NOTE: commented out in MW
|
||||||
|
|
||||||
|
int startPos = 0;
|
||||||
|
if (findOnlyinclude) {
|
||||||
|
// Ignore all input up to the next <onlyinclude>
|
||||||
|
startPos = XophpString_.strpos(text, "<onlyinclude>", i);
|
||||||
|
if (XophpInt_.is_false(startPos)) {
|
||||||
|
// Ignored section runs to the end
|
||||||
|
accum.Add(XophpArray.New("ignore", XophpArray.New(XophpString_.substr(text, i))));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int tagEndPos = startPos + XophpString_.strlen("<onlyinclude>"); // past-the-end
|
||||||
|
accum.Add(XophpArray.New("ignore", XophpArray.New(XophpString_.substr(text, i, tagEndPos - i))));
|
||||||
|
i = tagEndPos;
|
||||||
|
findOnlyinclude = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String found = null, curChar = null;
|
||||||
|
XophpArray rule = null;
|
||||||
|
if (fakeLineStart) {
|
||||||
|
found = "line-start";
|
||||||
|
curChar = "";
|
||||||
|
} else {
|
||||||
|
// Find next opening brace, closing brace or pipe
|
||||||
|
String search = searchBase;
|
||||||
|
String currentClosing;
|
||||||
|
if (XophpObject_.is_false(stack.top)) {
|
||||||
|
currentClosing = "";
|
||||||
|
} else {
|
||||||
|
currentClosing = stack.top.close;
|
||||||
|
search += currentClosing;
|
||||||
|
}
|
||||||
|
if (findPipe) {
|
||||||
|
search += "|";
|
||||||
|
}
|
||||||
|
if (findEquals) {
|
||||||
|
// First equals will be for the template
|
||||||
|
search += "=";
|
||||||
|
}
|
||||||
|
rule = null;
|
||||||
|
// Output literal section, advance input counter
|
||||||
|
int literalLength = XophpString_.strcspn(text, XophpString_.strspn_hash(search), i);
|
||||||
|
if (literalLength > 0) {
|
||||||
|
XomwPreprocessor_Hash.addLiteral(accum, XophpString_.substr(text, i, literalLength));
|
||||||
|
i += literalLength;
|
||||||
|
}
|
||||||
|
if (i >= lengthText) {
|
||||||
|
if (XophpString_.eq(currentClosing, "\n")) {
|
||||||
|
// Do a past-the-end run to finish off the heading
|
||||||
|
curChar = "";
|
||||||
|
found = "line-end";
|
||||||
|
} else {
|
||||||
|
// All done
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String curTwoChar = null;
|
||||||
|
curChar = curTwoChar = Char_.To_str(String_.CharAt(text, i));
|
||||||
|
if ((i + 1) < lengthText) {
|
||||||
|
curTwoChar += Char_.To_str(String_.CharAt(text, i + 1));
|
||||||
|
}
|
||||||
|
if (String_.Eq(curChar, "|")) {
|
||||||
|
found = "pipe";
|
||||||
|
} else if (String_.Eq(curChar, "=")) {
|
||||||
|
found = "equals";
|
||||||
|
} else if (String_.Eq(curChar, "<")) {
|
||||||
|
found = "angle";
|
||||||
|
} else if (String_.Eq(curChar, "\n")) {
|
||||||
|
if (inHeading) {
|
||||||
|
found = "line-end";
|
||||||
|
} else {
|
||||||
|
found = "line-start";
|
||||||
|
}
|
||||||
|
} else if (String_.Eq(curTwoChar, currentClosing)) {
|
||||||
|
found = "close";
|
||||||
|
curChar = curTwoChar;
|
||||||
|
} else if (String_.Eq(curChar, currentClosing)) {
|
||||||
|
found = "close";
|
||||||
|
} else if (XophpObject_.isset_obj(this.rules.Get_by(curTwoChar))) {
|
||||||
|
curChar = curTwoChar;
|
||||||
|
found = "open";
|
||||||
|
rule = this.rules.Get_by_ary(curChar);
|
||||||
|
} else if (XophpObject_.isset_obj(this.rules.Get_by(curChar))) {
|
||||||
|
found = "open";
|
||||||
|
rule = this.rules.Get_by_ary(curChar);
|
||||||
|
} else {
|
||||||
|
// Some versions of PHP have a strcspn which stops on
|
||||||
|
// null characters; ignore these and continue.
|
||||||
|
// We also may get "-" and "}" characters here which
|
||||||
|
// don"t match -{ or currentClosing. Add these to
|
||||||
|
// output and continue.
|
||||||
|
if (String_.Eq(curChar, "-") || String_.Eq(curChar, "}")) {
|
||||||
|
XomwPreprocessor_Hash.addLiteral(accum, curChar);
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (String_.Eq(found, "angle")) {
|
||||||
|
String inner, close;
|
||||||
|
int attrEnd;
|
||||||
|
XophpArray matches = XophpArray.New();
|
||||||
|
// Handle </onlyinclude>
|
||||||
|
if (enableOnlyinclude
|
||||||
|
&& XophpString_.eq(XophpString_.substr(text, i, XophpString_.strlen("</onlyinclude>")), "</onlyinclude>")
|
||||||
|
) {
|
||||||
|
findOnlyinclude = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine element name
|
||||||
|
if (!XophpRegex_.preg_match_bool(elementsRegex, text, matches, 0, i + 1)) {
|
||||||
|
// Element name missing or not listed
|
||||||
|
XomwPreprocessor_Hash.addLiteral(accum, "<");
|
||||||
|
++i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Handle comments
|
||||||
|
if (XophpArray_.isset(matches, 2) && String_.Eq(matches.Get_at_str(2), "!--")) {
|
||||||
|
// To avoid leaving blank lines, when a sequence of
|
||||||
|
// space-separated comments is both preceded and followed by
|
||||||
|
// a newline (ignoring spaces), then
|
||||||
|
// trim leading and trailing spaces and the trailing newline.
|
||||||
|
|
||||||
|
// Find the end
|
||||||
|
int endPos = XophpString_.strpos(text, "-->", i + 4);
|
||||||
|
if (XophpInt_.is_false(endPos)) {
|
||||||
|
// Unclosed comment in input, runs to end
|
||||||
|
inner = XophpString_.substr(text, i);
|
||||||
|
accum.Add(XophpArray.New("comment", XophpArray.New(inner)));
|
||||||
|
i = lengthText;
|
||||||
|
} else {
|
||||||
|
// Search backwards for leading whitespace
|
||||||
|
int wsStart = XophpInt_.is_true(i) ? (i - XophpString_.strspn(revText, strspn_hash__ws_tab, lengthText - i)) : 0;
|
||||||
|
|
||||||
|
// Search forwards for trailing whitespace
|
||||||
|
// wsEnd will be the position of the last space (or the ">" if there"s none)
|
||||||
|
int wsEnd = endPos + 2 + XophpString_.strspn(text, strspn_hash__ws_tab, endPos + 3);
|
||||||
|
|
||||||
|
// Keep looking forward as long as we"re finding more
|
||||||
|
// comments.
|
||||||
|
XophpArray comments = XophpArray.New(XophpArray.New().Add(wsStart).Add(wsEnd));
|
||||||
|
while (XophpString_.eq(XophpString_.substr(text, wsEnd + 1, 4), "<!--")) {
|
||||||
|
int c = XophpString_.strpos(text, "-.", wsEnd + 4);
|
||||||
|
if (XophpInt_.is_false(c)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c = c + 2 + XophpString_.strspn(text, strspn_hash__ws_tab, c + 3);
|
||||||
|
comments.Add(XophpArray.New(wsEnd + 1).Add(c));
|
||||||
|
wsEnd = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eat the line if possible
|
||||||
|
// TODO: This could theoretically be done if wsStart == 0, i.e. for comments at
|
||||||
|
// the overall start. That"s not how Sanitizer::removeHTMLcomments() did it, but
|
||||||
|
// it"s a possible beneficial b/c break.
|
||||||
|
if (wsStart > 0 && XophpString_.eq(XophpString_.substr(text, wsStart - 1, 1), "\n")
|
||||||
|
&& XophpString_.eq(XophpString_.substr(text, wsEnd + 1, 1), "\n")
|
||||||
|
) {
|
||||||
|
// Remove leading whitespace from the end of the accumulator
|
||||||
|
int wsLength = i - wsStart;
|
||||||
|
int endIndex = XophpArray_.count(accum) - 1;
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
|
if (wsLength > 0
|
||||||
|
&& endIndex >= 0
|
||||||
|
&& XophpType_.is_string(accum.Get_at(endIndex))
|
||||||
|
&& XophpString_.strspn(accum.Get_at_str(endIndex), strspn_hash__ws_tab, -wsLength) == wsLength
|
||||||
|
) {
|
||||||
|
accum.Set(endIndex, XophpString_.substr(accum.Get_at_str(endIndex), 0, -wsLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump all but the last comment to the accumulator
|
||||||
|
int commentsLen = comments.Len();
|
||||||
|
for (int commentsIdx = 0; commentsIdx < commentsLen; commentsIdx++) {
|
||||||
|
XophpArrayItm itm = comments.Get_at_itm(commentsIdx);
|
||||||
|
int j = itm.Key_as_int();
|
||||||
|
XophpArray com = (XophpArray)itm.Val();
|
||||||
|
startPos = com.Get_at_int(0);
|
||||||
|
endPos = com.Get_at_int(1) + 1;
|
||||||
|
if (j == (XophpArray_.count(comments) - 1)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
inner = XophpString_.substr(text, startPos, endPos - startPos);
|
||||||
|
accum.Add(XophpArray.New("comment", XophpArray.New(inner)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do a line-start run next time to look for headings after the comment
|
||||||
|
fakeLineStart = true;
|
||||||
|
} else {
|
||||||
|
// No line to eat, just take the comment itself
|
||||||
|
startPos = i;
|
||||||
|
endPos += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (XophpObject_.is_true(stack.top)) {
|
||||||
|
XomwPPDPart part = stack.top.getCurrentPart();
|
||||||
|
if (!(XophpObject_.isset(part.commentEnd) && part.commentEnd == wsStart - 1)) {
|
||||||
|
part.visualEnd = wsStart;
|
||||||
|
}
|
||||||
|
// Else comments abutting, no change in visual end
|
||||||
|
part.commentEnd = endPos;
|
||||||
|
}
|
||||||
|
i = endPos + 1;
|
||||||
|
inner = XophpString_.substr(text, startPos, endPos - startPos + 1);
|
||||||
|
accum.Add(XophpArray.New("comment", XophpArray.New(inner)));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String name = matches.Get_at_str(1);
|
||||||
|
String lowerName = XophpString_.strtolower(name);
|
||||||
|
int attrStart = i + XophpString_.strlen(name) + 1;
|
||||||
|
|
||||||
|
// Find end of tag
|
||||||
|
int tagEndPos = noMoreGT ? XophpInt_.False : XophpString_.strpos(text, ">", attrStart);
|
||||||
|
if (XophpInt_.is_false(tagEndPos)) {
|
||||||
|
// Infinite backtrack
|
||||||
|
// Disable tag search to prevent worst-case O(N^2) performance
|
||||||
|
noMoreGT = true;
|
||||||
|
XomwPreprocessor_Hash.addLiteral(accum, "<");
|
||||||
|
++i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle ignored tags
|
||||||
|
if (XophpArray_.in_array(lowerName, ignoredTags)) {
|
||||||
|
accum.Add(XophpArray.New("ignore", XophpArray.New(XophpString_.substr(text, i, tagEndPos - i + 1))));
|
||||||
|
i = tagEndPos + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tagStartPos = i;
|
||||||
|
if (XophpString_.Char_eq(text, tagEndPos - 1, "/")) {
|
||||||
|
// Short end tag
|
||||||
|
attrEnd = tagEndPos - 1;
|
||||||
|
inner = null;
|
||||||
|
i = tagEndPos + 1;
|
||||||
|
close = null;
|
||||||
|
} else {
|
||||||
|
matches.Clear(); // XO
|
||||||
|
attrEnd = tagEndPos;
|
||||||
|
// Find closing tag
|
||||||
|
if (
|
||||||
|
!XophpObject_.isset_obj(noMoreClosingTag.Get_by(name)) &&
|
||||||
|
XophpRegex_.preg_match_bool("</" + XophpRegex_.preg_quote(name, "/") + "\\s*>", XophpRegex_.MODIFIER_i,
|
||||||
|
text, matches, XophpRegex_.PREG_OFFSET_CAPTURE, tagEndPos + 1)
|
||||||
|
) {
|
||||||
|
inner = XophpString_.substr(text, tagEndPos + 1, matches.Get_at_ary(0).Get_at_int(1) - tagEndPos - 1);
|
||||||
|
i = matches.Get_at_ary(0).Get_at_int(1) + XophpString_.strlen(matches.Get_at_ary(0).Get_at_str(0));
|
||||||
|
close = matches.Get_at_ary(0).Get_at_str(0);
|
||||||
|
} else {
|
||||||
|
// No end tag
|
||||||
|
if (XophpArray_.in_array(name, xmlishAllowMissingEndTag)) {
|
||||||
|
// Let it run out to the end of the text.
|
||||||
|
inner = XophpString_.substr(text, tagEndPos + 1);
|
||||||
|
i = lengthText;
|
||||||
|
close = null;
|
||||||
|
} else {
|
||||||
|
// Don"t match the tag, treat opening tag as literal and resume parsing.
|
||||||
|
i = tagEndPos + 1;
|
||||||
|
XomwPreprocessor_Hash.addLiteral(accum,
|
||||||
|
XophpString_.substr(text, tagStartPos, tagEndPos + 1 - tagStartPos));
|
||||||
|
// Cache results, otherwise we have O(N^2) performance for input like <foo><foo><foo>...
|
||||||
|
noMoreClosingTag.Set(name, true);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// <includeonly> and <noinclude> just become <ignore> tags
|
||||||
|
if (XophpArray_.in_array(lowerName, ignoredElements)) {
|
||||||
|
accum.Add(XophpArray.New("ignore", XophpArray.New(XophpString_.substr(text, tagStartPos, i - tagStartPos))));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String attr = null;
|
||||||
|
if (attrEnd <= attrStart) {
|
||||||
|
attr = "";
|
||||||
|
} else {
|
||||||
|
// Note that the attr element contains the whitespace between name and attribute,
|
||||||
|
// this is necessary for precise reconstruction during pre-save transform.
|
||||||
|
attr = XophpString_.substr(text, attrStart, attrEnd - attrStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
XophpArray children = XophpArray.New(
|
||||||
|
XophpArray.New("name", XophpArray.New(name)),
|
||||||
|
XophpArray.New("attr", XophpArray.New(attr)));
|
||||||
|
if (inner != null) {
|
||||||
|
children.Add(XophpArray.New("inner", XophpArray.New(inner)));
|
||||||
|
}
|
||||||
|
if (close != null) {
|
||||||
|
children.Add(XophpArray.New("close", XophpArray.New(close)));
|
||||||
|
}
|
||||||
|
accum.Add(XophpArray.New("ext", children));
|
||||||
|
} else if (String_.Eq(found, "line-start")) {
|
||||||
|
// Is this the start of a heading?
|
||||||
|
// Line break belongs before the heading element in any case
|
||||||
|
if (fakeLineStart) {
|
||||||
|
fakeLineStart = false;
|
||||||
|
} else {
|
||||||
|
XomwPreprocessor_Hash.addLiteral(accum, curChar);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = XophpString_.strspn(text, strspn_hash__eq, i, 6);
|
||||||
|
if (count == 1 && findEquals) {
|
||||||
|
// DWIM: This looks kind of like a name/value separator.
|
||||||
|
// Let"s let the equals handler have it and break the potential
|
||||||
|
// heading. This is heuristic, but AFAICT the methods for
|
||||||
|
// completely correct disambiguation are very complex.
|
||||||
|
} else if (count > 0) {
|
||||||
|
XophpArray piece = XophpArray.New()
|
||||||
|
.Add("open", "\n")
|
||||||
|
.Add("close", "\n")
|
||||||
|
.Add("parts", XophpArray.New(new XomwPPDPart_Hash(XophpString_.str_repeat("=", count))))
|
||||||
|
.Add("startPos", i)
|
||||||
|
.Add("count", count);
|
||||||
|
stack.push(piece);
|
||||||
|
accum = stack.getAccum(); // =&
|
||||||
|
XophpArray stackFlags = stack.getFlags();
|
||||||
|
if (XophpArray_.isset(stackFlags, "findEquals")) {
|
||||||
|
findEquals = stackFlags.Get_by_bool("findEquals");
|
||||||
|
}
|
||||||
|
if (XophpArray_.isset(stackFlags, "findPipe")) {
|
||||||
|
findPipe = stackFlags.Get_by_bool("findPipe");
|
||||||
|
}
|
||||||
|
if (XophpArray_.isset(stackFlags, "inHeading")) {
|
||||||
|
inHeading = stackFlags.Get_by_bool("inHeading");
|
||||||
|
}
|
||||||
|
i += count;
|
||||||
|
}
|
||||||
|
} else if (found == "line-end") {
|
||||||
|
XomwPPDStackElement piece = stack.top;
|
||||||
|
// A heading must be open, otherwise \n wouldn"t have been in the search list
|
||||||
|
// FIXME: Don"t use assert()
|
||||||
|
// phpcs:ignore MediaWiki.Usage.ForbiddenFunctions.assert
|
||||||
|
// assert(piece.open === "\n");
|
||||||
|
XomwPPDPart part = piece.getCurrentPart();
|
||||||
|
// Search back through the input to see if it has a proper close.
|
||||||
|
// Do this using the reversed String since the other solutions
|
||||||
|
// (end anchor, etc.) are inefficient.
|
||||||
|
int wsLength = XophpString_.strspn(revText, strspn_hash__ws_tab, lengthText - i);
|
||||||
|
int searchStart = i - wsLength;
|
||||||
|
// XO.NOTE: MW says isset(part.commentEnd) b/c commentEnd can be null due to magic property
|
||||||
|
if (XophpInt_.is_true(part.commentEnd) && searchStart - 1 == part.commentEnd) {
|
||||||
|
// Comment found at line end
|
||||||
|
// Search for equals signs before the comment
|
||||||
|
searchStart = part.visualEnd;
|
||||||
|
searchStart -= XophpString_.strspn(revText, strspn_hash__ws_tab, lengthText - searchStart);
|
||||||
|
}
|
||||||
|
XophpArray element;
|
||||||
|
int count = piece.count;
|
||||||
|
int equalsLength = XophpString_.strspn(revText, strspn_hash__eq, lengthText - searchStart);
|
||||||
|
if (equalsLength > 0) {
|
||||||
|
if (searchStart - equalsLength == piece.startPos) {
|
||||||
|
// This is just a single String of equals signs on its own line
|
||||||
|
// Replicate the doHeadings behavior /={count}(.+)={count}/
|
||||||
|
// First find out how many equals signs there really are (don"t stop at 6)
|
||||||
|
count = equalsLength;
|
||||||
|
if (count < 3) {
|
||||||
|
count = 0;
|
||||||
|
} else {
|
||||||
|
count = XophpMath_.min(6, XophpDouble_.intval((count - 1) / 2));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
count = XophpMath_.min(equalsLength, count);
|
||||||
|
}
|
||||||
|
if (count > 0) {
|
||||||
|
// Normal match, output <h>
|
||||||
|
element = XophpArray.New(XophpArray.New("possible-h",
|
||||||
|
XophpArray_.array_merge(
|
||||||
|
XophpArray.New(
|
||||||
|
XophpArray.New("@level", XophpArray.New(count)),
|
||||||
|
XophpArray.New("@i", XophpArray.New(headingIndex++))
|
||||||
|
),
|
||||||
|
accum
|
||||||
|
)
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
// Single equals sign on its own line, count=0
|
||||||
|
element = accum;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No match, no <h>, just pass down the inner text
|
||||||
|
element = accum;
|
||||||
|
}
|
||||||
|
// Unwind the stack
|
||||||
|
stack.pop();
|
||||||
|
accum = stack.getAccum(); // =&
|
||||||
|
XophpArray stackFlags = stack.getFlags();
|
||||||
|
if (XophpArray_.isset(stackFlags, "findEquals")) {
|
||||||
|
findEquals = stackFlags.Get_by_bool("findEquals");
|
||||||
|
}
|
||||||
|
if (XophpArray_.isset(stackFlags, "findPipe")) {
|
||||||
|
findPipe = stackFlags.Get_by_bool("findPipe");
|
||||||
|
}
|
||||||
|
if (XophpArray_.isset(stackFlags, "inHeading")) {
|
||||||
|
inHeading = stackFlags.Get_by_bool("inHeading");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the result to the enclosing accumulator
|
||||||
|
XophpArray_.array_splice(accum, XophpArray_.count(accum), 0, element);
|
||||||
|
|
||||||
|
// Note that we do NOT increment the input pointer.
|
||||||
|
// This is because the closing linebreak could be the opening linebreak of
|
||||||
|
// another heading. Infinite loops are avoided because the next iteration MUST
|
||||||
|
// hit the heading open case above, which unconditionally increments the
|
||||||
|
// input pointer.
|
||||||
|
} else if (String_.Eq(found, "open")) {
|
||||||
|
// count opening brace characters
|
||||||
|
int curLen = XophpString_.strlen(curChar);
|
||||||
|
int count = (curLen > 1) ?
|
||||||
|
// allow the final character to repeat
|
||||||
|
XophpString_.strspn(text, XophpString_.strspn_hash(XophpString_.Char_as_str(curChar, curLen - 1)), i + 1) + 1 :
|
||||||
|
XophpString_.strspn(text, XophpString_.strspn_hash(curChar), i);
|
||||||
|
|
||||||
|
String savedPrefix = "";
|
||||||
|
boolean lineStart = (i > 0 && XophpString_.Char_eq(text, i - 1, "\n"));
|
||||||
|
|
||||||
|
if (String_.Eq(curChar, "-{") && count > curLen) {
|
||||||
|
// -{ => {{ transition because rightmost wins
|
||||||
|
savedPrefix = "-";
|
||||||
|
i++;
|
||||||
|
curChar = "{";
|
||||||
|
count--;
|
||||||
|
rule = this.rules.Get_by_ary(curChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need to add to stack only if opening brace count is enough for one of the rules
|
||||||
|
if (count >= rule.Get_by_int("min")) {
|
||||||
|
// Add it to the stack
|
||||||
|
XophpArray piece = XophpArray.New()
|
||||||
|
.Add("open", curChar)
|
||||||
|
.Add("close", rule.Get_by("end"))
|
||||||
|
.Add("savedPrefix", savedPrefix)
|
||||||
|
.Add("count", count)
|
||||||
|
.Add("lineStart", lineStart)
|
||||||
|
;
|
||||||
|
|
||||||
|
stack.push(piece);
|
||||||
|
accum = stack.getAccum(); // =&
|
||||||
|
XophpArray stackFlags = stack.getFlags();
|
||||||
|
if (XophpArray_.isset(stackFlags, "findEquals")) {
|
||||||
|
findEquals = stackFlags.Get_by_bool("findEquals");
|
||||||
|
}
|
||||||
|
if (XophpArray_.isset(stackFlags, "findPipe")) {
|
||||||
|
findPipe = stackFlags.Get_by_bool("findPipe");
|
||||||
|
}
|
||||||
|
if (XophpArray_.isset(stackFlags, "inHeading")) {
|
||||||
|
inHeading = stackFlags.Get_by_bool("inHeading");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Add literal brace(s)
|
||||||
|
XomwPreprocessor_Hash.addLiteral(accum, savedPrefix + XophpString_.str_repeat(curChar, count));
|
||||||
|
}
|
||||||
|
i += count;
|
||||||
|
} else if (String_.Eq(found, "close")) {
|
||||||
|
XomwPPDStackElement_Hash piece = (XomwPPDStackElement_Hash)stack.top;
|
||||||
|
// lets check if there are enough characters for closing brace
|
||||||
|
int maxCount = piece.count;
|
||||||
|
if (String_.Eq(piece.close, "}-") && String_.Eq(curChar, "}")) {
|
||||||
|
maxCount--; // don"t try to match closing "-" as a "}"
|
||||||
|
}
|
||||||
|
int curLen = XophpString_.strlen(curChar);
|
||||||
|
int count = (curLen > 1) ? curLen :
|
||||||
|
XophpString_.strspn(text, XophpString_.strspn_hash(curChar), i, maxCount);
|
||||||
|
|
||||||
|
// check for maximum matching characters (if there are 5 closing
|
||||||
|
// characters, we will probably need only 3 - depending on the rules)
|
||||||
|
rule = this.rules.Get_by_ary(piece.open);
|
||||||
|
int matchingCount;
|
||||||
|
if (count > rule.Get_by_int("max")) {
|
||||||
|
// The specified maximum exists in the callback array, unless the caller
|
||||||
|
// has made an error
|
||||||
|
matchingCount = rule.Get_by_int("max");
|
||||||
|
} else {
|
||||||
|
// Count is less than the maximum
|
||||||
|
// Skip any gaps in the callback array to find the true largest match
|
||||||
|
// Need to use array_key_exists not isset because the callback can be null
|
||||||
|
matchingCount = count;
|
||||||
|
while (matchingCount > 0 && !XophpArray_.array_key_exists(matchingCount, rule.Get_by_ary("names"))) {
|
||||||
|
--matchingCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String endText;
|
||||||
|
XophpArray element;
|
||||||
|
if (matchingCount <= 0) {
|
||||||
|
// No matching element found in callback array
|
||||||
|
// Output a literal closing brace and continue
|
||||||
|
endText = XophpString_.substr(text, i, count);
|
||||||
|
XomwPreprocessor_Hash.addLiteral(accum, endText);
|
||||||
|
i += count;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String name = rule.Get_by_ary("names").Get_by_str(matchingCount);
|
||||||
|
if (name == null) {
|
||||||
|
// No element, just literal text
|
||||||
|
endText = XophpString_.substr(text, i, matchingCount);
|
||||||
|
element = piece.breakSyntax(matchingCount);
|
||||||
|
XomwPreprocessor_Hash.addLiteral(element, endText);
|
||||||
|
} else {
|
||||||
|
// Create XML element
|
||||||
|
XophpArray parts = piece.parts;
|
||||||
|
XophpArray titleAccum = ((XomwPPDPart)parts.Get_at(0)).output;
|
||||||
|
XophpArray_.unset(parts, 0);
|
||||||
|
|
||||||
|
XophpArray children = XophpArray.New();
|
||||||
|
|
||||||
|
// The invocation is at the start of the line if lineStart is set in
|
||||||
|
// the stack, and all opening brackets are used up.
|
||||||
|
if (maxCount == matchingCount &&
|
||||||
|
!XophpObject_.empty(piece.lineStart) &&
|
||||||
|
XophpString_.strlen(piece.savedPrefix) == 0) {
|
||||||
|
children.Add(XophpArray.New("@lineStart", XophpArray.New(1)));
|
||||||
|
}
|
||||||
|
XophpArray titleNode = XophpArray.New("title", titleAccum);
|
||||||
|
children.Add(titleNode);
|
||||||
|
int argIndex = 1;
|
||||||
|
int parts_len = parts.Len();
|
||||||
|
for (int j = 0; j < parts_len; j++) {
|
||||||
|
XomwPPDPart_Hash part = (XomwPPDPart_Hash)parts.Get_at(j);
|
||||||
|
if (XophpInt_.is_true(part.eqpos)) { // XO.NOTE: MW says isset(part.commentEnd) b/c commentEnd can be null due to magic property
|
||||||
|
Object equalsNode = part.output.Get_at(part.eqpos);
|
||||||
|
XophpArray nameNode = XophpArray.New("name", XophpArray_.array_slice(part.output, 0, part.eqpos));
|
||||||
|
XophpArray valueNode = XophpArray.New("value", XophpArray_.array_slice(part.output, part.eqpos + 1));
|
||||||
|
XophpArray partNode = XophpArray.New("part", XophpArray.New(nameNode, equalsNode, valueNode));
|
||||||
|
children.Add(partNode);
|
||||||
|
} else {
|
||||||
|
XophpArray nameNode = XophpArray.New("name", XophpArray.New(XophpArray.New("@index", XophpArray.New(argIndex++))));
|
||||||
|
XophpArray valueNode = XophpArray.New("value", part.output);
|
||||||
|
XophpArray partNode = XophpArray.New("part", XophpArray.New(nameNode, valueNode));
|
||||||
|
children.Add(partNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
element = XophpArray.New(XophpArray.New(name, children));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance input pointer
|
||||||
|
i += matchingCount;
|
||||||
|
|
||||||
|
// Unwind the stack
|
||||||
|
stack.pop();
|
||||||
|
accum = stack.getAccum(); // =&
|
||||||
|
|
||||||
|
// Re-add the old stack element if it still has unmatched opening characters remaining
|
||||||
|
if (matchingCount < piece.count) {
|
||||||
|
piece.parts = XophpArray.New(new XomwPPDPart_Hash(""));
|
||||||
|
piece.count -= matchingCount;
|
||||||
|
// do we still qualify for any callback with remaining count?
|
||||||
|
int min = this.rules.Get_by_ary(piece.open).Get_by_int("min");
|
||||||
|
if (piece.count >= min) {
|
||||||
|
stack.push(piece);
|
||||||
|
accum = stack.getAccum(); // =&
|
||||||
|
} else if (piece.count == 1 && String_.Eq(piece.open, "{") && String_.Eq(piece.savedPrefix, "-")) {
|
||||||
|
piece.savedPrefix = "";
|
||||||
|
piece.open = "-{";
|
||||||
|
piece.count = 2;
|
||||||
|
piece.close = this.rules.Get_by_ary(piece.open).Get_by_str("end");
|
||||||
|
stack.push(piece);
|
||||||
|
accum = stack.getAccum(); // =&
|
||||||
|
} else {
|
||||||
|
String s = XophpString_.substr(piece.open, 0, -1);
|
||||||
|
s += XophpString_.str_repeat(
|
||||||
|
XophpString_.substr(piece.open, -1),
|
||||||
|
piece.count - XophpString_.strlen(s)
|
||||||
|
);
|
||||||
|
XomwPreprocessor_Hash.addLiteral(accum, piece.savedPrefix + s);
|
||||||
|
}
|
||||||
|
} else if (!String_.Eq(piece.savedPrefix, "")) {
|
||||||
|
XomwPreprocessor_Hash.addLiteral(accum, piece.savedPrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
XophpArray stackFlags = stack.getFlags();
|
||||||
|
if (XophpArray_.isset(stackFlags, "findEquals")) {
|
||||||
|
findEquals = stackFlags.Get_by_bool("findEquals");
|
||||||
|
}
|
||||||
|
if (XophpArray_.isset(stackFlags, "findPipe")) {
|
||||||
|
findPipe = stackFlags.Get_by_bool("findPipe");
|
||||||
|
}
|
||||||
|
if (XophpArray_.isset(stackFlags, "inHeading")) {
|
||||||
|
inHeading = stackFlags.Get_by_bool("inHeading");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add XML element to the enclosing accumulator
|
||||||
|
XophpArray_.array_splice(accum, XophpArray_.count(accum), 0, element);
|
||||||
|
} else if (String_.Eq(found, "pipe")) {
|
||||||
|
findEquals = true; // shortcut for getFlags()
|
||||||
|
stack.addPart();
|
||||||
|
accum = stack.getAccum(); // =&
|
||||||
|
++i;
|
||||||
|
} else if (String_.Eq(found, "equals")) {
|
||||||
|
findEquals = false; // shortcut for getFlags()
|
||||||
|
accum.Add(XophpArray.New("equals", XophpArray.New("=")));
|
||||||
|
stack.getCurrentPart().eqpos = XophpArray_.count(accum) - 1;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output any remaining unclosed brackets
|
||||||
|
XophpArray tempStack = stack.stack;
|
||||||
|
int tempStackLen = tempStack.Len();
|
||||||
|
for (int j = 0; j < tempStackLen; j++) {
|
||||||
|
XomwPPDStackElement_Hash piece = (XomwPPDStackElement_Hash)tempStack.Get_at(j);
|
||||||
|
XophpArray_.array_splice(stack.rootAccum, XophpArray_.count(stack.rootAccum), 0, piece.breakSyntax());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable top-level headings
|
||||||
|
XophpArray rootAccum = stack.rootAccum;
|
||||||
|
int rootAccumLen = rootAccum.Len();
|
||||||
|
for (int j = 0; j < rootAccumLen; j++) {
|
||||||
|
XophpArray node = rootAccum.Get_at_ary_or_null(j); // stack.rootAccum as &node
|
||||||
|
if (XophpArray_.is_array(node) && String_.Eq(node.Get_at_str(XomwPPNode_Hash_Tree.NAME), "possible-h")) {
|
||||||
|
node.Set(XomwPPNode_Hash_Tree.NAME, "h");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XophpArray rootStore = XophpArray.New(XophpArray.New("root", stack.rootAccum));
|
||||||
|
XomwPPNode_Hash_Tree rootNode = new XomwPPNode_Hash_Tree(rootStore, 0);
|
||||||
|
|
||||||
|
// Cache
|
||||||
|
// tree = json_encode(rootStore, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||||
|
// if (tree !== false) {
|
||||||
|
// this.cacheSetTree(text, flags, tree);
|
||||||
|
// }
|
||||||
|
|
||||||
|
return rootNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addLiteral(XophpArray accum, String text) {
|
||||||
|
int n = XophpArray_.count(accum);
|
||||||
|
if (XophpInt_.is_true(n) && XophpType_.is_string(accum.Get_at(n - 1))) {
|
||||||
|
accum.Concat_str(n - 1, text);
|
||||||
|
} else {
|
||||||
|
accum.Add(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String preprocessToDbg(String src, boolean for_inclusion) {
|
||||||
|
XomwPPNode_Hash_Tree node = (XomwPPNode_Hash_Tree)this.preprocessToObj(src, for_inclusion ? 1 : 0);
|
||||||
|
return node.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,248 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||||
|
or alternatively under the terms of the Apache License Version 2.0.
|
||||||
|
|
||||||
|
You may use XOWA according to either of these licenses as is most appropriate
|
||||||
|
for your project on a case-by-case basis.
|
||||||
|
|
||||||
|
The terms of each license can be found in the source code repository:
|
||||||
|
|
||||||
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||||
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||||
|
*/
|
||||||
|
package gplx.xowa.mediawiki.includes.parsers.preprocessors_new; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*; import gplx.xowa.mediawiki.includes.parsers.*;
|
||||||
|
import org.junit.*;
|
||||||
|
public class XomwPreprocessor__tst {
|
||||||
|
private final XomwPreprocessor__fxt fxt = new XomwPreprocessor__fxt();
|
||||||
|
@Before public void init() {fxt.Clear();}
|
||||||
|
@Test public void Text() {
|
||||||
|
fxt.Test__parse("abc", "<root>abc</root>");
|
||||||
|
}
|
||||||
|
@Test public void Brack() {
|
||||||
|
fxt.Test__parse("a[[b]]c", "<root>a[[b]]c</root>");
|
||||||
|
}
|
||||||
|
@Test public void Brack__one() { // COVERS: "Add literal brace(s)"
|
||||||
|
fxt.Test__parse("a[b]c", "<root>a[b]c</root>");
|
||||||
|
}
|
||||||
|
@Test public void Brack__max() { // COVERS: "The specified maximum exists in the callback array, unless the caller"
|
||||||
|
fxt.Test__parse("a[[[[[b]]]]]c", "<root>a[[[[[b]]]]]c</root>");
|
||||||
|
}
|
||||||
|
@Test public void Template() {
|
||||||
|
fxt.Test__parse("a{{b}}c", "<root>a<template><title>b</title></template>c</root>");
|
||||||
|
}
|
||||||
|
@Test public void Template__args__idx() {
|
||||||
|
fxt.Test__parse("a{{b|c|d}}e", "<root>a<template><title>b</title><part><name index=\"1\" /><value>c</value></part><part><name index=\"2\" /><value>d</value></part></template>e</root>");
|
||||||
|
}
|
||||||
|
@Test public void Template__args__key() {
|
||||||
|
fxt.Test__parse("a{{b|c=d}}e", "<root>a<template><title>b</title><part><name>c</name>=<value>d</value></part></template>e</root>");
|
||||||
|
}
|
||||||
|
@Test public void Template__line_start() { // COVERS: "The invocation is at the start of the line if lineStart is set in"
|
||||||
|
fxt.Test__parse(String_.Concat_lines_nl_skip_last
|
||||||
|
( "a"
|
||||||
|
, "{{b}}"
|
||||||
|
), String_.Concat_lines_nl_skip_last
|
||||||
|
( "<root>a"
|
||||||
|
, "<template lineStart=\"1\"><title>b</title></template></root>"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
@Test public void Template__max() { // COVERS: "do we still qualify for any callback with remaining count?"
|
||||||
|
fxt.Test__parse("a{{{{{b}}}}}c", "<root>a<template><title><tplarg><title>b</title></tplarg></title></template>c</root>");
|
||||||
|
}
|
||||||
|
@Test public void Tplarg() {
|
||||||
|
fxt.Test__parse("a{{{b}}}c", "<root>a<tplarg><title>b</title></tplarg>c</root>");
|
||||||
|
}
|
||||||
|
@Test public void Tplarg__dflt() {
|
||||||
|
fxt.Test__parse("a{{{b|c}}}d", "<root>a<tplarg><title>b</title><part><name index=\"1\" /><value>c</value></part></tplarg>d</root>");
|
||||||
|
}
|
||||||
|
@Test public void Comment() {
|
||||||
|
fxt.Test__parse("a<!--b-->c", "<root>a<comment><!--b--></comment>c</root>");
|
||||||
|
}
|
||||||
|
@Test public void Comment__dangling() {// COVERS: "Unclosed comment in input, runs to end"
|
||||||
|
fxt.Test__parse("a<!--b", "<root>a<comment><!--b</comment></root>");
|
||||||
|
}
|
||||||
|
@Test public void Comment__ws() { // COVERS: "Search backwards for leading whitespace"
|
||||||
|
fxt.Test__parse("a <!--b--> c", "<root>a <comment><!--b--></comment> c</root>"); // NOTE: space is outside comment
|
||||||
|
}
|
||||||
|
@Test public void Comment__many__ws() {// COVERS: "Dump all but the last comment to the accumulator"
|
||||||
|
fxt.Test__parse("a <!--1--> <!--2--> z", "<root>a <comment><!--1--></comment> <comment><!--2--></comment> z</root>"); // NOTE: space is outside comment;
|
||||||
|
}
|
||||||
|
@Test public void Comment__nl__ws() { // COVERS: "Eat the line if possible"
|
||||||
|
fxt.Test__parse(String_.Concat_lines_nl_skip_last
|
||||||
|
( "a"
|
||||||
|
, " <!--1--> "
|
||||||
|
, " <!--2--> "
|
||||||
|
, "z"
|
||||||
|
), String_.Concat_lines_nl_skip_last
|
||||||
|
( "<root>a"
|
||||||
|
, "<comment> <!--1--> " // NOTE: space is inside </comment> if flanked by nl;
|
||||||
|
, "</comment><comment> <!--2--> "
|
||||||
|
, "</comment>z</root>"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
@Test public void Ext() { // COVERS.ALSO: "Note that the attr element contains the whitespace between name and attribute,"
|
||||||
|
fxt.Test__parse("a<pre id=\"1\">b</pre>c", "<root>a<ext><name>pre</name><attr> id="1"</attr><inner>b</inner><close></pre></close></ext>c</root>");
|
||||||
|
}
|
||||||
|
@Test public void Ext__inline() { // COVERS: "if ( $text[$tagEndPos - 1] == '/' ) {"
|
||||||
|
fxt.Test__parse("a<pre/>b" , "<root>a<ext><name>pre</name><attr></attr></ext>b</root>");
|
||||||
|
fxt.Test__parse("a<pre />b" , "<root>a<ext><name>pre</name><attr> </attr></ext>b</root>");
|
||||||
|
}
|
||||||
|
@Test public void Ext__end__pass__space() {// COVERS: "\s*" in `preg_match( "/<\/" . preg_quote( $name, '/' ) . "\s*>/i",`
|
||||||
|
fxt.Test__parse("a<pre>b</pre >c", "<root>a<ext><name>pre</name><attr></attr><inner>b</inner><close></pre ></close></ext>c</root>");
|
||||||
|
}
|
||||||
|
@Test public void Ext__end__pass__name() { // COVERS: "\s*" in `preg_match( "/<\/" . preg_quote( $name, '/' ) . "\s*>/i",`
|
||||||
|
fxt.Test__parse("a<pre>b</pro></pre>c", "<root>a<ext><name>pre</name><attr></attr><inner>b</pro></inner><close></pre></close></ext>c</root>");
|
||||||
|
}
|
||||||
|
@Test public void Ext__end__fail__angle() {// COVERS: "\s*" in `preg_match( "/<\/" . preg_quote( $name, '/' ) . "\s*>/i",`
|
||||||
|
fxt.Test__parse("a<pre>b</pre c", "<root>a<pre>b</pre c</root>");
|
||||||
|
}
|
||||||
|
@Test public void Ext__dangling() { // COVERS: "Let it run out to the end of the text."
|
||||||
|
fxt.Test__parse("a<pre>bc", "<root>a<pre>bc</root>");
|
||||||
|
}
|
||||||
|
@Test public void Ext__dangling__many() { // COVERS: "Cache results, otherwise we have O(N^2) performance for input like <foo><foo><foo>..."
|
||||||
|
fxt.Test__parse("a<pre><pre><pre>bc", "<root>a<pre><pre><pre>bc</root>");
|
||||||
|
}
|
||||||
|
@Test public void Ext__unclosed() { // COVERS: "Infinite backtrack"
|
||||||
|
fxt.Test__parse("a<pre bcd", "<root>a<pre bcd</root>");
|
||||||
|
}
|
||||||
|
@Test public void Ext__noinclude() { // COVERS: "<includeonly> and <noinclude> just become <ignore> tags"
|
||||||
|
fxt.Init__for_inclusion_(Bool_.N);
|
||||||
|
fxt.Test__parse("a<includeonly>b<noinclude>c</noinclude>d</includeonly>e", "<root>a<ignore><includeonly>b<noinclude>c</noinclude>d</includeonly></ignore>e</root>");
|
||||||
|
}
|
||||||
|
@Test public void Heading() {
|
||||||
|
fxt.Test__parse(String_.Concat_lines_nl_skip_last
|
||||||
|
( "a"
|
||||||
|
, "== b1 =="
|
||||||
|
, "z"
|
||||||
|
), String_.Concat_lines_nl_skip_last
|
||||||
|
( "<root>a"
|
||||||
|
, "<h level=\"2\" i=\"1\">== b1 ==</h>"
|
||||||
|
, "z</root>"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
@Test public void Heading__eos__no_nl() {
|
||||||
|
fxt.Test__parse(String_.Concat_lines_nl_skip_last
|
||||||
|
( "a"
|
||||||
|
, "== b1 =="
|
||||||
|
), String_.Concat_lines_nl_skip_last
|
||||||
|
( "<root>a"
|
||||||
|
, "<h level=\"2\" i=\"1\">== b1 ==</h></root>"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
@Test public void Heading__bos__implied_nl() { // COVERS: "Is this the start of a heading?"
|
||||||
|
fxt.Test__parse(String_.Concat_lines_nl_skip_last
|
||||||
|
( "== b1 =="
|
||||||
|
, "z"
|
||||||
|
), String_.Concat_lines_nl_skip_last
|
||||||
|
( "<root><h level=\"2\" i=\"1\">== b1 ==</h>"
|
||||||
|
, "z</root>"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
@Test public void Heading__dwim__y() { // COVERS: "DWIM: This looks kind of like a name/value separator."
|
||||||
|
fxt.Test__parse(String_.Concat_lines_nl_skip_last
|
||||||
|
( "a{{b|"
|
||||||
|
, "=c="
|
||||||
|
, "}}d"
|
||||||
|
), String_.Concat_lines_nl_skip_last
|
||||||
|
( "<root>a<template><title>b</title><part><name>"
|
||||||
|
, "</name>=<value>c="
|
||||||
|
, "</value></part></template>d</root>"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
@Test public void Heading__dwim__n() { // COVERS: "DWIM: This looks kind of like a name/value separator."
|
||||||
|
fxt.Test__parse(String_.Concat_lines_nl_skip_last
|
||||||
|
( "a{{b|"
|
||||||
|
, "==c=="
|
||||||
|
, "}}d"
|
||||||
|
), String_.Concat_lines_nl_skip_last
|
||||||
|
( "<root>a<template><title>b</title><part><name index=\"1\" /><value>"
|
||||||
|
, "<possible-h level=\"2\" i=\"1\">==c==</possible-h>" // NOTE: verified against MW:1.29; possible-h line hit
|
||||||
|
, "</value></part></template>d</root>"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
@Test public void Heading__comment() { // COVERS: "Comment found at line end"
|
||||||
|
fxt.Test__parse(String_.Concat_lines_nl_skip_last
|
||||||
|
( "a"
|
||||||
|
, "==b== <!--c-->"
|
||||||
|
, ""
|
||||||
|
), String_.Concat_lines_nl_skip_last
|
||||||
|
( "<root>a"
|
||||||
|
, "<h level=\"2\" i=\"1\">==b== <comment><!--c--></comment></h>"
|
||||||
|
, "</root>"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
@Test public void Heading__consecutive__5() { // COVERS: "This is just a single String of equals signs on its own line"
|
||||||
|
fxt.Test__parse(String_.Concat_lines_nl_skip_last
|
||||||
|
( "a"
|
||||||
|
, "====="
|
||||||
|
, ""
|
||||||
|
), String_.Concat_lines_nl_skip_last
|
||||||
|
( "<root>a"
|
||||||
|
, "<h level=\"2\" i=\"1\">=====</h>"
|
||||||
|
, "</root>"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
@Test public void Heading__consecutive__1() { // COVERS: "Single equals sign on its own line, count=0"
|
||||||
|
fxt.Test__parse(String_.Concat_lines_nl_skip_last
|
||||||
|
( "a"
|
||||||
|
, "="
|
||||||
|
, ""
|
||||||
|
), String_.Concat_lines_nl_skip_last
|
||||||
|
( "<root>a"
|
||||||
|
, "="
|
||||||
|
, "</root>"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
@Test public void Heading__unclosed() { // COVERS: "No match, no <h>, just pass down the inner src"
|
||||||
|
fxt.Test__parse(String_.Concat_lines_nl_skip_last
|
||||||
|
( "a"
|
||||||
|
, "===b"
|
||||||
|
, ""
|
||||||
|
), String_.Concat_lines_nl_skip_last
|
||||||
|
( "<root>a"
|
||||||
|
, "===b"
|
||||||
|
, "</root>"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
@Test public void Inclusion__n() {
|
||||||
|
fxt.Init__for_inclusion_(Bool_.N);
|
||||||
|
fxt.Test__parse("a<onlyinclude>b</onlyinclude>c", "<root>a<ignore><onlyinclude></ignore>b<ignore></onlyinclude></ignore>c</root>");
|
||||||
|
}
|
||||||
|
@Test public void Inclusion__y() {
|
||||||
|
fxt.Init__for_inclusion_(Bool_.Y);
|
||||||
|
fxt.Test__parse("a<onlyinclude>b</onlyinclude>c", "<root><ignore>a<onlyinclude></ignore>b<ignore></onlyinclude>c</ignore></root>");
|
||||||
|
}
|
||||||
|
@Test public void Ignored__noinclude() { // COVERS: "Handle ignored tags"
|
||||||
|
fxt.Init__for_inclusion_(Bool_.N);
|
||||||
|
fxt.Test__parse("a<noinclude>b</noinclude>c", "<root>a<ignore><noinclude></ignore>b<ignore></noinclude></ignore>c</root>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class XomwPreprocessor__fxt {
|
||||||
|
private boolean hash_enabled = Bool_.Y;
|
||||||
|
private boolean for_inclusion = false;
|
||||||
|
public XomwPreprocessor__fxt() {
|
||||||
|
}
|
||||||
|
public void Clear() {
|
||||||
|
hash_enabled = true;
|
||||||
|
for_inclusion = false;
|
||||||
|
}
|
||||||
|
public void Init__for_inclusion_(boolean v) {for_inclusion = v;}
|
||||||
|
public XomwPreprocessor__fxt Init__hash_y() {hash_enabled = Bool_.Y; return this;}
|
||||||
|
public void Test__parse(String src_str, String expd) {
|
||||||
|
List_adp list = List_adp_.New();
|
||||||
|
if (hash_enabled) {
|
||||||
|
XomwParser parser = new XomwParser(XomwEnv_fxt.NewTest());
|
||||||
|
XomwPreprocessor_Hash wkr_hash = new XomwPreprocessor_Hash(parser);
|
||||||
|
parser.mStripList.Add("pre");
|
||||||
|
list.Add(wkr_hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < list.Len(); i++) {
|
||||||
|
XomwPreprocessor wkr = (XomwPreprocessor)list.Get_at(i);
|
||||||
|
String actl = wkr.preprocessToDbg(src_str, for_inclusion);
|
||||||
|
Tfds.Eq_str_lines(expd, actl, src_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4585,7 +4585,7 @@ public class XomwLanguage {
|
|||||||
// For unknown languages, fallbackSequence returns an empty array,
|
// For unknown languages, fallbackSequence returns an empty array,
|
||||||
// hardcode fallback to 'en' in that case.
|
// hardcode fallback to 'en' in that case.
|
||||||
Object rv = XomwLanguage.getLocalisationCache().getItem(code, "fallbackSequence");
|
Object rv = XomwLanguage.getLocalisationCache().getItem(code, "fallbackSequence");
|
||||||
return rv == null ? XophpArray.New().Add("en") : (XophpArray)rv;
|
return rv == null ? XophpArray.New("en") : (XophpArray)rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
|
@ -114,8 +114,8 @@ public class XomwLanguage_tst {
|
|||||||
fxt.Test_commafy("-1234567890" , "-1,23,45,67,890");
|
fxt.Test_commafy("-1234567890" , "-1,23,45,67,890");
|
||||||
}
|
}
|
||||||
@Test public void handleExplicitPluralForms() {
|
@Test public void handleExplicitPluralForms() {
|
||||||
fxt.Test__handleExplicitPluralForms__string("1", XophpArray.New().Add("1=one"), "one");
|
fxt.Test__handleExplicitPluralForms__string("1", XophpArray.New("1=one"), "one");
|
||||||
fxt.Test__handleExplicitPluralForms__array("1", XophpArray.New().Add("no_match"), XophpArray.New().Add(0, "no_match"));
|
fxt.Test__handleExplicitPluralForms__array("1", XophpArray.New("no_match"), XophpArray.New().Add(0, "no_match"));
|
||||||
}
|
}
|
||||||
@Test public void getPluralRuleIndexNumber() {
|
@Test public void getPluralRuleIndexNumber() {
|
||||||
fxt.Init__pluralRulesXml
|
fxt.Init__pluralRulesXml
|
||||||
|
@ -36,7 +36,7 @@ class XomwRange {
|
|||||||
if (end == null) {
|
if (end == null) {
|
||||||
this.parts.Add(start);
|
this.parts.Add(start);
|
||||||
} else {
|
} else {
|
||||||
this.parts.Add(XophpArray.New().Add(start).Add(end));
|
this.parts.Add(XophpArray.New(start, end));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ package gplx.objects.strings.bfrs; import gplx.*; import gplx.objects.*; import
|
|||||||
import java.lang.*;
|
import java.lang.*;
|
||||||
import gplx.objects.primitives.*;
|
import gplx.objects.primitives.*;
|
||||||
import gplx.objects.errs.*;
|
import gplx.objects.errs.*;
|
||||||
|
import gplx.objects.strings.unicodes.*;
|
||||||
public class String_bfr {
|
public class String_bfr {
|
||||||
private java.lang.StringBuilder sb = new java.lang.StringBuilder();
|
private java.lang.StringBuilder sb = new java.lang.StringBuilder();
|
||||||
public boolean Has_none() {return this.Len() == 0;}
|
public boolean Has_none() {return this.Len() == 0;}
|
||||||
@ -32,6 +33,16 @@ public class String_bfr {
|
|||||||
Add_char(c);
|
Add_char(c);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
public String_bfr Add_char_by_code(int code) {
|
||||||
|
if (code >= Ustring_.Surrogate_cp_bgn && code <= Ustring_.Surrogate_cp_end) {
|
||||||
|
sb.append((char)((code - 0x10000) / 0x400 + 0xD800));
|
||||||
|
sb.append((char)((code - 0x10000) % 0x400 + 0xDC00));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sb.append((char)code);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
public String_bfr Add_int_pad_bgn(char pad_char, int str_len, int val) {
|
public String_bfr Add_int_pad_bgn(char pad_char, int str_len, int val) {
|
||||||
int digit_len = Int_.Count_digits(val);
|
int digit_len = Int_.Count_digits(val);
|
||||||
int pad_len = str_len - digit_len;
|
int pad_len = str_len - digit_len;
|
||||||
|
Loading…
Reference in New Issue
Block a user