/*
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.gfml; import gplx.*;
class GfmlFrame_nde extends GfmlFrame_base {
@Override public int FrameType() {return GfmlFrame_.Type_nde;}
public GfmlNde CurNde() {return nde;} GfmlNde nde;
public int CurNdeStartType() {return ndeStartType;} int ndeStartType;
public GfmlDocPos CurDocPos() {return docPos;} GfmlDocPos docPos = GfmlDocPos_.Root;
public void NullArea_set(boolean v) {nullArea = v;} private boolean nullArea = false;
public void DatTkn_set(GfmlTkn datTkn) { // < data >
if (nullArea) { // tkn is unnamed atrVal for new nde; EX: < a:; data >
nullArea = false;
GfmlFrame_nde frame = NewFrame(GfmlNdeStartType.DatTkn);
frame.tknMgr.DatTkn_set(datTkn);
}
else {
GfmlTkn itmKeyTkn = tknMgr.KeyTkn_pop();
if (itmKeyTkn != GfmlTkn_.Null) // elemKey is pending: tkn is atrVal; EX: < a=data >
tknMgr.ExecMakeAtr(itmKeyTkn, datTkn);
else // tkn is unnamed atrVal; EX: < a datTkn >
tknMgr.DatTkn_set(datTkn);
}
}
public void NdeBody_bgn(GfmlTkn symTkn) { // EX: < { >
WaitingTkns_AddSym(symTkn, GfmlNdeSymType.BodyBgn);
GfmlFrame_nde frame = this;
if (nullArea) // EX: {{ NOTE: else nde is in header; don't begin nde; EX: a:{
frame = NewFrame(GfmlNdeStartType.Brace);
tknMgr.ExecXferTkns_ndeBgn(this.CurNde());
frame.nullArea = true;
}
public void NdeInline(GfmlTkn symTkn) { // ;
WaitingTkns_AddSym(symTkn, GfmlNdeSymType.Inline);
if (nullArea) // empty node; EX: < ;; > NOTE: this will not be called if dataTkn is present, since dataTkn starts node; EX: < a; >
NewFrame(GfmlNdeStartType.Inline);
bldr.Frames_end(); // NOTE: no need for frame.nullArea = true b/c frame is ended
}
public void KeyTkn_set(GfmlTkn symTkn) { // EX: < = >
WaitingTkns_AddSym(symTkn, GfmlNdeSymType.Key);
tknMgr.KeyTkn_setFromDataTknOrFail();
}
public void NdeHeader_set(GfmlTkn symTkn) { // EX: < : >
WaitingTkns_AddSym(symTkn, GfmlNdeSymType.Hnd);
tknMgr.IdxNdeBgn_setToAtrBgn();
tknMgr.HndTkn_setByDatTknOrFail();
GfmlTkn hnd = tknMgr.HndTkn_pop();
GfmlFrame_nde frame = this;
if (bldr.CurNdeFrame().CurNdeStartType() == GfmlNdeStartType.Prop) // EX: < [a: > - must start new sub node;
frame = NewFrame(GfmlNdeStartType.Hnd);
frame.CurNde().HndTkn_set(hnd);
bldr.TypeMgr().NdeResolve(frame.CurNde(), ownerTypeKey);
}
public void NdeDot(GfmlTkn symTkn) { // EX: < . >
GfmlFrame_nde frm = this, oldFrm = this;
GfmlTkn hndTkn = HndTkn_GetForDotOp(frm); // get hndTkn; needed for (a) newFrm if prpNde; or (b) curFrm
boolean createPrpNde = dotSymCreatesPrpNde; // get createPrpNde b/c it will be reused later in this proc
if (createPrpNde) { // inside parens; . will create a prpNde EX: a:(b.c); vs a.b
frm = NewFrame(GfmlNdeStartType.Dot);
frm.nde.KeyedSubObj_(true); // NOTE: must set prpNdes to keyed
frm.nde.ChainId_(bldr.ChainIdNext());
}
if (hndTkn != GfmlTkn_.Null) { // NOTE: need to check for Null to handle ")."; EX: a.b().c(); 2nd . would return Null and overwrite b
if (frm.nde.HndTkn() == GfmlTkn_.Null)
frm.nde.HndTkn_set(hndTkn);
else
tknMgr.ExecMakeAtr(GfmlTkn_.Null, hndTkn);
}
frm.WaitingTkns_AddSym(symTkn, GfmlNdeSymType.Dot); // REVIEW: may want to dump into differnt nde...
frm.tknMgr.ExecXferTkns_ndeBgn(frm.CurNde());
oldFrm = frm; // get oldFrm
frm = frm.NewFrame(GfmlNdeStartType.Dot);
NdeDot_SetChainId(createPrpNde, oldFrm, frm);
}
public void NdeParen_bgn(GfmlTkn symTkn) { // EX: < ( >
HndTkn_SetFromDatTkn();
WaitingTkns_AddSym(symTkn, GfmlNdeSymType.HdrBgn); // REVIEW: may want to dump into differnt nde...
dotSymCreatesPrpNde = true;
frmHasParens = true;
}
public void NdeParen_end(GfmlTkn symTkn) { // EX: < ) >
tknMgr.ConsumeWaitingDatTkn(bldr.CurNde());
WaitingTkns_AddSym(symTkn, GfmlNdeSymType.HdrEnd);
dotSymCreatesPrpNde = false;
if (!frmHasParens) {
bldr.Frames_end();
bldr.CurNdeFrame().frmHasParens = false; // does this assume that auto-closing stops at paren node?
}
}
public void AtrSpr(GfmlTkn symTkn) { // EX: < , > NOTE: proc resembles NdeParen_end
tknMgr.ConsumeWaitingDatTkn(bldr.CurNde());
WaitingTkns_AddSym(symTkn, GfmlNdeSymType.AtrSpr);
if (!frmHasParens) {
bldr.Frames_end();
GfmlFrame_nde frm = bldr.CurNdeFrame(); // get the current frm after all popped
int idx = frm.waitingTkns.Count(); // NOTE: reset idxs b/c endFrame will automatically set to 0, and should be objCount
frm.tknMgr.IdxAtrBgn_setHack(idx);
frm.tknMgr.IdxNdeBgn_set(idx);
frm.nullArea = false; // NOTE: endFrame automatically sets nullArea to true; set to false
}
}
public void NdeProp_bgn(GfmlTkn symTkn) { // EX: < [ >
int oldNdeBgn = tknMgr.IdxNdeBgn(); // get oldNdeBgn; needed for header atrs; EX: < a:b [d] > ndeBgn = 0 (a pos), but will start keyNde at 5 ([ pos)
GfmlTkn keyTkn = tknMgr.KeyTkn_pop(); boolean keyTknExists = keyTkn != GfmlTkn_.Null;
int newNdeBgn = keyTknExists ? tknMgr.IdxAtrBgn() : waitingTkns.Count(); // if there is a key, set ndeBgn end atrBgn (EX: a=[); else set end curIdx
tknMgr.IdxNdeBgn_set(newNdeBgn);
WaitingTkns_AddSym(symTkn, GfmlNdeSymType.PrpBgn);
tknMgr.ConsumeWaitingDatTkn(nde);// NEEDED for KeydDefault
GfmlFrame_nde frame = NewFrame(GfmlNdeStartType.Prop);
tknMgr.IdxNdeBgn_set(oldNdeBgn); // restore oldNdeBgn
if (!keyTknExists) {
keyTkn = bldr.TypeMgr().FldPool().Keyed_PopNextAsTkn();
}
frame.CurNde().KeyTkn_set(keyTkn);
bldr.TypeMgr().NdeResolve(frame.CurNde(), ownerTypeKey);
frame.nullArea = false;
}
GfmlFrame_nde NewFrame(int newNdeFrameType) {
GfmlDocPos newPos = docPos.NewDown(subNdeCount++);
GfmlNde newNde = GfmlNde.new_(tknMgr.HndTkn_pop(), GfmlType_.Null, newNdeFrameType == GfmlNdeStartType.Prop).DocPos_(newPos);
GfmlFrame_nde newFrm = GfmlFrame_nde_.node_(bldr, newNde);
newFrm.ndeStartType = newNdeFrameType;
newFrm.ownerTypeKey = this.CurNde().Type().Key();
tknMgr.ExecXferTkns_ndeBgn(newNde);
bldr.Frames_push(newFrm);
bldr.TypeMgr().NdeBgn(newNde, newFrm.ownerTypeKey);
bldr.Doc().PragmaMgr().BgnCmds_exec(newPos, bldr);
return newFrm;
}
@Override public void Build_end(GfmlBldr bldr, GfmlFrame ownerFrame) {
GfmlFrame_nde ownerNdeFrame = (GfmlFrame_nde)ownerFrame;
tknMgr.ExecXferTkns_ndeAll(nde);
bldr.TypeMgr().NdeEnd();
bldr.Doc().PragmaMgr().EndCmds_exec(docPos, bldr);
bldr.Doc().PragmaMgr().Pragmas_compile(this.CurNde().Hnd(), bldr);
if (ownerFrame == null) return; // rootFrame; ignore below
ownerNdeFrame.waitingTkns.Add(this.CurNde());
int ndeType = this.CurNdeStartType();
if (ndeType == GfmlNdeStartType.Dot){ // if i was created by dot, close owner;
if (ownerNdeFrame.nde.ChainId() != this.nde.ChainId()) { // can also be if (nde.ChainHead())
}
else
bldr.Frames_end(); // auto-close dot ndes
}
else if (ndeType == GfmlNdeStartType.Prop) {}
else {
ownerNdeFrame.tknMgr.IdxNdeBgn_set(ownerNdeFrame.waitingTkns.Count());
ownerNdeFrame.nullArea = true; // reset
}
}
@Override protected GfmlFrame_base MakeNew_hook() {return new GfmlFrame_nde();}
public void IdxNdeBgn_set(int v) {tknMgr.IdxNdeBgn_set(v);}
@gplx.Internal protected void WaitingTkns_AddSym(GfmlTkn tkn, int type) {waitingTkns.Add(tkn); bldr.PrvSymType_set(type);}
@gplx.Internal protected void HndTkn_SetFromDatTkn() {
GfmlTkn hndTkn = tknMgr.DatTkn_pop();
if (hndTkn != GfmlTkn_.Null)
nde.HndTkn_set(hndTkn);
}
GfmlTkn HndTkn_GetForDotOp(GfmlFrame_nde frm) {
if (bldr.PrvSymType() == GfmlNdeSymType.HdrEnd) return GfmlTkn_.Null; // if prev was ), ignore; EX: a(). does not have hndTkn
GfmlTkn hndTkn = frm.tknMgr.DatTkn_pop();
// if (hndTkn == GfmlTkn_.Null) bldr.UsrMsgs_fail(GfmlUsrMsgs.fail_DatTkn_notFound());
return hndTkn;
}
void NdeDot_SetChainId(boolean createPrpNde, GfmlFrame_nde oldFrm, GfmlFrame_nde frm) {
if (createPrpNde) // prpNde; make sure new dotNde gets same chainId
frm.nde.ChainId_(oldFrm.nde.ChainId());
else { // oldNde is dotNde
if (oldFrm.ndeStartType == GfmlNdeStartType.Dot) // oldNde is dotNde; just take oldNde's chainId; ex: a.b.c
frm.nde.ChainId_(oldFrm.nde.ChainId());
else { // oldNde is something else
int chainId = bldr.ChainIdNext();
oldFrm.nde.ChainId_(chainId); // NOTE: needed for auto-closing; EX: {a.b;} a is a DatTkn nde, but needs to be closed when b is closed
frm.nde.ChainId_(chainId);
}
}
}
GfmlBldr bldr; GfmlFrame_ndeTknMgr tknMgr; int subNdeCount = 0; String ownerTypeKey; boolean frmHasParens = false; boolean dotSymCreatesPrpNde = false;
public static GfmlFrame_nde new_(GfmlBldr bldr, GfmlNde newNde, GfmlLxr newLxr) {
GfmlFrame_nde rv = new GfmlFrame_nde();
rv.bldr = bldr;
rv.ctor_(newLxr);
rv.tknMgr = GfmlFrame_ndeTknMgr.new_(rv, bldr);
rv.nde = newNde;
rv.docPos = newNde.DocPos();
return rv;
}
}
class GfmlFrame_nde_ {
public static GfmlFrame_nde as_(Object obj) {return obj instanceof GfmlFrame_nde ? (GfmlFrame_nde)obj : null;}
public static GfmlFrame_nde node_(GfmlBldr bldr, GfmlNde newNde) {return GfmlFrame_nde.new_(bldr, newNde, bldr.CurFrame().Lxr());}
@gplx.Internal protected static GfmlFrame_nde root_(GfmlBldr bldr, GfmlNde newNde, GfmlLxr newLxr) {return GfmlFrame_nde.new_(bldr, newNde, newLxr);}
@gplx.Internal protected static final GfmlFrame_nde OwnerRoot_ = null;
@gplx.Internal protected static void TransferToNde(GfmlObjList waitingTkns, GfmlNde nde, int bgn) {
int end = waitingTkns.Count();
for (int i = bgn; i < end; i++) {
GfmlObj tkn = waitingTkns.Get_at(i);
nde.SubObjs_Add(tkn);
}
if (bgn != end) // ignore if bgn == end
waitingTkns.Del_range(bgn, end - 1);
}
@gplx.Internal protected static void TransferToAtr(GfmlObjList src, GfmlAtr trg, int bgn, int end) {
int len = end - bgn;
if (len <= 0 || end == -1) return; // -1 b/c calling proc passes end - 1, and end may be 0
for (int i = 0; i < len; i++)
trg.SubObjs_Add(src.Get_at(i + bgn));
src.Del_range(bgn, end - 1);
}
}
class GfmlNdeStartType {
public static final int
Hnd = 1 // a:
, Brace = 2 // { // has no header (since header would have created node first)
, DatTkn = 3 // c; // has no hnd
, Inline = 4 // ; // is empty (since something would have created node first)
, Dot = 5 // a.b;
, Prop = 6 // a=[b c];
;
}
class GfmlNdeSymType {
public static final int
Null = 0
, BodyBgn = 1 // {
, BodyEnd = 2 // }
, Inline = 3 // ;
, Key = 4 // =
, Hnd = 5 // :
, Dot = 6 // .
, HdrBgn = 7 // (
, HdrEnd = 8 // )
, PrpBgn = 9 // [
, PrpEnd = 10 // ]
, AtrSpr = 11 // ,
;
}