Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Comment Parser #48

Merged
merged 4 commits into from
Jan 21, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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