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

Remove the state machine #36

Merged
merged 7 commits into from
Mar 19, 2017
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
199 changes: 153 additions & 46 deletions src/Strinken/Engine/Cursor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Strinken.Common;

Expand All @@ -26,6 +27,8 @@ public Cursor(string input)
reader = new StringReader(input);
Position = -1;
Value = '\0';

Next();
}

/// <summary>
Expand Down Expand Up @@ -64,19 +67,25 @@ public void Next()
Position++;
}

/// <summary>
/// Peeks the next character of the cursor.
/// </summary>
/// <returns>The next character of the cursor.</returns>
public int Peek() => reader.Peek();

/// <summary>
/// Indicates if the next character is the end.
/// </summary>
/// <returns>A value indicating whether the next character is the end.</returns>
public bool PeekIsEnd() => Position != -1 && Peek() == -1;

/// <summary>
/// Parses an argument.
/// </summary>
/// <returns>The result of the parsing.</returns>
public ParseResult<Token> ParseArgument()
{
if (Value != SpecialCharacter.ArgumentIndicator && Value != SpecialCharacter.ArgumentSeparator)
{
return ParseResult<Token>.FailureWithMessage(string.Format(Errors.IllegalCharacter, CharValue, Position));
}

var subtype = TokenSubtype.Base;
Next();
if (Value == SpecialCharacter.ArgumentTagIndicator)
{
// Consume ArgumentTagIndicator
Expand All @@ -96,7 +105,7 @@ public ParseResult<Token> ParseArgument()
return ParseResult<Token>.Success(new Token(result.Value.Data, TokenType.Argument, subtype));
}

return ParseResult<Token>.FailureWithMessage(result.Message);
return ParseResult<Token>.FailureWithMessage(result.Message != Errors.EmptyTag ? result.Message : Errors.EmptyArgument);
}
else
{
Expand All @@ -106,7 +115,7 @@ public ParseResult<Token> ParseArgument()
return ParseResult<Token>.Success(new Token(result.Value, TokenType.Argument, subtype));
}

return ParseResult<Token>.FailureWithMessage(result.Message);
return ParseResult<Token>.FailureWithMessage(result.Message != Errors.EmptyName ? result.Message : Errors.EmptyArgument);
}
}

Expand All @@ -116,26 +125,14 @@ public ParseResult<Token> ParseArgument()
/// <returns>The result of the parsing.</returns>
public ParseResult<Token> ParseFilter()
{
if (Value != SpecialCharacter.FilterSeparator)
{
return ParseResult<Token>.FailureWithMessage(string.Format(Errors.IllegalCharacter, CharValue, Position));
}

var subtype = TokenSubtype.Base;
Next();

/*
* Special characters before the token can be parsed here.
*/

var ends = new[] { SpecialCharacter.FilterSeparator, SpecialCharacter.ArgumentIndicator };
var result = ParseName(ends, c => !c.IsInvalidTokenNameCharacter());
if (result.Result)
{
return ParseResult<Token>.Success(new Token(result.Value, TokenType.Filter, subtype));
return ParseResult<Token>.Success(new Token(result.Value, TokenType.Filter, TokenSubtype.Base));
}

return ParseResult<Token>.FailureWithMessage(result.Message);
return ParseResult<Token>.FailureWithMessage(result.Message != Errors.EmptyName ? result.Message : Errors.EmptyFilter);
}

/// <summary>
Expand All @@ -148,16 +145,22 @@ public ParseResult<IList<Token>> ParseFilterAndArguments()
var filterParseResult = ParseFilter();
if (!filterParseResult.Result)
{
return ParseResult<IList<Token>>.FailureWithMessage(filterParseResult.Message != Errors.EmptyName ? filterParseResult.Message : Errors.EmptyFilter);
return ParseResult<IList<Token>>.FailureWithMessage(filterParseResult.Message);
}

tokenList.Add(filterParseResult.Value);
while (Value != SpecialCharacter.FilterSeparator && Value != SpecialCharacter.TokenEndIndicator && !HasEnded())
{
if (Value != SpecialCharacter.ArgumentIndicator && Value != SpecialCharacter.ArgumentSeparator)
{
return ParseResult<IList<Token>>.FailureWithMessage(string.Format(Errors.IllegalCharacter, CharValue, Position));
}

Next();
var argumentParseResult = ParseArgument();
if (!argumentParseResult.Result)
{
return ParseResult<IList<Token>>.FailureWithMessage(argumentParseResult.Message != Errors.EmptyName ? argumentParseResult.Message : Errors.EmptyArgument);
return ParseResult<IList<Token>>.FailureWithMessage(argumentParseResult.Message);
}

tokenList.Add(argumentParseResult.Value);
Expand All @@ -167,7 +170,7 @@ public ParseResult<IList<Token>> ParseFilterAndArguments()
}

/// <summary>
/// Parses a string and returns the first name in it.
/// Parses a string inside a token and returns the first name in it.
/// </summary>
/// <param name="ends">A list of valid ends.</param>
/// <param name="isValidChar">A function indicating whether a character is valid.</param>
Expand All @@ -183,52 +186,53 @@ public ParseResult<string> ParseName(ICollection<int> ends, Func<char, bool> isV

while (true)
{
if (updatedEnd.Contains(Value))
switch (Value)
{
break;
}
case int _ when updatedEnd.Contains(Value):
var parsedName = builder.ToString();
return !string.IsNullOrEmpty(parsedName) ? ParseResult<string>.Success(parsedName) : ParseResult<string>.FailureWithMessage(Errors.EmptyName);

if (HasEnded())
{
return ParseResult<string>.FailureWithMessage(Errors.EndOfString);
}
case int _ when HasEnded():
return ParseResult<string>.FailureWithMessage(Errors.EndOfString);

if (!isValidChar?.Invoke(CharValue) ?? false)
{
return ParseResult<string>.FailureWithMessage(string.Format(Errors.IllegalCharacter, CharValue, Position));
case int _ when !isValidChar?.Invoke(CharValue) ?? false:
return ParseResult<string>.FailureWithMessage(string.Format(Errors.IllegalCharacter, CharValue, Position));

default:
break;
}

builder.Append(CharValue);
Next();
}

var parsedName = builder.ToString();
return !string.IsNullOrEmpty(parsedName) ? ParseResult<string>.Success(parsedName) : ParseResult<string>.FailureWithMessage(Errors.EmptyName);
}

