Skip to content

Commit

Permalink
Merge pull request sprache#48 from IanWold/Comments
Browse files Browse the repository at this point in the history
Comment Parser
  • Loading branch information
mikehadlow committed Jan 21, 2015
2 parents 8d57457 + 2e7c62a commit 0a84be6
Show file tree
Hide file tree
Showing 8 changed files with 206 additions and 24 deletions.
13 changes: 6 additions & 7 deletions src/Sprache.Tests/Scenarios/AssemblerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ from instructionName in AsmToken(Parse.LetterOrDigit.Many().Text())
from operands in AsmToken(Identifier).XDelimitedBy(Parse.Char(','))
select Tuple.Create(instructionName, operands.ToArray());

public static Parser<string> Comment =
AsmToken(Parse.EndOfLineComment(";"));
public static CommentParser Comment = new CommentParser() { Single = ";" };

public static Parser<string> LabelId =
Parse.Identifier(Parse.Letter.Or(Parse.Chars("._?")), Parse.LetterOrDigit.Or(Parse.Chars("_@#$~.?")));
Expand All @@ -37,7 +36,7 @@ from colon in AsmToken(Parse.Char(':'))
public static readonly Parser<IEnumerable<AssemblerLine>> Assembler = (
from label in Label.Optional()
from instruction in Instruction.Optional()
from comment in Comment.Optional()
from comment in AsmToken(Comment.SingleLineComment).Optional()
from lineTerminator in Parse.LineTerminator
select new AssemblerLine(
label.GetOrDefault(),
Expand Down Expand Up @@ -150,17 +149,17 @@ public override bool Equals(object obj)
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((AssemblerLine) obj);
return Equals((AssemblerLine)obj);
}

public override int GetHashCode()
{
unchecked
{
var hashCode = (Label != null ? Label.GetHashCode() : 0);
hashCode = (hashCode*397) ^ (InstructionName != null ? InstructionName.GetHashCode() : 0);
hashCode = (hashCode*397) ^ (Operands != null ? Operands.GetHashCode() : 0);
hashCode = (hashCode*397) ^ (Comment != null ? Comment.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (InstructionName != null ? InstructionName.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (Operands != null ? Operands.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (Comment != null ? Comment.GetHashCode() : 0);
return hashCode;
}
}
Expand Down
129 changes: 129 additions & 0 deletions src/Sprache/CommentParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Sprache
{
/// <summary>
/// Constructs customizable comment parsers.
/// </summary>
public class CommentParser : IComment
{
///<summary>
///Single-line comment header.
///</summary>
public string Single { get; set; }

///<summary>
///Newline character preference.
///</summary>
public string NewLine { get; set; }

///<summary>
///Multi-line comment opener.
///</summary>
public string MultiOpen { get; set; }

///<summary>
///Multi-line comment closer.
///</summary>
public string MultiClose { get; set; }

/// <summary>
/// Initializes a Comment with C-style headers and Windows newlines.
/// </summary>
public CommentParser()
{
Single = "//";
MultiOpen = "/*";
MultiClose = "*/";
NewLine = "\n";
}

/// <summary>
/// Initializes a Comment with custom multi-line headers and newline characters.
/// Single-line headers are made null, it is assumed they would not be used.
/// </summary>
/// <param name="multiOpen"></param>
/// <param name="multiClose"></param>
/// <param name="newLine"></param>
public CommentParser(string multiOpen, string multiClose, string newLine = "\n")
{
Single = null;
MultiOpen = multiOpen;
MultiClose = multiClose;
NewLine = newLine;
}

/// <summary>
/// Initializes a Comment with custom headers and newline characters.
/// </summary>
/// <param name="single"></param>
/// <param name="multiOpen"></param>
/// <param name="multiClose"></param>
/// <param name="newLine"></param>
public CommentParser(string single, string multiOpen, string multiClose, string newLine = "\n")
{
Single = single;
MultiOpen = multiOpen;
MultiClose = multiClose;
NewLine = newLine;
}

///<summary>
///Parse a single-line comment.
///</summary>
public Parser<string> SingleLineComment
{
get
{
if (Single == null)
throw new ParseException("Field 'Single' is null; single-line comments not allowed.");

return from first in Parse.String(Single)
from rest in Parse.CharExcept(NewLine).Many().Text()
select rest;
}
private set { }
}

///<summary>
///Parse a multi-line comment.
///</summary>
public Parser<string> MultiLineComment
{
get
{
if (MultiOpen == null)
throw new ParseException("Field 'MultiOpen' is null; multi-line comments not allowed.");
else if (MultiClose == null)
throw new ParseException("Field 'MultiClose' is null; multi-line comments not allowed.");

return from first in Parse.String(MultiOpen)
from rest in Parse.AnyChar
.Until(Parse.String(MultiClose)).Text()
select rest;
}
private set { }
}

///<summary>
///Parse a comment.
///</summary>
public Parser<string> AnyComment
{
get
{
if (Single != null && MultiOpen != null && MultiClose != null)
return SingleLineComment.Or(MultiLineComment);
else if (Single != null && (MultiOpen == null || MultiClose == null))
return SingleLineComment;
else if (Single == null && (MultiOpen != null && MultiClose != null))
return MultiLineComment;
else throw new ParseException("Unable to parse comment; check values of fields 'MultiOpen' and 'MultiClose'.");
}
private set { }
}
}
}
45 changes: 45 additions & 0 deletions src/Sprache/IComment.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Sprache
{
interface IComment
{
///<summary>
///Single-line comment header.
///</summary>
string Single { get; set; }

///<summary>
///Newline character preference.
///</summary>
string NewLine { get; set; }

///<summary>
///Multi-line comment opener.
///</summary>
string MultiOpen { get; set; }

///<summary>
///Multi-line comment closer.
///</summary>
string MultiClose { get; set; }

///<summary>
///Parse a single-line comment.
///</summary>
Parser<string> SingleLineComment { get; }

///<summary>
///Parse a multi-line comment.
///</summary>
Parser<string> MultiLineComment { get; }

///<summary>
///Parse a comment.
///</summary>
Parser<string> AnyComment { get; }
}
}
13 changes: 0 additions & 13 deletions src/Sprache/Parse.Primitives.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,6 @@ from n in Char('\n')
.Or(LineEnd)
.Named("LineTerminator");

/// <summary>
/// Parser for single line comment. Doesn't contain tail line ending
/// </summary>
/// <param name="commentStart">Symbols to start comment. I.e. "//" for C#, "#" for perl, ";" for assembler</param>
/// <returns></returns>
public static Parser<string> EndOfLineComment(string commentStart)
{
return
from start in String(commentStart)
from comment in CharExcept("\r\n").Many().Text()
select comment;
}

/// <summary>
/// Parser for identifier starting with <paramref name="firstLetterParser"/> and continuing with <paramref name="tailLetterParser"/>
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions src/Sprache/Sprache.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
<!-- A reference to the entire .NET Framework is automatically included -->
</ItemGroup>
<ItemGroup>
<Compile Include="CommentParser.cs" />
<Compile Include="IComment.cs" />
<Compile Include="IInput.cs" />
<Compile Include="Input.cs" />
<Compile Include="IPositionAware.cs" />
Expand Down
16 changes: 12 additions & 4 deletions src/XmlExample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Text;
using Sprache;
using System.IO;

namespace XmlExample
{
Expand Down Expand Up @@ -45,6 +46,8 @@ public override string ToString()

public static class XmlParser
{
static CommentParser Comment = new CommentParser("<!--", "-->", "\r\n");

static readonly Parser<string> Identifier =
from first in Parse.Letter.Once()
from rest in Parse.LetterOrDigit.XOr(Parse.Char('-')).XOr(Parse.Char('_')).Many()
Expand Down Expand Up @@ -81,10 +84,14 @@ from end in EndTag(tag)
static readonly Parser<Node> ShortNode = Tag(from id in Identifier
from slash in Parse.Char('/')
select new Node { Name = id });

static readonly Parser<Node> Node = ShortNode.Or(FullNode);

static readonly Parser<Item> Item = Node.Select(n => (Item)n).XOr(Content);
static readonly Parser<Item> Item =
from leading in Comment.MultiLineComment.Many()
from item in Node.Select(n => (Item)n).XOr(Content)
from trailing in Comment.MultiLineComment.Many()
select item;

public static readonly Parser<Document> Document =
from leading in Parse.WhiteSpace.Many()
Expand All @@ -96,8 +103,9 @@ class Program
{
static void Main()
{
const string doc = "<body><p>hello,<br/> <i>world!</i></p></body>";
var parsed = XmlParser.Document.Parse(doc);
StreamReader reader = new StreamReader("TestFile.xml");
var parsed = XmlParser.Document.Parse(reader.ReadToEnd());
reader.Close();
Console.WriteLine(parsed);
Console.ReadKey(true);
}
Expand Down
7 changes: 7 additions & 0 deletions src/XmlExample/TestFile.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<body>
<p>
hello,<br/> <!--
This is a comment
--><i>world!</i>
</p>
</body>
5 changes: 5 additions & 0 deletions src/XmlExample/XmlExample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@
<Name>Sprache</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="TestFile.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
Expand Down

0 comments on commit 0a84be6

Please sign in to comment.