mirror of https://github.com/gnosygnu/xowa
XomwTemplateParser: Port XomwPreprocessor classes as direct translation of MW code [#632]
parent
17d7a7ebed
commit
7ad1291768
@ -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;}
|
||||||
|
}
|
||||||
|
|
@ -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;}
|
||||||
|
}
|
@ -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
|
||||||
|
// ( ""
|
||||||
|
// ));
|
||||||
|
}
|
||||||
|
}
|
@ -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 {
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue