a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2293 lines
62 KiB
C#
2293 lines
62 KiB
C#
//
|
|
// Commons.Xml.Relaxng.Derivative.RdpPatterns.cs
|
|
//
|
|
// Author:
|
|
// Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
|
|
//
|
|
// 2003 Atsushi Enomoto "No rights reserved."
|
|
//
|
|
// Copyright (c) 2004 Novell Inc.
|
|
// All rights reserved
|
|
//
|
|
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Xml;
|
|
using Commons.Xml.Relaxng;
|
|
|
|
using LabelList = System.Collections.Hashtable;
|
|
|
|
|
|
namespace Commons.Xml.Relaxng.Derivative
|
|
{
|
|
public delegate RdpPattern RdpApplyAfterHandler (RdpPattern p);
|
|
|
|
// abstract Pattern. Note that in README the classes in this namespace
|
|
// is explicitly written as not for public use (and hidden in monodoc
|
|
// for now).
|
|
public abstract class RdpPattern
|
|
{
|
|
public static readonly RdpPattern Anything;
|
|
|
|
static RdpPattern ()
|
|
{
|
|
RdpPattern anyAtts = new RdpList (new RdpAttribute (RdpAnyName.Instance, RdpText.Instance));
|
|
RdpElement anyElement = new RdpElement (RdpAnyName.Instance, null);
|
|
Anything = new RdpChoice (RdpEmpty.Instance, new RdpChoice (anyAtts, new RdpChoice (RdpText.Instance, new RdpList (anyElement))));
|
|
anyElement.Children = Anything;
|
|
}
|
|
|
|
internal bool nullableComputed;
|
|
internal bool isNullable;
|
|
Hashtable patternPool;
|
|
|
|
internal string debug ()
|
|
{
|
|
return RdpUtil.DebugRdpPattern (this, new Hashtable ());
|
|
}
|
|
|
|
public abstract RelaxngPatternType PatternType { get; }
|
|
|
|
public abstract RdpContentType ContentType { get; }
|
|
|
|
private Hashtable setupTable (Type type, RdpPattern p)
|
|
{
|
|
if (patternPool == null) // could be null for RdpElement etc.
|
|
patternPool = new Hashtable ();
|
|
|
|
Hashtable typePool = (Hashtable) patternPool [type];
|
|
if (typePool == null) {
|
|
typePool = new Hashtable ();
|
|
patternPool [type] = typePool;
|
|
}
|
|
Hashtable pTable = (Hashtable) typePool [p];
|
|
if (pTable == null) {
|
|
pTable = new Hashtable ();
|
|
typePool [p] = pTable;
|
|
}
|
|
return pTable;
|
|
}
|
|
|
|
internal RdpFlip MakeFlip (RdpBinaryFunction func, RdpPattern p)
|
|
{
|
|
if (patternPool == null) // could be null for RdpElement etc.
|
|
patternPool = new Hashtable ();
|
|
|
|
// Though this method takes function argument, all
|
|
// p1 callers have different pattern types, so we don't
|
|
// have to distinguish tables by func.
|
|
|
|
Hashtable table = patternPool [func] as Hashtable;
|
|
if (table == null) {
|
|
table = new Hashtable ();
|
|
patternPool [func] = table;
|
|
}
|
|
RdpFlip f = table [p] as RdpFlip;
|
|
if (f != null)
|
|
return f;
|
|
f = new RdpFlip (func, p);
|
|
table [p] = f;
|
|
return f;
|
|
}
|
|
|
|
public RdpChoice MakeChoiceLeaf (RdpPattern p)
|
|
{
|
|
if (patternPool == null) // could be null for RdpElement etc.
|
|
patternPool = new Hashtable ();
|
|
Hashtable leaves = (Hashtable) patternPool [typeof (RdpEmpty)];
|
|
if (leaves == null) {
|
|
leaves = new Hashtable ();
|
|
patternPool [typeof (RdpEmpty)] = leaves;
|
|
}
|
|
RdpChoice leaf = leaves [p] as RdpChoice;
|
|
if (leaf == null) {
|
|
leaf = new RdpChoice (RdpEmpty.Instance, p);
|
|
leaf.setInternTable (patternPool);
|
|
leaves [p] = leaf;
|
|
}
|
|
return leaf;
|
|
}
|
|
|
|
public RdpPattern MakeChoice (RdpPattern p1, RdpPattern p2)
|
|
{
|
|
if (p1.PatternType == RelaxngPatternType.NotAllowed)
|
|
return p2;
|
|
if (p2.PatternType == RelaxngPatternType.NotAllowed)
|
|
return p1;
|
|
if (p1 == p2)
|
|
return p1;
|
|
// choice-leaves support
|
|
if (p1.PatternType == RelaxngPatternType.Empty)
|
|
return MakeChoiceLeaf (p2);
|
|
if (p2.PatternType == RelaxngPatternType.Empty)
|
|
return MakeChoiceLeaf (p1);
|
|
|
|
if (p1.GetHashCode () > p2.GetHashCode ()) {
|
|
RdpPattern tmp = p1;
|
|
p1 = p2;
|
|
p2 = tmp;
|
|
}
|
|
|
|
Hashtable p1Table = setupTable (typeof (RdpChoice), p1);
|
|
if (p1Table [p2] == null) {
|
|
RdpChoice c = new RdpChoice (p1, p2);
|
|
c.setInternTable (this.patternPool);
|
|
p1Table [p2] = c;
|
|
}
|
|
return (RdpChoice) p1Table [p2];
|
|
}
|
|
|
|
public RdpPattern MakeGroup (RdpPattern p1, RdpPattern p2)
|
|
{
|
|
if (p1.PatternType == RelaxngPatternType.Empty)
|
|
return p2;
|
|
|
|
Hashtable p1Table = setupTable (typeof (RdpGroup), p1);
|
|
if (p1Table [p2] == null) {
|
|
RdpGroup g = new RdpGroup (p1, p2);
|
|
g.setInternTable (this.patternPool);
|
|
p1Table [p2] = g;
|
|
}
|
|
return (RdpGroup) p1Table [p2];
|
|
}
|
|
|
|
public RdpInterleave MakeInterleave (RdpPattern p1, RdpPattern p2)
|
|
{
|
|
if (p1.GetHashCode () > p2.GetHashCode ()) {
|
|
RdpPattern tmp = p1;
|
|
p1 = p2;
|
|
p2 = tmp;
|
|
}
|
|
|
|
Hashtable p1Table = setupTable (typeof (RdpInterleave), p1);
|
|
if (p1Table [p2] == null) {
|
|
RdpInterleave i = new RdpInterleave (p1, p2);
|
|
i.setInternTable (this.patternPool);
|
|
p1Table [p2] = i;
|
|
}
|
|
return (RdpInterleave) p1Table [p2];
|
|
}
|
|
|
|
public RdpAfter MakeAfter (RdpPattern p1, RdpPattern p2)
|
|
{
|
|
Hashtable p1Table = setupTable (typeof (RdpAfter), p1);
|
|
if (p1Table [p2] == null) {
|
|
RdpAfter a = new RdpAfter (p1, p2);
|
|
a.setInternTable (this.patternPool);
|
|
p1Table [p2] = a;
|
|
}
|
|
return (RdpAfter) p1Table [p2];
|
|
}
|
|
|
|
public RdpOneOrMore MakeOneOrMore (RdpPattern p)
|
|
{
|
|
if (patternPool == null) // could be null for RdpElement etc.
|
|
patternPool = new Hashtable ();
|
|
|
|
Hashtable pTable = (Hashtable) patternPool [typeof (RdpOneOrMore)];
|
|
if (pTable == null) {
|
|
pTable = new Hashtable ();
|
|
patternPool [typeof (RdpOneOrMore)] = pTable;
|
|
}
|
|
if (pTable [p] == null) {
|
|
RdpOneOrMore oom = new RdpOneOrMore (p);
|
|
oom.setInternTable (patternPool);
|
|
pTable [p] = oom;
|
|
}
|
|
return (RdpOneOrMore) pTable [p];
|
|
}
|
|
|
|
internal void setInternTable (Hashtable ht)
|
|
{
|
|
if (this.patternPool != null)
|
|
return;
|
|
this.patternPool = ht;
|
|
|
|
Hashtable pt = ht [GetType ()] as Hashtable;
|
|
if (pt == null) {
|
|
pt = new Hashtable ();
|
|
ht [GetType ()] = pt;
|
|
}
|
|
|
|
RdpAbstractSingleContent single =
|
|
this as RdpAbstractSingleContent;
|
|
if (single != null) {
|
|
if (pt [single.Child] == null) {
|
|
pt [single.Child] = this;
|
|
single.Child.setInternTable (ht);
|
|
}
|
|
return;
|
|
}
|
|
|
|
RdpAbstractBinary binary =
|
|
this as RdpAbstractBinary;
|
|
if (binary != null) {
|
|
Hashtable lTable = setupTable (GetType (), binary.LValue);
|
|
if (lTable [binary.RValue] == null) {
|
|
lTable [binary.RValue] = this;
|
|
binary.LValue.setInternTable (ht);
|
|
binary.RValue.setInternTable (ht);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// For rest patterns, only check recursively, without pooling.
|
|
RdpAttribute attr = this as RdpAttribute;
|
|
if (attr != null) {
|
|
attr.Children.setInternTable (ht);
|
|
return;
|
|
}
|
|
RdpElement el = this as RdpElement;
|
|
if (el != null) {
|
|
el.Children.setInternTable (ht);
|
|
return;
|
|
}
|
|
RdpDataExcept dex= this as RdpDataExcept;
|
|
if (dex != null) {
|
|
dex.Except.setInternTable (ht);
|
|
return;
|
|
}
|
|
|
|
switch (PatternType) {
|
|
case RelaxngPatternType.Empty:
|
|
case RelaxngPatternType.NotAllowed:
|
|
case RelaxngPatternType.Text:
|
|
case RelaxngPatternType.Data:
|
|
case RelaxngPatternType.Value:
|
|
return;
|
|
}
|
|
|
|
#if REPLACE_IN_ADVANCE
|
|
throw new InvalidOperationException ();
|
|
#endif
|
|
}
|
|
|
|
internal abstract void MarkReachableDefs ();
|
|
|
|
internal abstract void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept);
|
|
|
|
// This method is to detect text pattern inside interleave child.
|
|
internal abstract bool ContainsText ();
|
|
|
|
internal virtual RdpPattern ExpandRef (Hashtable defs)
|
|
{
|
|
return this;
|
|
}
|
|
|
|
internal virtual RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)
|
|
{
|
|
return this;
|
|
}
|
|
|
|
public abstract bool Nullable { get; }
|
|
|
|
internal virtual bool IsTextValueDependent {
|
|
get { return false; }
|
|
}
|
|
|
|
internal virtual bool IsContextDependent {
|
|
get { return false; }
|
|
}
|
|
|
|
// fills QName collection
|
|
public void GetLabels (LabelList elements, LabelList attributes)
|
|
{
|
|
GetLabels (elements, attributes, false);
|
|
}
|
|
|
|
public abstract void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass);
|
|
|
|
internal void AddNameLabel (LabelList names, RdpNameClass nc)
|
|
{
|
|
RdpName name = nc as RdpName;
|
|
if (name != null) {
|
|
XmlQualifiedName qname = new XmlQualifiedName (
|
|
name.LocalName, name.NamespaceURI);
|
|
names [qname] = qname;
|
|
return;
|
|
}
|
|
RdpNameClassChoice choice = nc as RdpNameClassChoice;
|
|
if (choice != null) {
|
|
AddNameLabel (names, choice.LValue);
|
|
AddNameLabel (names, choice.RValue);
|
|
return;
|
|
}
|
|
// For NsName and AnyName, do nothing.
|
|
}
|
|
|
|
#region Derivative
|
|
public virtual RdpPattern TextDeriv (string s, XmlReader reader)
|
|
{
|
|
return RdpNotAllowed.Instance;
|
|
}
|
|
|
|
internal virtual RdpPattern TextDeriv (string s, XmlReader reader, MemoizationStore memo)
|
|
{
|
|
return TextDeriv (s, reader);
|
|
}
|
|
|
|
internal virtual RdpPattern EmptyTextDeriv (MemoizationStore memo)
|
|
{
|
|
return TextDeriv (String.Empty, null, memo);
|
|
}
|
|
|
|
internal virtual RdpPattern TextOnlyDeriv ()
|
|
{
|
|
return this;
|
|
}
|
|
|
|
internal virtual RdpPattern TextOnlyDeriv (MemoizationStore store)
|
|
{
|
|
return this;
|
|
}
|
|
|
|
internal virtual RdpPattern MixedTextDeriv ()
|
|
{
|
|
return RdpNotAllowed.Instance;
|
|
}
|
|
|
|
internal virtual RdpPattern MixedTextDeriv (MemoizationStore memo)
|
|
{
|
|
return RdpNotAllowed.Instance;
|
|
}
|
|
|
|
public RdpPattern ListDeriv (string [] list, int index, XmlReader reader)
|
|
{
|
|
return listDerivInternal (list, 0, reader);
|
|
}
|
|
|
|
private RdpPattern listDerivInternal (string [] list, int start, XmlReader reader)
|
|
{
|
|
if (list.Length <= start)
|
|
return this;
|
|
else if (list [start].Length == 0)
|
|
return listDerivInternal (list, start + 1, reader);
|
|
else
|
|
return this.TextDeriv (list [start].Trim (RdpUtil.WhitespaceChars), reader).listDerivInternal (list, start + 1, reader);
|
|
}
|
|
|
|
// Choice(this, p)
|
|
public virtual RdpPattern Choice (RdpPattern p)
|
|
{
|
|
if (p is RdpNotAllowed)
|
|
return this;
|
|
else if (this is RdpNotAllowed)
|
|
return p;
|
|
else
|
|
return MakeChoice (this, p);
|
|
}
|
|
|
|
// Group(this, p)
|
|
public virtual RdpPattern Group (RdpPattern p)
|
|
{
|
|
if (p is RdpNotAllowed || this is RdpNotAllowed)
|
|
return RdpNotAllowed.Instance;
|
|
else if (p is RdpEmpty)
|
|
return this;
|
|
else if (this is RdpEmpty)
|
|
return p;
|
|
else
|
|
return MakeGroup (this, p);
|
|
}
|
|
|
|
// Interleave(this, p)
|
|
public virtual RdpPattern Interleave (RdpPattern p)
|
|
{
|
|
if (p is RdpNotAllowed || this is RdpNotAllowed)
|
|
return RdpNotAllowed.Instance;
|
|
else if (p is RdpEmpty)
|
|
return this;
|
|
else if (this is RdpEmpty)
|
|
return p;
|
|
else
|
|
return MakeInterleave (this, p);
|
|
}
|
|
|
|
// After(this, p)
|
|
public virtual RdpPattern After (RdpPattern p)
|
|
{
|
|
if (this is RdpNotAllowed || p is RdpNotAllowed)
|
|
return RdpNotAllowed.Instance;
|
|
else
|
|
return MakeAfter (this, p);
|
|
}
|
|
|
|
|
|
// applyAfter((f, p1=this), p2)
|
|
public virtual RdpPattern ApplyAfter (RdpApplyAfterHandler h)
|
|
{
|
|
throw new Exception ("INTERNAL ERROR: should not happen. This is " + this);
|
|
}
|
|
|
|
// startTagOpenDeriv (this, qname)
|
|
// startTagOpenDeriv _ qn = NotAllowed (default)
|
|
public virtual RdpPattern StartTagOpenDeriv (string name, string ns)
|
|
{
|
|
return RdpNotAllowed.Instance;
|
|
}
|
|
|
|
internal virtual RdpPattern StartTagOpenDeriv (string name, string ns, MemoizationStore memo)
|
|
{
|
|
return StartTagOpenDeriv (name, ns);
|
|
}
|
|
|
|
// attDeriv(ctx, this, att)
|
|
// attDeriv _ _ _ = NotAllowed
|
|
public virtual RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)
|
|
{
|
|
return RdpNotAllowed.Instance;
|
|
}
|
|
|
|
public virtual RdpPattern StartAttDeriv (string name, string ns)
|
|
{
|
|
return RdpNotAllowed.Instance;
|
|
}
|
|
|
|
internal virtual RdpPattern StartAttDeriv (string name, string ns, MemoizationStore memo)
|
|
{
|
|
return StartAttDeriv (name, ns);
|
|
}
|
|
|
|
public virtual RdpPattern EndAttDeriv ()
|
|
{
|
|
return RdpNotAllowed.Instance;
|
|
}
|
|
|
|
internal virtual RdpPattern EndAttDeriv (MemoizationStore memo)
|
|
{
|
|
return EndAttDeriv ();
|
|
}
|
|
|
|
public bool ValueMatch (string s, XmlReader reader)
|
|
{
|
|
return Nullable && Util.IsWhitespace (s) ||
|
|
TextDeriv (s, reader).Nullable;
|
|
}
|
|
|
|
public virtual RdpPattern StartTagCloseDeriv ()
|
|
{
|
|
return this;
|
|
}
|
|
|
|
internal virtual RdpPattern StartTagCloseDeriv (MemoizationStore memo)
|
|
{
|
|
return StartTagCloseDeriv ();
|
|
}
|
|
|
|
public RdpPattern OneOrMore ()
|
|
{
|
|
if (PatternType == RelaxngPatternType.NotAllowed)
|
|
return RdpNotAllowed.Instance;
|
|
else
|
|
return MakeOneOrMore (this);
|
|
}
|
|
|
|
public virtual RdpPattern EndTagDeriv ()
|
|
{
|
|
return RdpNotAllowed.Instance;
|
|
}
|
|
|
|
internal virtual RdpPattern EndTagDeriv (MemoizationStore memo)
|
|
{
|
|
return EndTagDeriv ();
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
// Empty
|
|
public class RdpEmpty : RdpPattern
|
|
{
|
|
public RdpEmpty () {}
|
|
static RdpEmpty ()
|
|
{
|
|
instance = new RdpEmpty ();
|
|
}
|
|
|
|
public override bool Nullable {
|
|
get { return true; }
|
|
}
|
|
|
|
internal override bool IsTextValueDependent {
|
|
get { return false; }
|
|
}
|
|
|
|
internal override bool IsContextDependent {
|
|
get { return false; }
|
|
}
|
|
|
|
static RdpEmpty instance;
|
|
public static RdpEmpty Instance {
|
|
get { return instance; }
|
|
}
|
|
|
|
public override RelaxngPatternType PatternType {
|
|
get { return RelaxngPatternType.Empty; }
|
|
}
|
|
|
|
public override RdpContentType ContentType {
|
|
get { return RdpContentType.Empty; }
|
|
}
|
|
|
|
public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
internal override void MarkReachableDefs ()
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
|
|
{
|
|
if (dataExcept)
|
|
throw new RelaxngException ("empty cannot appear under except of a data pattern.");
|
|
}
|
|
|
|
internal override bool ContainsText()
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// NotAllowed
|
|
public class RdpNotAllowed : RdpPattern
|
|
{
|
|
public RdpNotAllowed () {}
|
|
static RdpNotAllowed ()
|
|
{
|
|
instance = new RdpNotAllowed ();
|
|
}
|
|
|
|
static RdpNotAllowed instance;
|
|
public static RdpNotAllowed Instance {
|
|
get { return instance; }
|
|
}
|
|
|
|
public override bool Nullable {
|
|
get { return false; }
|
|
}
|
|
|
|
internal override bool IsTextValueDependent {
|
|
get { return false; }
|
|
}
|
|
|
|
internal override bool IsContextDependent {
|
|
get { return false; }
|
|
}
|
|
|
|
public override RdpPattern ApplyAfter (RdpApplyAfterHandler h)
|
|
{
|
|
return RdpNotAllowed.Instance;
|
|
}
|
|
|
|
public override RelaxngPatternType PatternType {
|
|
get { return RelaxngPatternType.NotAllowed; }
|
|
}
|
|
|
|
public override RdpContentType ContentType {
|
|
get { return RdpContentType.Empty; }
|
|
}
|
|
|
|
internal override void MarkReachableDefs ()
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
internal override bool ContainsText()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
|
|
{
|
|
// FIXME: Supposed to clear something here?
|
|
}
|
|
}
|
|
|
|
// Text
|
|
public class RdpText : RdpPattern
|
|
{
|
|
static RdpText instance;
|
|
public static RdpText Instance {
|
|
get { return instance; }
|
|
}
|
|
|
|
public RdpText () {}
|
|
static RdpText ()
|
|
{
|
|
instance = new RdpText ();
|
|
}
|
|
|
|
public override bool Nullable {
|
|
get { return true; }
|
|
}
|
|
|
|
internal override bool IsTextValueDependent {
|
|
get { return false; }
|
|
}
|
|
|
|
internal override bool IsContextDependent {
|
|
get { return false; }
|
|
}
|
|
|
|
public override RelaxngPatternType PatternType {
|
|
get { return RelaxngPatternType.Text; }
|
|
}
|
|
|
|
public override RdpContentType ContentType {
|
|
get { return RdpContentType.Complex; }
|
|
}
|
|
|
|
public override RdpPattern TextDeriv (string s, XmlReader reader)
|
|
{
|
|
return this;
|
|
}
|
|
|
|
internal override RdpPattern EmptyTextDeriv (MemoizationStore memo)
|
|
{
|
|
return this;
|
|
}
|
|
|
|
internal override RdpPattern MixedTextDeriv ()
|
|
{
|
|
return this;
|
|
}
|
|
|
|
internal override RdpPattern MixedTextDeriv (MemoizationStore memo)
|
|
{
|
|
return this;
|
|
}
|
|
|
|
internal override void MarkReachableDefs ()
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
|
|
{
|
|
if (list)
|
|
throw new RelaxngException ("text is not allowed under a list.");
|
|
if (dataExcept)
|
|
throw new RelaxngException ("text is not allowed under except of a list.");
|
|
}
|
|
|
|
internal override bool ContainsText()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
|
|
{
|
|
// do nothing
|
|
}
|
|
}
|
|
|
|
// AbstractBinary
|
|
public abstract class RdpAbstractBinary : RdpPattern
|
|
{
|
|
public RdpAbstractBinary (RdpPattern l, RdpPattern r)
|
|
{
|
|
this.l = l;
|
|
this.r = r;
|
|
}
|
|
|
|
RdpPattern l;
|
|
public RdpPattern LValue {
|
|
get { return l; }
|
|
set { l = value; }
|
|
}
|
|
|
|
RdpPattern r;
|
|
public RdpPattern RValue {
|
|
get { return r; }
|
|
set { r = value; }
|
|
}
|
|
|
|
RdpContentType computedContentType = RdpContentType.Invalid;
|
|
public override RdpContentType ContentType {
|
|
get {
|
|
if (computedContentType == RdpContentType.Invalid) {
|
|
if (l.ContentType == RdpContentType.Empty)
|
|
computedContentType = r.ContentType;
|
|
else if (r.ContentType == RdpContentType.Empty)
|
|
computedContentType = l.ContentType;
|
|
else if ((l.ContentType & RdpContentType.Simple) != 0 || ((r.ContentType & RdpContentType.Simple) != 0))
|
|
throw new RelaxngException ("The content type of this group is invalid.");
|
|
else
|
|
computedContentType = RdpContentType.Complex;
|
|
}
|
|
return computedContentType;
|
|
}
|
|
}
|
|
|
|
bool expanded;
|
|
internal override RdpPattern ExpandRef (Hashtable defs)
|
|
{
|
|
if (!expanded) {
|
|
l = l.ExpandRef (defs);
|
|
r = r.ExpandRef (defs);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)
|
|
{
|
|
if (visited.Contains (this))
|
|
return this;
|
|
visited.Add (this, this);
|
|
|
|
if (LValue.PatternType == RelaxngPatternType.NotAllowed ||
|
|
RValue.PatternType == RelaxngPatternType.NotAllowed) {
|
|
result = true;
|
|
return RdpNotAllowed.Instance;
|
|
} else if (LValue.PatternType == RelaxngPatternType.Empty) {
|
|
result = true;
|
|
return RValue.ReduceEmptyAndNotAllowed (ref result, visited);
|
|
} else if (RValue.PatternType == RelaxngPatternType.Empty) {
|
|
result = true;
|
|
return LValue.ReduceEmptyAndNotAllowed (ref result, visited);
|
|
} else {
|
|
LValue = LValue.ReduceEmptyAndNotAllowed (ref result, visited);
|
|
RValue = RValue.ReduceEmptyAndNotAllowed (ref result, visited);
|
|
return this;
|
|
}
|
|
}
|
|
|
|
internal override void MarkReachableDefs ()
|
|
{
|
|
l.MarkReachableDefs ();
|
|
r.MarkReachableDefs ();
|
|
}
|
|
|
|
internal override bool ContainsText()
|
|
{
|
|
return l.ContainsText () || r.ContainsText ();
|
|
}
|
|
|
|
// 7.3 (group/interleave attribute names) and
|
|
// part of 7.4 (interleave element names)
|
|
// FIXME: Actually it should be done against the correct
|
|
// simplified grammar, expanding all refs.
|
|
internal void CheckNameOverlap (bool checkElements)
|
|
{
|
|
if (RdpUtil.NamesOverlap (LValue, RValue, checkElements))
|
|
throw new RelaxngException ("Duplicate attributes inside a group or an interleave is not allowed.");
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Choice
|
|
public class RdpChoice : RdpAbstractBinary
|
|
{
|
|
public RdpChoice (RdpPattern l, RdpPattern r) : base (l, r)
|
|
{
|
|
}
|
|
|
|
public override bool Nullable {
|
|
get {
|
|
if (!nullableComputed) {
|
|
isNullable =
|
|
LValue.Nullable || RValue.Nullable;
|
|
nullableComputed = true;
|
|
}
|
|
return isNullable;
|
|
}
|
|
}
|
|
|
|
bool isTextValueDependentComputed;
|
|
bool isTextValueDependent;
|
|
|
|
internal override bool IsTextValueDependent {
|
|
get {
|
|
if (!isTextValueDependentComputed) {
|
|
isTextValueDependent = LValue.IsTextValueDependent || RValue.IsTextValueDependent;
|
|
isTextValueDependentComputed = true;
|
|
}
|
|
return isTextValueDependent;
|
|
}
|
|
}
|
|
|
|
bool isContextDependentComputed;
|
|
bool isContextDependent;
|
|
|
|
internal override bool IsContextDependent {
|
|
get {
|
|
if (!isContextDependentComputed) {
|
|
isContextDependent = LValue.IsContextDependent || RValue.IsContextDependent;
|
|
isContextDependentComputed = true;
|
|
}
|
|
return isContextDependent;
|
|
}
|
|
}
|
|
|
|
public override RelaxngPatternType PatternType {
|
|
get { return RelaxngPatternType.Choice; }
|
|
}
|
|
|
|
RdpContentType computedContentType = RdpContentType.Invalid;
|
|
public override RdpContentType ContentType {
|
|
get {
|
|
if (computedContentType == RdpContentType.Invalid) {
|
|
if (LValue.ContentType == RdpContentType.Simple ||
|
|
RValue.ContentType == RdpContentType.Simple)
|
|
computedContentType = RdpContentType.Simple;
|
|
else
|
|
computedContentType = base.ContentType;
|
|
}
|
|
return computedContentType;
|
|
}
|
|
}
|
|
|
|
public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
|
|
{
|
|
LValue.GetLabels (elements, attributes, collectNameClass);
|
|
RValue.GetLabels (elements, attributes, collectNameClass);
|
|
}
|
|
|
|
|
|
internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)
|
|
{
|
|
if (visited.Contains (this))
|
|
return this;
|
|
visited.Add (this, this);
|
|
|
|
if (LValue.PatternType == RelaxngPatternType.NotAllowed &&
|
|
RValue.PatternType == RelaxngPatternType.NotAllowed) {
|
|
result = true;
|
|
return RdpNotAllowed.Instance;
|
|
} else if (LValue.PatternType == RelaxngPatternType.NotAllowed) {
|
|
result = true;
|
|
return RValue.ReduceEmptyAndNotAllowed (ref result, visited);
|
|
} else if (RValue.PatternType == RelaxngPatternType.NotAllowed) {
|
|
result = true;
|
|
return LValue.ReduceEmptyAndNotAllowed (ref result, visited);
|
|
} else if (LValue.PatternType == RelaxngPatternType.Empty &&
|
|
RValue.PatternType == RelaxngPatternType.Empty) {
|
|
result = true;
|
|
return RdpEmpty.Instance;
|
|
} else if (RValue.PatternType == RelaxngPatternType.Empty) {
|
|
result = true;
|
|
RValue = LValue.ReduceEmptyAndNotAllowed (ref result, visited);
|
|
LValue = RdpEmpty.Instance;
|
|
return this;
|
|
} else {
|
|
LValue = LValue.ReduceEmptyAndNotAllowed (ref result, visited);
|
|
RValue = RValue.ReduceEmptyAndNotAllowed (ref result, visited);
|
|
return this;
|
|
}
|
|
}
|
|
|
|
public override RdpPattern TextDeriv (string s, XmlReader reader)
|
|
{
|
|
return LValue.TextDeriv (s, reader).Choice (RValue.TextDeriv (s, reader));
|
|
}
|
|
|
|
internal override RdpPattern TextDeriv (string s, XmlReader reader, MemoizationStore memo)
|
|
{
|
|
return memo.TextDeriv (LValue, s, reader).Choice (memo.TextDeriv (RValue, s, reader));
|
|
}
|
|
|
|
internal override RdpPattern EmptyTextDeriv (MemoizationStore memo)
|
|
{
|
|
return memo.EmptyTextDeriv (LValue)
|
|
.Choice (memo.EmptyTextDeriv (RValue));
|
|
}
|
|
|
|
internal override RdpPattern TextOnlyDeriv ()
|
|
{
|
|
return LValue.TextOnlyDeriv ().Choice (
|
|
RValue.TextOnlyDeriv ());
|
|
}
|
|
|
|
internal override RdpPattern TextOnlyDeriv (MemoizationStore memo)
|
|
{
|
|
return memo.TextOnlyDeriv (LValue).Choice (
|
|
memo.TextOnlyDeriv (RValue));
|
|
}
|
|
|
|
internal override RdpPattern MixedTextDeriv ()
|
|
{
|
|
return LValue.MixedTextDeriv ().Choice (
|
|
RValue.MixedTextDeriv ());
|
|
}
|
|
|
|
internal override RdpPattern MixedTextDeriv (MemoizationStore memo)
|
|
{
|
|
return memo.MixedTextDeriv (LValue).Choice (
|
|
memo.MixedTextDeriv (RValue));
|
|
}
|
|
|
|
public override RdpPattern ApplyAfter (RdpApplyAfterHandler handler)
|
|
{
|
|
// return handler (LValue).Choice (handler (RValue));
|
|
return LValue.ApplyAfter (handler).Choice (RValue.ApplyAfter (handler));
|
|
}
|
|
|
|
public override RdpPattern StartTagOpenDeriv (string name, string ns)
|
|
{
|
|
#if UseStatic
|
|
return RdpUtil.Choice (
|
|
RdpUtil.StartTagOpenDeriv (LValue, qname),
|
|
RdpUtil.StartTagOpenDeriv (RValue, qname));
|
|
#else
|
|
RdpPattern lDeriv = LValue.StartTagOpenDeriv (name, ns);
|
|
return lDeriv.Choice (RValue.StartTagOpenDeriv (name, ns));
|
|
#endif
|
|
}
|
|
|
|
internal override RdpPattern StartTagOpenDeriv (string name, string ns, MemoizationStore memo)
|
|
{
|
|
RdpPattern lDeriv = memo.StartTagOpenDeriv (LValue, name, ns);
|
|
return lDeriv.Choice (memo.StartTagOpenDeriv (RValue, name, ns));
|
|
}
|
|
|
|
// attDeriv cx (Choice p1 p2) att =
|
|
// choice (attDeriv cx p1 att) (attDeriv cx p2 att)
|
|
public override RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)
|
|
{
|
|
return LValue.AttDeriv (name, ns, value, reader)
|
|
.Choice (RValue.AttDeriv (name, ns, value, reader));
|
|
}
|
|
|
|
public override RdpPattern StartAttDeriv (string name, string ns)
|
|
{
|
|
RdpPattern lDeriv = LValue.StartAttDeriv (name, ns);
|
|
return lDeriv.Choice (RValue.StartAttDeriv (name, ns));
|
|
}
|
|
|
|
internal override RdpPattern StartAttDeriv (string name, string ns, MemoizationStore memo)
|
|
{
|
|
return memo.StartAttDeriv (LValue, name, ns)
|
|
.Choice (memo.StartAttDeriv (RValue, name, ns));
|
|
}
|
|
|
|
public override RdpPattern EndAttDeriv ()
|
|
{
|
|
return LValue.EndAttDeriv ().Choice (RValue.EndAttDeriv ());
|
|
}
|
|
|
|
internal override RdpPattern EndAttDeriv (MemoizationStore memo)
|
|
{
|
|
return memo.EndAttDeriv (LValue).Choice (memo.EndAttDeriv (RValue));
|
|
}
|
|
|
|
// startTagCloseDeriv (Choice p1 p2) =
|
|
// choice (startTagCloseDeriv p1) (startTagCloseDeriv p2)
|
|
public override RdpPattern StartTagCloseDeriv ()
|
|
{
|
|
return LValue.StartTagCloseDeriv ()
|
|
.Choice (RValue.StartTagCloseDeriv ());
|
|
}
|
|
|
|
internal override RdpPattern StartTagCloseDeriv (MemoizationStore memo)
|
|
{
|
|
return memo.StartTagCloseDeriv (LValue)
|
|
.Choice (memo.StartTagCloseDeriv (RValue));
|
|
}
|
|
|
|
public override RdpPattern EndTagDeriv ()
|
|
{
|
|
return LValue.EndTagDeriv ().Choice (RValue.EndTagDeriv ());
|
|
}
|
|
|
|
internal override RdpPattern EndTagDeriv (MemoizationStore memo)
|
|
{
|
|
return memo.EndTagDeriv (LValue).Choice (memo.EndTagDeriv (RValue));
|
|
}
|
|
|
|
internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
|
|
{
|
|
LValue.CheckConstraints (attribute, oneOrMore, oneOrMoreGroup, oneOrMoreInterleave, list, dataExcept);
|
|
RValue.CheckConstraints (attribute, oneOrMore, oneOrMoreGroup, oneOrMoreInterleave, list, dataExcept);
|
|
}
|
|
}
|
|
|
|
// Interleave
|
|
public class RdpInterleave : RdpAbstractBinary
|
|
{
|
|
public RdpInterleave (RdpPattern l, RdpPattern r) : base (l, r)
|
|
{
|
|
}
|
|
|
|
public override bool Nullable {
|
|
get {
|
|
if (!nullableComputed) {
|
|
isNullable =
|
|
LValue.Nullable && RValue.Nullable;
|
|
nullableComputed = true;
|
|
}
|
|
return isNullable;
|
|
}
|
|
}
|
|
|
|
internal override bool IsTextValueDependent {
|
|
get { return LValue.IsTextValueDependent || RValue.IsTextValueDependent; }
|
|
}
|
|
|
|
internal override bool IsContextDependent {
|
|
get { return LValue.IsContextDependent || RValue.IsContextDependent; }
|
|
}
|
|
|
|
public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
|
|
{
|
|
LValue.GetLabels (elements, attributes, collectNameClass);
|
|
RValue.GetLabels (elements, attributes, collectNameClass);
|
|
}
|
|
|
|
internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)
|
|
{
|
|
if (visited.Contains (this))
|
|
return this;
|
|
visited.Add (this, this);
|
|
|
|
if (LValue.PatternType == RelaxngPatternType.NotAllowed ||
|
|
RValue.PatternType == RelaxngPatternType.NotAllowed) {
|
|
result = true;
|
|
return RdpNotAllowed.Instance;
|
|
} else {
|
|
LValue = LValue.ReduceEmptyAndNotAllowed (ref result, visited);
|
|
RValue = RValue.ReduceEmptyAndNotAllowed (ref result, visited);
|
|
return this;
|
|
}
|
|
}
|
|
|
|
public override RdpPattern TextDeriv (string s, XmlReader reader)
|
|
{
|
|
return LValue.TextDeriv (s, reader).Interleave (RValue)
|
|
.Choice (LValue.Interleave (RValue.TextDeriv (s, reader)));
|
|
}
|
|
|
|
internal override RdpPattern TextDeriv (string s, XmlReader reader, MemoizationStore memo)
|
|
{
|
|
return memo.TextDeriv (LValue, s, reader).Interleave (RValue)
|
|
.Choice (LValue.Interleave (memo.TextDeriv (RValue, s, reader)));
|
|
}
|
|
|
|
internal override RdpPattern EmptyTextDeriv (MemoizationStore memo)
|
|
{
|
|
return memo.EmptyTextDeriv (LValue).Interleave (RValue)
|
|
.Choice (LValue.Interleave (memo.EmptyTextDeriv (RValue)));
|
|
}
|
|
|
|
internal override RdpPattern TextOnlyDeriv ()
|
|
{
|
|
return LValue.TextOnlyDeriv ().Interleave (
|
|
RValue.TextOnlyDeriv ());
|
|
}
|
|
|
|
internal override RdpPattern TextOnlyDeriv (MemoizationStore memo)
|
|
{
|
|
return memo.TextOnlyDeriv (LValue).Interleave (
|
|
memo.TextOnlyDeriv (RValue));
|
|
}
|
|
|
|
internal override RdpPattern MixedTextDeriv ()
|
|
{
|
|
return LValue.MixedTextDeriv ().Interleave (RValue).Choice (
|
|
LValue.Interleave (RValue.MixedTextDeriv ()));
|
|
}
|
|
|
|
internal override RdpPattern MixedTextDeriv (MemoizationStore memo)
|
|
{
|
|
return memo.MixedTextDeriv (LValue).Interleave (RValue).Choice (
|
|
LValue.Interleave (memo.MixedTextDeriv (RValue)));
|
|
}
|
|
|
|
// => choice (applyAfter (flip interleave p2) (startTagOpenDeriv p1 qn)) (applyAfter (interleave p1) (startTagOpenDeriv p2 qn)
|
|
// => p1.startTagOpenDeriv(qn).applyAfter (flip interleave p2).choice (p2.startTagOpenDeriv(qn).applyAfter (interleave p1) )
|
|
public override RdpPattern StartTagOpenDeriv (string name, string ns)
|
|
{
|
|
RdpPattern handledL = LValue.StartTagOpenDeriv (name, ns);
|
|
RdpPattern handledR = RValue.StartTagOpenDeriv (name, ns);
|
|
RdpFlip flipL = MakeFlip (RdpUtil.InterleaveFunction, RValue);
|
|
RdpPattern choiceL = handledL.ApplyAfter (new RdpApplyAfterHandler (flipL.Apply));
|
|
RdpPattern choiceR = handledR.ApplyAfter (new RdpApplyAfterHandler (LValue.Interleave));
|
|
return choiceL.Choice (choiceR);
|
|
}
|
|
|
|
internal override RdpPattern StartTagOpenDeriv (string name, string ns, MemoizationStore memo)
|
|
{
|
|
RdpPattern handledL = memo.StartTagOpenDeriv (LValue, name, ns);
|
|
RdpPattern handledR = memo.StartTagOpenDeriv (RValue, name, ns);
|
|
RdpFlip flipL = MakeFlip (RdpUtil.InterleaveFunction, RValue);
|
|
RdpPattern choiceL = handledL.ApplyAfter (new RdpApplyAfterHandler (flipL.Apply));
|
|
RdpPattern choiceR = handledR.ApplyAfter (new RdpApplyAfterHandler (LValue.Interleave));
|
|
return choiceL.Choice (choiceR);
|
|
}
|
|
|
|
// attDeriv cx (Interleave p1 p2) att =
|
|
// choice (interleave (attDeriv cx p1 att) p2)
|
|
// (interleave p1 (attDeriv cx p2 att))
|
|
public override RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)
|
|
{
|
|
return LValue.AttDeriv (name, ns, value, reader)
|
|
.Interleave (RValue)
|
|
.Choice (LValue.Interleave (
|
|
RValue.AttDeriv (name, ns, value, reader)));
|
|
}
|
|
|
|
public override RdpPattern StartAttDeriv (string name, string ns)
|
|
{
|
|
RdpPattern handledL = LValue.StartAttDeriv (name, ns);
|
|
RdpPattern handledR = RValue.StartAttDeriv (name, ns);
|
|
RdpFlip flipL = MakeFlip (RdpUtil.InterleaveFunction, RValue);
|
|
RdpPattern choiceL = handledL.ApplyAfter (new RdpApplyAfterHandler (flipL.Apply));
|
|
RdpPattern choiceR = handledR.ApplyAfter (new RdpApplyAfterHandler (LValue.Interleave));
|
|
return choiceL.Choice (choiceR);
|
|
}
|
|
|
|
internal override RdpPattern StartAttDeriv (string name, string ns, MemoizationStore memo)
|
|
{
|
|
RdpPattern handledL = memo.StartAttDeriv (LValue, name, ns);
|
|
RdpPattern handledR = memo.StartAttDeriv (RValue, name, ns);
|
|
RdpFlip flipL = MakeFlip (RdpUtil.InterleaveFunction, RValue);
|
|
RdpPattern choiceL = handledL.ApplyAfter (new RdpApplyAfterHandler (flipL.Apply));
|
|
RdpPattern choiceR = handledR.ApplyAfter (new RdpApplyAfterHandler (LValue.Interleave));
|
|
return choiceL.Choice (choiceR);
|
|
}
|
|
|
|
// startTagCloseDeriv (Interleave p1 p2) =
|
|
// interleave (startTagCloseDeriv p1) (startTagCloseDeriv p2)
|
|
public override RdpPattern StartTagCloseDeriv ()
|
|
{
|
|
return LValue.StartTagCloseDeriv ()
|
|
.Interleave (RValue.StartTagCloseDeriv ());
|
|
}
|
|
|
|
internal override RdpPattern StartTagCloseDeriv (MemoizationStore memo)
|
|
{
|
|
return memo.StartTagCloseDeriv (LValue)
|
|
.Interleave (memo.StartTagCloseDeriv (RValue));
|
|
}
|
|
|
|
public override RelaxngPatternType PatternType {
|
|
get { return RelaxngPatternType.Interleave; }
|
|
}
|
|
|
|
internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
|
|
{
|
|
if (list)
|
|
throw new RelaxngException ("interleave is not allowed under a list.");
|
|
if (dataExcept)
|
|
throw new RelaxngException ("interleave is not allowed under except of a data.");
|
|
|
|
// 7.1
|
|
LValue.CheckConstraints (attribute, oneOrMore, oneOrMoreGroup, oneOrMore, list, dataExcept);
|
|
RValue.CheckConstraints (attribute, oneOrMore, oneOrMoreGroup, oneOrMore, list, dataExcept);
|
|
|
|
// unique name analysis - 7.3 and part of 7.4
|
|
CheckNameOverlap (true);
|
|
|
|
// (2) text/text prohibited
|
|
if (LValue.ContainsText () && RValue.ContainsText ())
|
|
throw new RelaxngException ("Both branches of the interleave contains a text pattern.");
|
|
}
|
|
}
|
|
|
|
// Group
|
|
public class RdpGroup : RdpAbstractBinary
|
|
{
|
|
public RdpGroup (RdpPattern l, RdpPattern r) : base (l, r)
|
|
{
|
|
}
|
|
|
|
public override bool Nullable {
|
|
get {
|
|
if (!nullableComputed) {
|
|
isNullable =
|
|
LValue.Nullable && RValue.Nullable;
|
|
nullableComputed = true;
|
|
}
|
|
return isNullable;
|
|
}
|
|
}
|
|
|
|
internal override bool IsTextValueDependent {
|
|
get { return LValue.IsTextValueDependent || (LValue.Nullable ? RValue.IsTextValueDependent : false); }
|
|
}
|
|
|
|
internal override bool IsContextDependent {
|
|
get { return LValue.IsContextDependent || (LValue.Nullable ? RValue.IsContextDependent : false); }
|
|
}
|
|
|
|
public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
|
|
{
|
|
LValue.GetLabels (elements, attributes, collectNameClass);
|
|
if (LValue.Nullable)
|
|
RValue.GetLabels (elements, attributes, collectNameClass);
|
|
else
|
|
RValue.GetLabels (null, attributes, collectNameClass);
|
|
}
|
|
|
|
public override RdpPattern TextDeriv (string s, XmlReader reader)
|
|
{
|
|
RdpPattern p = LValue.TextDeriv (s, reader);
|
|
p = (p.PatternType == RelaxngPatternType.NotAllowed) ?
|
|
p : p.Group (RValue);
|
|
return LValue.Nullable ?
|
|
p.Choice (RValue.TextDeriv (s, reader)) : p;
|
|
}
|
|
|
|
internal override RdpPattern TextDeriv (string s, XmlReader reader, MemoizationStore memo)
|
|
{
|
|
RdpPattern p = memo.TextDeriv (LValue, s, reader);
|
|
p = (p.PatternType == RelaxngPatternType.NotAllowed) ?
|
|
p : p.Group (RValue);
|
|
return LValue.Nullable ?
|
|
p.Choice (memo.TextDeriv (RValue, s, reader)) : p;
|
|
}
|
|
|
|
internal override RdpPattern EmptyTextDeriv (MemoizationStore memo)
|
|
{
|
|
RdpPattern p = memo.EmptyTextDeriv (LValue);
|
|
p = p.PatternType == RelaxngPatternType.NotAllowed ?
|
|
p : p.Group (RValue);
|
|
return LValue.Nullable ?
|
|
p.Choice (memo.EmptyTextDeriv (RValue)) : p;
|
|
}
|
|
|
|
internal override RdpPattern TextOnlyDeriv ()
|
|
{
|
|
RdpPattern p = LValue.TextOnlyDeriv ();
|
|
return p.PatternType == RelaxngPatternType.NotAllowed ?
|
|
p : p.Group (RValue.TextOnlyDeriv ());
|
|
}
|
|
|
|
internal override RdpPattern TextOnlyDeriv (MemoizationStore memo)
|
|
{
|
|
RdpPattern p = memo.TextOnlyDeriv (LValue);
|
|
return p.PatternType == RelaxngPatternType.NotAllowed ?
|
|
p : p.Group (memo.TextOnlyDeriv (RValue));
|
|
}
|
|
|
|
internal override RdpPattern MixedTextDeriv ()
|
|
{
|
|
RdpPattern p = LValue.MixedTextDeriv ().Group (RValue);
|
|
return LValue.Nullable ?
|
|
p.Choice (RValue.MixedTextDeriv ()) : p;
|
|
}
|
|
|
|
internal override RdpPattern MixedTextDeriv (MemoizationStore memo)
|
|
{
|
|
RdpPattern p = memo.MixedTextDeriv (LValue).Group (RValue);
|
|
return LValue.Nullable ?
|
|
p.Choice (memo.MixedTextDeriv (RValue)) : p;
|
|
}
|
|
|
|
// startTagOpenDeriv (Group p1 p2) qn =
|
|
// let x = applyAfter (flip group p2) (startTagOpenDeriv p1 qn)
|
|
// in if nullable p1 then
|
|
// choice x (startTagOpenDeriv p2 qn)
|
|
// else
|
|
// x
|
|
public override RdpPattern StartTagOpenDeriv (string name, string ns)
|
|
{
|
|
RdpPattern handled = LValue.StartTagOpenDeriv (name, ns);
|
|
RdpFlip f = MakeFlip (RdpUtil.GroupFunction, RValue);
|
|
RdpPattern x = handled.ApplyAfter (new RdpApplyAfterHandler (f.Apply));
|
|
if (LValue.Nullable)
|
|
return x.Choice (RValue.StartTagOpenDeriv (name, ns));
|
|
else
|
|
return x;
|
|
}
|
|
|
|
internal override RdpPattern StartTagOpenDeriv (string name, string ns, MemoizationStore memo)
|
|
{
|
|
RdpPattern handled = memo.StartTagOpenDeriv (LValue, name, ns);
|
|
RdpFlip f = MakeFlip (RdpUtil.GroupFunction, RValue);
|
|
RdpPattern x = handled.ApplyAfter (new RdpApplyAfterHandler (f.Apply));
|
|
if (LValue.Nullable)
|
|
return x.Choice (memo.StartTagOpenDeriv (RValue, name, ns));
|
|
else
|
|
return x;
|
|
}
|
|
|
|
// attDeriv cx (Group p1 p2) att =
|
|
// choice (group (attDeriv cx p1 att) p2)
|
|
// (group p1 (attDeriv cx p2 att))
|
|
public override RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)
|
|
{
|
|
return LValue.AttDeriv (name, ns, value, reader).Group (RValue)
|
|
.Choice (LValue.Group (
|
|
RValue.AttDeriv (name, ns, value, reader)));
|
|
}
|
|
|
|
// startAttDeriv (group p1 p2) == startAttDeriv (interleave p1 p2)
|
|
public override RdpPattern StartAttDeriv (string name, string ns)
|
|
{
|
|
RdpPattern handledL = LValue.StartAttDeriv (name, ns);
|
|
RdpPattern handledR = RValue.StartAttDeriv (name, ns);
|
|
RdpFlip flipL = MakeFlip (RdpUtil.GroupFunction, RValue);
|
|
RdpPattern choiceL = handledL.ApplyAfter (new RdpApplyAfterHandler (flipL.Apply));
|
|
RdpPattern choiceR = handledR.ApplyAfter (new RdpApplyAfterHandler (LValue.Group));
|
|
return choiceL.Choice (choiceR);
|
|
}
|
|
|
|
internal override RdpPattern StartAttDeriv (string name, string ns, MemoizationStore memo)
|
|
{
|
|
RdpPattern handledL = memo.StartAttDeriv (LValue, name, ns);
|
|
RdpPattern handledR = memo.StartAttDeriv (RValue, name, ns);
|
|
RdpFlip flipL = MakeFlip (RdpUtil.GroupFunction, RValue);
|
|
RdpPattern choiceL = handledL.ApplyAfter (new RdpApplyAfterHandler (flipL.Apply));
|
|
RdpPattern choiceR = handledR.ApplyAfter (new RdpApplyAfterHandler (LValue.Group));
|
|
return choiceL.Choice (choiceR);
|
|
}
|
|
|
|
// startTagCloseDeriv (Group p1 p2) =
|
|
// group (startTagCloseDeriv p1) (startTagCloseDeriv p2)
|
|
public override RdpPattern StartTagCloseDeriv ()
|
|
{
|
|
RdpPattern p = LValue.StartTagCloseDeriv ();
|
|
return p.PatternType == RelaxngPatternType.NotAllowed ?
|
|
p : p.Group (RValue.StartTagCloseDeriv ());
|
|
}
|
|
|
|
internal override RdpPattern StartTagCloseDeriv (MemoizationStore memo)
|
|
{
|
|
RdpPattern p = memo.StartTagCloseDeriv (LValue);
|
|
return p.PatternType == RelaxngPatternType.NotAllowed ?
|
|
p : p.Group (memo.StartTagCloseDeriv (RValue));
|
|
}
|
|
|
|
public override RelaxngPatternType PatternType {
|
|
get { return RelaxngPatternType.Group; }
|
|
}
|
|
|
|
internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
|
|
{
|
|
if (dataExcept)
|
|
throw new RelaxngException ("interleave is not allowed under except of a data.");
|
|
|
|
LValue.CheckConstraints (attribute, oneOrMore, oneOrMore, oneOrMoreInterleave, list, dataExcept);
|
|
RValue.CheckConstraints (attribute, oneOrMore, oneOrMore, oneOrMoreInterleave, list, dataExcept);
|
|
|
|
// 7.3
|
|
CheckNameOverlap (false);
|
|
}
|
|
}
|
|
|
|
public abstract class RdpAbstractSingleContent : RdpPattern
|
|
{
|
|
RdpPattern child;
|
|
bool isExpanded;
|
|
|
|
internal override RdpPattern ExpandRef (Hashtable defs)
|
|
{
|
|
if (!isExpanded)
|
|
child = child.ExpandRef (defs);
|
|
return this;
|
|
}
|
|
|
|
public RdpAbstractSingleContent (RdpPattern p)
|
|
{
|
|
this.child = p;
|
|
}
|
|
|
|
public RdpPattern Child {
|
|
get { return child; }
|
|
set { child = value; }
|
|
}
|
|
|
|
internal override void MarkReachableDefs ()
|
|
{
|
|
child.MarkReachableDefs ();
|
|
}
|
|
|
|
internal override bool ContainsText()
|
|
{
|
|
return child.ContainsText ();
|
|
}
|
|
}
|
|
|
|
// OneOrMore
|
|
public class RdpOneOrMore : RdpAbstractSingleContent
|
|
{
|
|
public RdpOneOrMore (RdpPattern p) : base (p)
|
|
{
|
|
}
|
|
|
|
public override RelaxngPatternType PatternType {
|
|
get { return RelaxngPatternType.OneOrMore; }
|
|
}
|
|
|
|
public override RdpContentType ContentType {
|
|
get {
|
|
if (Child.ContentType == RdpContentType.Simple)
|
|
throw new RelaxngException ("Invalid content type was found.");
|
|
return Child.ContentType;
|
|
}
|
|
}
|
|
|
|
public override bool Nullable {
|
|
get { return Child.Nullable; }
|
|
}
|
|
|
|
internal override bool IsTextValueDependent {
|
|
get { return Child.IsTextValueDependent; }
|
|
}
|
|
|
|
internal override bool IsContextDependent {
|
|
get { return Child.IsContextDependent; }
|
|
}
|
|
|
|
public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
|
|
{
|
|
Child.GetLabels (elements, attributes, collectNameClass);
|
|
}
|
|
|
|
internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)
|
|
{
|
|
if (visited.Contains (this))
|
|
return this;
|
|
visited.Add (this, this);
|
|
|
|
if (Child.PatternType == RelaxngPatternType.NotAllowed) {
|
|
result = true;
|
|
return RdpNotAllowed.Instance;
|
|
} else if (Child.PatternType == RelaxngPatternType.Empty)
|
|
return RdpEmpty.Instance;
|
|
else {
|
|
Child = Child.ReduceEmptyAndNotAllowed (ref result, visited);
|
|
return this;
|
|
}
|
|
}
|
|
|
|
public override RdpPattern TextDeriv (string s, XmlReader reader)
|
|
{
|
|
RdpPattern p = Child.TextDeriv (s, reader);
|
|
return p.PatternType == RelaxngPatternType.NotAllowed ?
|
|
p : p.Group (this.Choice (RdpEmpty.Instance));
|
|
}
|
|
|
|
internal override RdpPattern TextDeriv (string s, XmlReader reader, MemoizationStore memo)
|
|
{
|
|
RdpPattern p = memo.TextDeriv (Child, s, reader);
|
|
return p.PatternType == RelaxngPatternType.NotAllowed ?
|
|
p : p.Group (this.Choice (RdpEmpty.Instance));
|
|
}
|
|
|
|
internal override RdpPattern EmptyTextDeriv (MemoizationStore memo)
|
|
{
|
|
RdpPattern p = memo.EmptyTextDeriv (Child);
|
|
return p.PatternType == RelaxngPatternType.NotAllowed ?
|
|
p : p.Group (this.Choice (RdpEmpty.Instance));
|
|
}
|
|
|
|
internal override RdpPattern TextOnlyDeriv ()
|
|
{
|
|
return Child.TextOnlyDeriv ().OneOrMore ();
|
|
}
|
|
|
|
internal override RdpPattern TextOnlyDeriv (MemoizationStore memo)
|
|
{
|
|
return memo.TextOnlyDeriv (Child).OneOrMore ();
|
|
}
|
|
|
|
internal override RdpPattern MixedTextDeriv ()
|
|
{
|
|
RdpPattern p = Child.MixedTextDeriv ();
|
|
return p.PatternType == RelaxngPatternType.NotAllowed ?
|
|
p : p.Group (this.Choice (RdpEmpty.Instance));
|
|
}
|
|
|
|
internal override RdpPattern MixedTextDeriv (MemoizationStore memo)
|
|
{
|
|
RdpPattern p = memo.MixedTextDeriv (Child);
|
|
return p.PatternType == RelaxngPatternType.NotAllowed ?
|
|
p : p.Group (this.Choice (RdpEmpty.Instance));
|
|
}
|
|
|
|
// attDeriv cx (OneOrMore p) att =
|
|
// group (attDeriv cx p att) (choice (OneOrMore p) Empty)
|
|
public override RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)
|
|
{
|
|
RdpPattern p = Child.AttDeriv (name, ns, value, reader);
|
|
return p.PatternType == RelaxngPatternType.NotAllowed ?
|
|
p : p.Group (Choice (RdpEmpty.Instance));
|
|
}
|
|
|
|
// startTagOpenDeriv (OneOrMore p) qn =
|
|
// applyAfter (flip group (choice (OneOrMore p) Empty))
|
|
// (startTagOpenDeriv p qn)
|
|
public override RdpPattern StartTagOpenDeriv (string name, string ns)
|
|
{
|
|
RdpPattern rest = RdpEmpty.Instance.Choice (Child.OneOrMore ());
|
|
RdpPattern handled = Child.StartTagOpenDeriv (name, ns);
|
|
RdpFlip f = MakeFlip (RdpUtil.GroupFunction, rest);
|
|
return handled.ApplyAfter (new RdpApplyAfterHandler (f.Apply));
|
|
}
|
|
|
|
internal override RdpPattern StartTagOpenDeriv (string name, string ns, MemoizationStore memo)
|
|
{
|
|
RdpPattern rest = RdpEmpty.Instance.Choice (Child.OneOrMore ());
|
|
RdpPattern handled = memo.StartTagOpenDeriv (Child, name, ns);
|
|
RdpFlip f = MakeFlip (RdpUtil.GroupFunction, rest);
|
|
return handled.ApplyAfter (new RdpApplyAfterHandler (f.Apply));
|
|
}
|
|
|
|
public override RdpPattern StartAttDeriv (string name, string ns)
|
|
{
|
|
RdpPattern rest = RdpEmpty.Instance.Choice (Child.OneOrMore ());
|
|
RdpPattern handled = Child.StartAttDeriv (name, ns);
|
|
RdpFlip f = MakeFlip (RdpUtil.GroupFunction, rest);
|
|
return handled.ApplyAfter (new RdpApplyAfterHandler (f.Apply));
|
|
}
|
|
|
|
internal override RdpPattern StartAttDeriv (string name, string ns, MemoizationStore memo)
|
|
{
|
|
RdpPattern rest = RdpEmpty.Instance.Choice (Child.OneOrMore ());
|
|
RdpPattern handled = memo.StartAttDeriv (Child, name, ns);
|
|
RdpFlip f = MakeFlip (RdpUtil.GroupFunction, rest);
|
|
return handled.ApplyAfter (new RdpApplyAfterHandler (f.Apply));
|
|
}
|
|
|
|
// startTagCloseDeriv (OneOrMore p) =
|
|
// oneOrMore (startTagCloseDeriv p)
|
|
public override RdpPattern StartTagCloseDeriv ()
|
|
{
|
|
#if UseStatic
|
|
return RdpUtil.OneOrMore (
|
|
RdpUtil.StartTagCloseDeriv (children));
|
|
#else
|
|
return Child.StartTagCloseDeriv ().OneOrMore ();
|
|
#endif
|
|
}
|
|
|
|
internal override RdpPattern StartTagCloseDeriv (MemoizationStore memo)
|
|
{
|
|
return memo.StartTagCloseDeriv (Child).OneOrMore ();
|
|
}
|
|
|
|
internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
|
|
{
|
|
if (dataExcept)
|
|
throw new RelaxngException ("oneOrMore is not allowed under except of a data.");
|
|
this.Child.CheckConstraints (attribute, true, oneOrMoreGroup, oneOrMoreInterleave, list, dataExcept);
|
|
}
|
|
}
|
|
|
|
// List
|
|
public class RdpList : RdpAbstractSingleContent
|
|
{
|
|
public RdpList (RdpPattern p) : base (p)
|
|
{
|
|
}
|
|
|
|
internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)
|
|
{
|
|
if (visited.Contains (this))
|
|
return this;
|
|
visited.Add (this, this);
|
|
|
|
if (Child.PatternType == RelaxngPatternType.NotAllowed) {
|
|
result = true;
|
|
return RdpNotAllowed.Instance;
|
|
} else {
|
|
Child = Child.ReduceEmptyAndNotAllowed (ref result, visited);
|
|
return this;
|
|
}
|
|
}
|
|
|
|
public override bool Nullable {
|
|
get { return false; }
|
|
}
|
|
|
|
internal override bool IsTextValueDependent {
|
|
get { return true; }
|
|
}
|
|
|
|
internal override bool IsContextDependent {
|
|
get { return Child.IsContextDependent; }
|
|
}
|
|
|
|
public override RelaxngPatternType PatternType {
|
|
get { return RelaxngPatternType.List; }
|
|
}
|
|
|
|
public override RdpContentType ContentType {
|
|
get { return RdpContentType.Simple; }
|
|
}
|
|
|
|
public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
|
|
{
|
|
Child.GetLabels (elements, attributes, collectNameClass);
|
|
}
|
|
|
|
public override RdpPattern TextDeriv (string s, XmlReader reader)
|
|
{
|
|
s = Util.NormalizeWhitespace (s);
|
|
|
|
RdpPattern p = Child.ListDeriv (s.Split (RdpUtil.WhitespaceChars), 0, reader);
|
|
if (p.Nullable)
|
|
return RdpEmpty.Instance;
|
|
else
|
|
return RdpNotAllowed.Instance;
|
|
}
|
|
|
|
internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
|
|
{
|
|
if (list)
|
|
throw new RelaxngException ("list is not allowed uner another list.");
|
|
if (dataExcept)
|
|
throw new RelaxngException ("list is not allowed under except of a data.");
|
|
this.Child.CheckConstraints (attribute, oneOrMore, oneOrMoreGroup, oneOrMoreInterleave, true, dataExcept);
|
|
}
|
|
}
|
|
|
|
// Data
|
|
public class RdpData : RdpPattern
|
|
{
|
|
public RdpData (RdpDatatype dt)
|
|
{
|
|
this.dt = dt;
|
|
}
|
|
|
|
RdpDatatype dt;
|
|
public RdpDatatype Datatype {
|
|
get { return dt; }
|
|
}
|
|
|
|
public override bool Nullable {
|
|
get { return false; }
|
|
}
|
|
|
|
internal override bool IsTextValueDependent {
|
|
get { return true; }
|
|
}
|
|
|
|
internal override bool IsContextDependent {
|
|
get { return dt.IsContextDependent; }
|
|
}
|
|
|
|
public override RelaxngPatternType PatternType {
|
|
get { return RelaxngPatternType.Data; }
|
|
}
|
|
|
|
public override RdpContentType ContentType {
|
|
get { return RdpContentType.Simple; }
|
|
}
|
|
|
|
public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
|
|
{
|
|
// do nothing.
|
|
}
|
|
|
|
public override RdpPattern TextDeriv (string s, XmlReader reader)
|
|
{
|
|
if (dt.IsAllowed (s, reader))
|
|
return RdpEmpty.Instance;
|
|
else
|
|
return RdpNotAllowed.Instance;
|
|
}
|
|
|
|
internal override void MarkReachableDefs ()
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
internal override bool ContainsText()
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// DataExcept
|
|
public class RdpDataExcept : RdpData
|
|
{
|
|
public RdpDataExcept (RdpDatatype dt, RdpPattern except)
|
|
: base (dt)
|
|
{
|
|
this.except = except;
|
|
}
|
|
|
|
RdpPattern except;
|
|
public RdpPattern Except {
|
|
get { return except; }
|
|
set { except = value; }
|
|
}
|
|
|
|
public override RelaxngPatternType PatternType {
|
|
get { return RelaxngPatternType.DataExcept; }
|
|
}
|
|
|
|
public override RdpContentType ContentType {
|
|
get {
|
|
RdpContentType c = except.ContentType; // conformance required for except pattern.
|
|
return RdpContentType.Simple;
|
|
}
|
|
}
|
|
|
|
internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)
|
|
{
|
|
if (visited.Contains (this))
|
|
return this;
|
|
visited.Add (this, this);
|
|
|
|
if (except.PatternType == RelaxngPatternType.NotAllowed) {
|
|
result = true;
|
|
return new RdpData (this.Datatype);
|
|
} else {
|
|
except = except.ReduceEmptyAndNotAllowed (ref result, visited);
|
|
return this;
|
|
}
|
|
}
|
|
|
|
public override RdpPattern TextDeriv (string s, XmlReader reader)
|
|
{
|
|
if (Datatype.IsAllowed (s, reader) && !except.TextDeriv (s, reader).Nullable)
|
|
return RdpEmpty.Instance;
|
|
else
|
|
return RdpNotAllowed.Instance;
|
|
}
|
|
|
|
internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
|
|
{
|
|
this.except.CheckConstraints (attribute, oneOrMore, oneOrMoreGroup, oneOrMoreInterleave, list, true);
|
|
}
|
|
|
|
internal override bool ContainsText()
|
|
{
|
|
return except.ContainsText ();
|
|
}
|
|
}
|
|
|
|
// Value
|
|
public class RdpValue : RdpPattern
|
|
{
|
|
public RdpValue (RdpDatatype dt, string value)
|
|
{
|
|
this.dt = dt;
|
|
this.value = value;
|
|
}
|
|
|
|
RdpDatatype dt;
|
|
public RdpDatatype Datatype {
|
|
get { return dt; }
|
|
}
|
|
|
|
string value;
|
|
public string Value {
|
|
get { return value; }
|
|
}
|
|
|
|
public override bool Nullable {
|
|
get { return false; }
|
|
}
|
|
|
|
internal override bool IsTextValueDependent {
|
|
get { return true; }
|
|
}
|
|
|
|
internal override bool IsContextDependent {
|
|
get { return dt.IsContextDependent; }
|
|
}
|
|
|
|
public override RelaxngPatternType PatternType {
|
|
get { return RelaxngPatternType.Value; }
|
|
}
|
|
|
|
public override RdpContentType ContentType {
|
|
get { return RdpContentType.Simple; }
|
|
}
|
|
|
|
public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
string cachedValue;
|
|
RdpPattern cachedPattern;
|
|
|
|
public override RdpPattern TextDeriv (string s, XmlReader reader)
|
|
{
|
|
if (s == cachedValue && !IsContextDependent)
|
|
return cachedPattern;
|
|
cachedPattern = TextDerivCore (s, reader);
|
|
cachedValue = s;
|
|
return cachedPattern;
|
|
}
|
|
|
|
RdpPattern TextDerivCore (string s, XmlReader reader)
|
|
{
|
|
if (dt.IsTypeEqual (value, s, reader))
|
|
return RdpEmpty.Instance;
|
|
else
|
|
return RdpNotAllowed.Instance;
|
|
}
|
|
|
|
internal override void MarkReachableDefs ()
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
|
|
{
|
|
// nothing to be checked
|
|
}
|
|
|
|
internal override bool ContainsText()
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Attribute
|
|
public class RdpAttribute : RdpPattern
|
|
{
|
|
public RdpAttribute (RdpNameClass nameClass, RdpPattern p)
|
|
{
|
|
this.nameClass = nameClass;
|
|
this.children = p;
|
|
}
|
|
|
|
RdpNameClass nameClass;
|
|
public RdpNameClass NameClass {
|
|
get { return nameClass; }
|
|
}
|
|
|
|
RdpPattern children;
|
|
public RdpPattern Children {
|
|
get { return children; }
|
|
set { children = value; }
|
|
}
|
|
|
|
public override bool Nullable {
|
|
get { return false; }
|
|
}
|
|
|
|
internal override bool IsTextValueDependent {
|
|
get { return false; }
|
|
}
|
|
|
|
internal override bool IsContextDependent {
|
|
get { return false; }
|
|
}
|
|
|
|
public override RelaxngPatternType PatternType {
|
|
get { return RelaxngPatternType.Attribute; }
|
|
}
|
|
|
|
public override RdpContentType ContentType {
|
|
get { return RdpContentType.Empty; }
|
|
}
|
|
|
|
public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
|
|
{
|
|
if (attributes != null) {
|
|
if (collectNameClass)
|
|
attributes [NameClass] = NameClass;
|
|
else
|
|
AddNameLabel (attributes, NameClass);
|
|
}
|
|
}
|
|
|
|
bool isExpanded;
|
|
internal override RdpPattern ExpandRef (Hashtable defs)
|
|
{
|
|
if (!isExpanded) {
|
|
isExpanded = true;
|
|
children = children.ExpandRef (defs);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)
|
|
{
|
|
if (visited.Contains (this))
|
|
return this;
|
|
visited.Add (this, this);
|
|
|
|
if (children.PatternType == RelaxngPatternType.NotAllowed) {
|
|
result = true;
|
|
return RdpNotAllowed.Instance;
|
|
} else {
|
|
children = children.ReduceEmptyAndNotAllowed (ref result, visited);
|
|
return this;
|
|
}
|
|
}
|
|
|
|
// attDeriv cx (Attribute nc p) (AttributeNode qn s) =
|
|
// if contains nc qn && valueMatch cx p s then Empty else NotAllowed
|
|
public override RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)
|
|
{
|
|
// If value is null, then does not check ValueMatch.
|
|
#if UseStatic
|
|
if (RdpUtil.Contains (this.nameClass, att.QName)
|
|
&& (value == null || RdpUtil.ValueMatch (ctx, this.children, att.Value)))
|
|
return RdpEmpty.Instance;
|
|
else
|
|
return RdpNotAllowed.Instance;
|
|
#else
|
|
if (nameClass.Contains (name, ns) &&
|
|
(value == null || children.ValueMatch (value, reader)))
|
|
return RdpEmpty.Instance;
|
|
else
|
|
return RdpNotAllowed.Instance;
|
|
#endif
|
|
}
|
|
|
|
public override RdpPattern StartAttDeriv (string name, string ns)
|
|
{
|
|
return nameClass.Contains (name, ns) ?
|
|
children.After (RdpEmpty.Instance) : RdpNotAllowed.Instance;
|
|
}
|
|
|
|
internal override RdpPattern StartAttDeriv (string name, string ns, MemoizationStore memo)
|
|
{
|
|
return nameClass.Contains (name, ns) ?
|
|
children.After (RdpEmpty.Instance) : RdpNotAllowed.Instance;
|
|
}
|
|
|
|
// startTagCloseDeriv (Attribute _ _) = NotAllowed
|
|
public override RdpPattern StartTagCloseDeriv ()
|
|
{
|
|
return RdpNotAllowed.Instance;
|
|
}
|
|
|
|
internal override RdpPattern StartTagCloseDeriv (MemoizationStore memo)
|
|
{
|
|
return RdpNotAllowed.Instance;
|
|
}
|
|
|
|
internal override void MarkReachableDefs ()
|
|
{
|
|
children.MarkReachableDefs ();
|
|
}
|
|
|
|
internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
|
|
{
|
|
// 7.1.1 and 7.1.2
|
|
if (attribute || oneOrMoreGroup || oneOrMoreInterleave || list || dataExcept)
|
|
throw new RelaxngException ("Not allowed attribute occurence was specified in the pattern.");
|
|
|
|
// latter part of 7.3
|
|
if (!oneOrMore && NameClass.HasInfiniteName)
|
|
throw new RelaxngException ("Attributes that has an infinite name class must be repeatable.");
|
|
|
|
this.Children.CheckConstraints (true, oneOrMore, false, false, false, false);
|
|
}
|
|
|
|
internal override bool ContainsText()
|
|
{
|
|
// This method is to detect text pattern inside interleave child.
|
|
// return children.ContainsText ();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Element
|
|
public class RdpElement : RdpPattern
|
|
{
|
|
public RdpElement (RdpNameClass nameClass, RdpPattern p)
|
|
{
|
|
this.nameClass = nameClass;
|
|
this.children = p;
|
|
}
|
|
|
|
RdpNameClass nameClass;
|
|
public RdpNameClass NameClass {
|
|
get { return nameClass; }
|
|
}
|
|
|
|
RdpPattern children;
|
|
public RdpPattern Children {
|
|
get { return children; }
|
|
set { children = value; }
|
|
}
|
|
|
|
public override bool Nullable {
|
|
get { return false; }
|
|
}
|
|
|
|
internal override bool IsTextValueDependent {
|
|
get { return false; }
|
|
}
|
|
|
|
internal override bool IsContextDependent {
|
|
get { return false; }
|
|
}
|
|
|
|
public override RelaxngPatternType PatternType {
|
|
get { return RelaxngPatternType.Element; }
|
|
}
|
|
|
|
bool contentTypeCheckDone;
|
|
public override RdpContentType ContentType {
|
|
get {
|
|
if (!contentTypeCheckDone) {
|
|
contentTypeCheckDone = true;
|
|
RdpContentType ct = children.ContentType; // conformance required.
|
|
}
|
|
return RdpContentType.Complex;
|
|
}
|
|
}
|
|
|
|
public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
|
|
{
|
|
if (elements != null) {
|
|
if (collectNameClass)
|
|
elements [NameClass] = NameClass;
|
|
else
|
|
AddNameLabel (elements, NameClass);
|
|
}
|
|
}
|
|
|
|
|
|
bool isExpanded;
|
|
short expanding; // FIXME: It is totally not required, but there is
|
|
// some bugs in simplification and without it it causes infinite loop.
|
|
internal override RdpPattern ExpandRef (Hashtable defs)
|
|
{
|
|
if (!isExpanded) {
|
|
isExpanded = true;
|
|
if (expanding == 100)
|
|
throw new RelaxngException (String.Format ("Invalid recursion was found. Name is {0}", nameClass));
|
|
expanding++;
|
|
children = children.ExpandRef (defs);
|
|
expanding--;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)
|
|
{
|
|
if (visited.Contains (this))
|
|
return this;
|
|
visited.Add (this, this);
|
|
|
|
children = children.ReduceEmptyAndNotAllowed (ref result, visited);
|
|
return this;
|
|
}
|
|
|
|
internal override RdpPattern TextOnlyDeriv ()
|
|
{
|
|
return RdpNotAllowed.Instance;
|
|
}
|
|
|
|
internal override RdpPattern TextOnlyDeriv (MemoizationStore memo)
|
|
{
|
|
return RdpNotAllowed.Instance;
|
|
}
|
|
|
|
public override RdpPattern StartTagOpenDeriv (string name, string ns)
|
|
{
|
|
#if UseStatic
|
|
if (RdpUtil.Contains (this.nameClass, qname))
|
|
return RdpUtil.After (this.Children, RdpEmpty.Instance);
|
|
else
|
|
return RdpNotAllowed.Instance;
|
|
#else
|
|
return nameClass.Contains (name, ns) ?
|
|
children.After (RdpEmpty.Instance) :
|
|
RdpNotAllowed.Instance;
|
|
#endif
|
|
}
|
|
|
|
internal override RdpPattern StartTagOpenDeriv (string name, string ns, MemoizationStore memo)
|
|
{
|
|
return nameClass.Contains (name, ns) ?
|
|
children.After (RdpEmpty.Instance) :
|
|
RdpNotAllowed.Instance;
|
|
}
|
|
|
|
internal override void MarkReachableDefs ()
|
|
{
|
|
children.MarkReachableDefs ();
|
|
}
|
|
|
|
bool constraintsChecked;
|
|
internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
|
|
{
|
|
if (constraintsChecked)
|
|
return;
|
|
constraintsChecked = true;
|
|
if (attribute || list || dataExcept)
|
|
throw new RelaxngException ("Not allowed element occurence was specified in the pattern.");
|
|
this.Children.CheckConstraints (false, false, false, oneOrMoreInterleave, false, false);
|
|
}
|
|
|
|
internal override bool ContainsText()
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// After
|
|
public class RdpAfter : RdpAbstractBinary
|
|
{
|
|
public RdpAfter (RdpPattern l, RdpPattern r) : base (l, r)
|
|
{
|
|
}
|
|
|
|
public override bool Nullable {
|
|
get { return false; }
|
|
}
|
|
|
|
internal override bool IsTextValueDependent {
|
|
get { return LValue.IsTextValueDependent; }
|
|
}
|
|
|
|
internal override bool IsContextDependent {
|
|
get { return LValue.IsContextDependent; }
|
|
}
|
|
|
|
public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
|
|
{
|
|
LValue.GetLabels (elements, attributes, collectNameClass);
|
|
}
|
|
|
|
public override RdpPattern TextDeriv (string s, XmlReader reader)
|
|
{
|
|
return LValue.TextDeriv (s, reader).After (RValue);
|
|
}
|
|
|
|
internal override RdpPattern TextDeriv (string s, XmlReader reader, MemoizationStore memo)
|
|
{
|
|
return memo.TextDeriv (LValue, s, reader).After (RValue);
|
|
}
|
|
|
|
internal override RdpPattern EmptyTextDeriv (MemoizationStore memo)
|
|
{
|
|
return memo.EmptyTextDeriv (LValue).After (RValue);
|
|
}
|
|
|
|
internal override RdpPattern TextOnlyDeriv ()
|
|
{
|
|
return LValue.TextOnlyDeriv ().After (RValue);
|
|
}
|
|
|
|
internal override RdpPattern TextOnlyDeriv (MemoizationStore memo)
|
|
{
|
|
return memo.TextOnlyDeriv (LValue).After (RValue);
|
|
}
|
|
|
|
internal override RdpPattern MixedTextDeriv ()
|
|
{
|
|
return LValue.MixedTextDeriv ().After (RValue);
|
|
}
|
|
|
|
internal override RdpPattern MixedTextDeriv (MemoizationStore memo)
|
|
{
|
|
return memo.MixedTextDeriv (LValue).After (RValue);
|
|
}
|
|
|
|
// startTagOpenDeriv (After p1 p2) qn =
|
|
// applyAfter (flip after p2) (startTagOpenDeriv p1 qn)
|
|
public override RdpPattern StartTagOpenDeriv (string name, string ns)
|
|
{
|
|
RdpPattern handled = LValue.StartTagOpenDeriv (name, ns);
|
|
RdpFlip f = MakeFlip (RdpUtil.AfterFunction, RValue);
|
|
return handled.ApplyAfter (new RdpApplyAfterHandler (
|
|
f.Apply));
|
|
}
|
|
|
|
internal override RdpPattern StartTagOpenDeriv (string name, string ns, MemoizationStore memo)
|
|
{
|
|
RdpPattern handled = memo.StartTagOpenDeriv (LValue, name, ns);
|
|
RdpFlip f = MakeFlip (RdpUtil.AfterFunction, RValue);
|
|
return handled.ApplyAfter (new RdpApplyAfterHandler (
|
|
f.Apply));
|
|
}
|
|
|
|
public override RdpPattern ApplyAfter (RdpApplyAfterHandler handler)
|
|
{
|
|
return LValue.After (handler (RValue));
|
|
}
|
|
|
|
// attDeriv cx (After p1 p2) att =
|
|
// after (attDeriv cx p1 att) p2
|
|
public override RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)
|
|
{
|
|
return LValue.AttDeriv (name, ns, value, reader).After (RValue);
|
|
}
|
|
|
|
public override RdpPattern StartAttDeriv (string name, string ns)
|
|
{
|
|
RdpPattern handled = LValue.StartAttDeriv (name, ns);
|
|
RdpFlip f = MakeFlip (RdpUtil.AfterFunction, RValue);
|
|
return handled.ApplyAfter (new RdpApplyAfterHandler (
|
|
f.Apply));
|
|
}
|
|
|
|
internal override RdpPattern StartAttDeriv (string name, string ns, MemoizationStore memo)
|
|
{
|
|
RdpPattern handled = memo.StartAttDeriv (LValue, name, ns);
|
|
RdpFlip f = MakeFlip (RdpUtil.AfterFunction, RValue);
|
|
return handled.ApplyAfter (new RdpApplyAfterHandler (
|
|
f.Apply));
|
|
}
|
|
|
|
public override RdpPattern EndAttDeriv ()
|
|
{
|
|
return LValue.Nullable ? RValue : RdpNotAllowed.Instance;
|
|
}
|
|
|
|
public override RdpPattern StartTagCloseDeriv ()
|
|
{
|
|
return LValue.StartTagCloseDeriv ().After (RValue);
|
|
}
|
|
|
|
internal override RdpPattern StartTagCloseDeriv (MemoizationStore memo)
|
|
{
|
|
return memo.StartTagCloseDeriv (LValue).After (RValue);
|
|
}
|
|
|
|
public override RdpPattern EndTagDeriv ()
|
|
{
|
|
return LValue.Nullable ? RValue : RdpNotAllowed.Instance;
|
|
}
|
|
|
|
public override RelaxngPatternType PatternType {
|
|
get { return RelaxngPatternType.After; }
|
|
}
|
|
|
|
internal override void MarkReachableDefs ()
|
|
{
|
|
throw new InvalidOperationException ();
|
|
}
|
|
|
|
internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
|
|
{
|
|
throw new InvalidOperationException ();
|
|
}
|
|
|
|
internal override bool ContainsText ()
|
|
{
|
|
throw new InvalidOperationException ();
|
|
}
|
|
}
|
|
}
|
|
|