Skip to content

Commit

Permalink
Convert InlineContainer to IInlineContainer.
Browse files Browse the repository at this point in the history
Now LineNode has 1 direct subclasses: InlineContainerLineNode.
Will add another subclass "Table" later.
  • Loading branch information
CXuesong committed Aug 18, 2017
1 parent a2e7478 commit cc4475a
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 54 deletions.
2 changes: 2 additions & 0 deletions MwParserFromScratch/Nodes/Inline.cs
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,7 @@ protected override Node CloneCore()
ClosingTagTrailingWhitespace = ClosingTagTrailingWhitespace,
};
n.Attributes.Add(Attributes);
n.Attributes.TrailingWhitespace = Attributes.TrailingWhitespace;
return n;
}

Expand Down Expand Up @@ -709,6 +710,7 @@ protected override Node CloneCore()
ClosingTagTrailingWhitespace = ClosingTagTrailingWhitespace,
};
n.Attributes.Add(Attributes);
n.Attributes.TrailingWhitespace = Attributes.TrailingWhitespace;
return n;
}

Expand Down
128 changes: 81 additions & 47 deletions MwParserFromScratch/Nodes/Wikitext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class Wikitext : Node

public Wikitext(params LineNode[] lines) : this((IEnumerable<LineNode>)lines)
{

}

public Wikitext(IEnumerable<LineNode> lines)
Expand Down Expand Up @@ -57,34 +57,27 @@ public override string ToPlainText(NodePlainTextOptions options)
}
}

public abstract class InlineContainer : Node
public interface IInlineContainer
{
/// <summary>
/// Content of the inline container.
/// </summary>
public NodeCollection<InlineNode> Inlines { get; }

public InlineContainer() : this(null)
{
}

public InlineContainer(IEnumerable<InlineNode> nodes)
{
Inlines = new NodeCollection<InlineNode>(this);
if (nodes != null) Inlines.Add(nodes);
}
NodeCollection<InlineNode> Inlines { get; }
}

public static class InlineContainerExtensions
{
/// <summary>
/// Append a <see cref="PlainText"/> node to the beginning of the paragraph.
/// </summary>
/// <param name="text">The text to be inserted.</param>
/// <returns>Either the new <see cref="PlainText"/> node inserted, or the existing <see cref="PlainText"/> at the beginning of the paragraph.</returns>
/// <exception cref="ArgumentNullException"><paramref name="text"/> is <c>null</c>.</exception>
public PlainText Prepend(string text)
public static PlainText Prepend(this IInlineContainer container, string text)
{
if (text == null) throw new ArgumentNullException(nameof(text));
var pt = Inlines.FirstNode as PlainText;
if (pt == null) Inlines.AddFirst(pt = new PlainText());
var pt = container.Inlines.FirstNode as PlainText;
if (pt == null) container.Inlines.AddFirst(pt = new PlainText());
pt.Content = text + pt.Content;
return pt;
}
Expand All @@ -95,27 +88,28 @@ public PlainText Prepend(string text)
/// <param name="text">The text to be inserted.</param>
/// <returns>Either the new <see cref="PlainText"/> node inserted, or the existing <see cref="PlainText"/> at the end of the paragraph.</returns>
/// <exception cref="ArgumentNullException"><paramref name="text"/> is <c>null</c>.</exception>
public PlainText Append(string text)
public static PlainText Append(this IInlineContainer container, string text)
{
if (text == null) throw new ArgumentNullException(nameof(text));
var pt = Inlines.LastNode as PlainText;
if (pt == null) Inlines.Add(pt = new PlainText());
var pt = container.Inlines.LastNode as PlainText;
if (pt == null) container.Inlines.Add(pt = new PlainText());
pt.Content += text;
return pt;
}

internal PlainText AppendWithLineInfo(string text, int lineNumber1, int linePosition1, int lineNumber2, int linePosition2)
internal static PlainText AppendWithLineInfo(this IInlineContainer container, string text, int lineNumber1, int linePosition1, int lineNumber2, int linePosition2)
{
Debug.Assert(container != null);
Debug.Assert(text != null);
Debug.Assert(lineNumber1 >= 0);
Debug.Assert(linePosition1 >= 0);
Debug.Assert(lineNumber2 >= 0);
Debug.Assert(linePosition2 >= 0);
Debug.Assert(lineNumber1 < lineNumber2 || lineNumber1 == lineNumber2 && linePosition1 <= linePosition2);
var pt = Inlines.LastNode as PlainText;
var pt = container.Inlines.LastNode as PlainText;
if (pt == null)
{
Inlines.Add(pt = new PlainText(text));
container.Inlines.Add(pt = new PlainText(text));
pt.SetLineInfo(lineNumber1, linePosition1, lineNumber2, linePosition2);
}
else
Expand All @@ -124,60 +118,100 @@ internal PlainText AppendWithLineInfo(string text, int lineNumber1, int linePosi
pt.Content += text;
pt.ExtendLineInfo(lineNumber2, linePosition2);
}
ExtendLineInfo(lineNumber2, linePosition2);
((Node)container).ExtendLineInfo(lineNumber2, linePosition2);
return pt;
}

/// <summary>
/// Enumerates the children of this node.
/// </summary>
public override IEnumerable<Node> EnumChildren()
=> Inlines;

/// <inheritdoc />
public override string ToPlainText(NodePlainTextOptions options)
{
return string.Join(null, Inlines.Select(i => i.ToPlainText(options))).Trim();
}
}