/// <summary>
/// Parses a string.
/// Parses a token.
/// </summary>
/// <returns>The result of the parsing.</returns>
public ParseResult<IList<Token>> ParseString()
public ParseResult<IList<Token>> ParseToken()
{
var tokenList = new List<Token>();
var tagParseResult = ParseTag();
if (!tagParseResult.Result)
{
return ParseResult<IList<Token>>.FailureWithMessage(tagParseResult.Message != Errors.EmptyName ? tagParseResult.Message : Errors.EmptyTag);
return ParseResult<IList<Token>>.FailureWithMessage(tagParseResult.Message);
}

tokenList.Add(tagParseResult.Value);
while (!HasEnded() && Value != SpecialCharacter.TokenEndIndicator)
{
if (Value != SpecialCharacter.FilterSeparator)
{
return ParseResult<IList<Token>>.FailureWithMessage(string.Format(Errors.IllegalCharacter, CharValue, Position));
}

Next();
var filterAndArgumentsParseResult = ParseFilterAndArguments();
if (filterAndArgumentsParseResult.Result)
{
foreach (var token in filterAndArgumentsParseResult.Value)
{
tokenList.Add(token);
}
tokenList.AddRange(filterAndArgumentsParseResult.Value ?? Enumerable.Empty<Token>());
}
else
{
Expand Down Expand Up @@ -265,7 +269,110 @@ public ParseResult<Token> ParseTag(bool isArgument = false)
return ParseResult<Token>.Success(new Token(result.Value, TokenType.Tag, subtype));
}

return ParseResult<Token>.FailureWithMessage(result.Message);
return ParseResult<Token>.FailureWithMessage(result.Message != Errors.EmptyName ? result.Message : Errors.EmptyTag);
}

/// <summary>
/// Parses an outside string.
/// </summary>
/// <returns>The result of the parsing.</returns>
public ParseResult<Token> ParseOutsideString()
{
var builder = new StringBuilder();
while (true)
{
switch (Value)
{
// Escaped indicator
case SpecialCharacter.TokenStartIndicator when Peek() == SpecialCharacter.TokenStartIndicator:
case SpecialCharacter.TokenEndIndicator when Peek() == SpecialCharacter.TokenEndIndicator:
Next();
break;

// Start of token or end of string
case SpecialCharacter.TokenStartIndicator:
case int _ when HasEnded():
return ParseResult<Token>.Success(new Token(builder.ToString(), TokenType.None, TokenSubtype.Base));

case SpecialCharacter.TokenEndIndicator when PeekIsEnd():
return ParseResult<Token>.FailureWithMessage(string.Format(Errors.IllegalCharacterAtStringEnd, CharValue));

case SpecialCharacter.TokenEndIndicator:
return ParseResult<Token>.FailureWithMessage(string.Format(Errors.IllegalCharacter, CharValue, Position));
}

builder.Append(CharValue);
Next();
}
}

/// <summary>
/// Parses a token and the following outside string.
/// </summary>
/// <returns>The result of the parsing.</returns>
public ParseResult<IList<Token>> ParseTokenAndOutsideString()
{
var tokenList = new List<Token>();
var tokenParseResult = ParseToken();
if (!tokenParseResult.Result)
{
return ParseResult<IList<Token>>.FailureWithMessage(tokenParseResult.Message);
}

tokenList.AddRange(tokenParseResult.Value ?? Enumerable.Empty<Token>());
if (Value != SpecialCharacter.TokenEndIndicator)
{
return ParseResult<IList<Token>>.FailureWithMessage(string.Format(Errors.IllegalCharacter, CharValue, Position));
}

Next();
var outsideParseResult = ParseOutsideString();
if (!outsideParseResult.Result)
{
return ParseResult<IList<Token>>.FailureWithMessage(outsideParseResult.Message);
}

tokenList.Add(outsideParseResult.Value);
return ParseResult<IList<Token>>.Success(tokenList);
}

/// <summary>
/// Parses a string.
/// </summary>
/// <returns>The result of the parsing.</returns>
public ParseResult<IList<Token>> ParseString()
{
var tokenList = new List<Token>();
var outsideParseResult = ParseOutsideString();
if (!outsideParseResult.Result)
{
return ParseResult<IList<Token>>.FailureWithMessage(outsideParseResult.Message);
}

tokenList.Add(outsideParseResult.Value);
while (!HasEnded())
{
if (Value != SpecialCharacter.TokenStartIndicator)
{
return ParseResult<IList<Token>>.FailureWithMessage(string.Format(Errors.IllegalCharacter, CharValue, Position));
}

Next();
var tokenParseResult = ParseTokenAndOutsideString();
if (tokenParseResult.Result)
{
foreach (var token in tokenParseResult.Value)
{
tokenList.Add(token);
}
}
else
{
return ParseResult<IList<Token>>.FailureWithMessage(tokenParseResult.Message);
}
}

return ParseResult<IList<Token>>.Success(tokenList);
}
}
}
Loading