/// <summary>
/// A single-line RUN.
/// A single-line (or multi-line) RUN.
/// </summary>
public class Run : InlineContainer
/// <remarks>
/// In some cases (e.g. the text of WIKILINK or the caption of TABLE), line-breaks are
/// allowed, but they will not be treated as paragraph breaks.
/// </remarks>
public class Run : Node, IInlineContainer
{
public Run()
public Run() : this((IEnumerable<InlineNode>)null)
{
}

public Run(params InlineNode[] nodes) : base(nodes)
public Run(params InlineNode[] nodes) : this((IEnumerable<InlineNode>)nodes)
{
}

public Run(IEnumerable<InlineNode> nodes) : base(nodes)
public Run(IEnumerable<InlineNode> nodes)
{
Inlines = new NodeCollection<InlineNode>(this);
if (nodes != null) Inlines.Add(nodes);
}

public NodeCollection<InlineNode> Inlines { get; }

public override IEnumerable<Node> EnumChildren() => Inlines;

protected override Node CloneCore() => new Run(Inlines);

public override string ToPlainText(NodePlainTextOptions options)
{
return string.Join(null, Inlines.Select(i => i.ToPlainText(options))).Trim();

}

public override string ToString()
{
return string.Join(null, Inlines);
}
}

public abstract class LineNode : InlineContainer
/// <summary>
/// Represents nodes that should be written in a stand-alone block of lines in WIKITEXT.
/// </summary>
public abstract class LineNode : Node
{
public LineNode()
{
}

public LineNode(IEnumerable<InlineNode> nodes) : base(nodes)
public LineNode(IEnumerable<InlineNode> nodes)
{
}
}

public class ListItem : LineNode
public abstract class InlineContainerLineNode : LineNode, IInlineContainer
{
public InlineContainerLineNode() : this((IEnumerable<InlineNode>)null)
{
}

public InlineContainerLineNode(params InlineNode[] nodes) : this((IEnumerable<InlineNode>)nodes)
{
}

public InlineContainerLineNode(IEnumerable<InlineNode> nodes)
{
Inlines = new NodeCollection<InlineNode>(this);
if (nodes != null) Inlines.Add(nodes);
}

public NodeCollection<InlineNode> Inlines { get; }

public override IEnumerable<Node> EnumChildren() => Inlines;

protected override Node CloneCore() => new Run(Inlines);

public override string ToPlainText(NodePlainTextOptions options)
{
return string.Join(null, Inlines.Select(i => i.ToPlainText(options))).Trim();
}

public override string ToString()
{
return string.Join(null, Inlines);
}
}

public class ListItem : InlineContainerLineNode
{
public ListItem()
{
Expand All @@ -199,7 +233,7 @@ public ListItem(IEnumerable<InlineNode> nodes) : base(nodes)

protected override Node CloneCore()
{
var n = new ListItem(Inlines) {Prefix = Prefix};
var n = new ListItem(Inlines) { Prefix = Prefix };
return n;
}

Expand All @@ -213,7 +247,7 @@ public override string ToString()
}
}

public class Heading : LineNode
public class Heading : InlineContainerLineNode
{
private int _Level;
private Run _Suffix;
Expand Down Expand Up @@ -272,7 +306,7 @@ public override IEnumerable<Node> EnumChildren()

protected override Node CloneCore()
{
var n = new Heading(Inlines) {Level = Level};
var n = new Heading(Inlines) { Level = Level };
return n;
}

Expand All @@ -283,7 +317,7 @@ public override string ToString()
}
}

public class Paragraph : LineNode
public class Paragraph : InlineContainerLineNode
{
public Paragraph()
{
Expand Down
10 changes: 5 additions & 5 deletions UnitTestProject1/BasicParsingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public void TestComment()
public void TestWikiLink1()
{
var root = Utility.ParseAndAssert("[[Duck]]\n", "P[[[Duck]]\n]");
var link = (WikiLink) root.Lines.First().Inlines.First();
var link = (WikiLink) root.Lines.First().EnumChildren().First();
Assert.AreEqual(link.Target.ToString(), "Duck");
Assert.AreEqual(link.Text, null);
}
Expand All @@ -134,7 +134,7 @@ public void TestWikiLink1()
public void TestWikiLink2()
{
var root = Utility.ParseAndAssert("[[Duck|ducks]]\n", "P[[[Duck|ducks]]\n]");
var link = (WikiLink) root.Lines.First().Inlines.First();
var link = (WikiLink) root.Lines.First().EnumChildren().First();
Assert.AreEqual(link.Target.ToString(), "Duck");
Assert.AreEqual(link.Text.ToString(), "ducks");
}
Expand All @@ -143,7 +143,7 @@ public void TestWikiLink2()
public void TestExternalLink1()
{
var root = Utility.ParseAndAssert("http://cxuesong.com\n", "P[-[http://cxuesong.com]-\n]");
var link = (ExternalLink)root.Lines.First().Inlines.First();
var link = (ExternalLink)root.Lines.First().EnumChildren().First();
Assert.AreEqual(link.Target.ToString(), "http://cxuesong.com");
Assert.AreEqual(link.Text, null);
Assert.IsFalse(link.Brackets);
Expand All @@ -153,7 +153,7 @@ public void TestExternalLink1()
public void TestExternalLink2()
{
var root = Utility.ParseAndAssert("[http://cxuesong.com]\n", "P[[http://cxuesong.com]\n]");
var link = (ExternalLink)root.Lines.First().Inlines.First();
var link = (ExternalLink)root.Lines.First().EnumChildren().First();
Assert.AreEqual(link.Target.ToString(), "http://cxuesong.com");
Assert.AreEqual(link.Text, null);
Assert.IsTrue(link.Brackets);
Expand All @@ -164,7 +164,7 @@ public void TestExternalLink3()
{
var root = Utility.ParseAndAssert("[https://zh.wikipedia.org Chinese Wikipedia ]\n",
"P[[https://zh.wikipedia.org Chinese Wikipedia ]\n]");
var link = (ExternalLink) root.Lines.First().Inlines.First();
var link = (ExternalLink) root.Lines.First().EnumChildren().First();
Assert.AreEqual(link.Target.ToString(), "https://zh.wikipedia.org");
Assert.AreEqual(link.Text.ToString(), " Chinese Wikipedia ");
Assert.IsTrue(link.Brackets);
Expand Down
2 changes: 1 addition & 1 deletion UnitTestProject1/NodeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public void EnumDescendantsTest()
Assert.IsTrue(si.HasLineInfo);
Trace.WriteLine(
$"{node.GetType().Name}\t({si.StartLineNumber},{si.StartLinePosition})-({si.EndLineNumber},{si.EndLinePosition})\t[|{node}|]");
if (node is InlineContainer container)
if (node is IInlineContainer container)
{
IWikitextLineInfo lastChild = null;
foreach (IWikitextLineInfo child in container.Inlines)
Expand Down
2 changes: 1 addition & 1 deletion UnitTestProject1/ParsingBehaviorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public void TestMethod2()
var root = Utility.ParseAndAssert("{{Test{{test|a|b|c}}|def|g=h",
"P[{{Test{{test|a|b|c}}|P[def]|P[g]=P[h]}}]",
options);
Assert.IsTrue(((IWikitextParsingInfo) root.Lines.FirstNode.Inlines.FirstNode).InferredClosingMark);
Assert.IsTrue(((IWikitextParsingInfo) root.Lines.FirstNode.EnumChildren().First()).InferredClosingMark);
root = Utility.ParseAndAssert("<div><a>test</a><tag>def</div>",
"P[<div>P[<a>P[test]</a><tag>P[def]</tag>]</div>]",
options);
Expand Down

0 comments on commit cc4475a

Please sign in to comment.