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

Use SearchValues for identitifers #168

Merged
merged 3 commits into from
Nov 23, 2024
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
37 changes: 37 additions & 0 deletions src/Parlot/Character.Mask.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
#if !NET8_0_OR_GREATER
using System.Runtime.CompilerServices;
#endif

namespace Parlot;

[Flags]
internal enum CharacterMask : byte
{
None = 0,
IdentifierStart = 1,
IdentifierPart = 2,
WhiteSpace = 4,
WhiteSpaceOrNewLine = 8
}

#if !NET8_0_OR_GREATER
public static partial class Character
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsDecimalDigit(char ch) => IsInRange(ch, '0', '9');

public static bool IsIdentifierStart(char ch)
{
return (_characterData[ch] & (byte)CharacterMask.IdentifierStart) != 0;
}

public static bool IsIdentifierPart(char ch)
{
return (_characterData[ch] & (byte)CharacterMask.IdentifierPart) != 0;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsHexDigit(char ch) => HexConverter.IsHexChar(ch);
}
#endif
35 changes: 35 additions & 0 deletions src/Parlot/Character.SearchValues.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#if NET8_0_OR_GREATER
using System.Buffers;
using System.Runtime.CompilerServices;

namespace Parlot;

public static partial class Character
{
internal const string DecimalDigits = "0123456789";
internal const string Alpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
internal const string AlphaNumeric = Alpha + DecimalDigits;
internal const string DefaultIdentifierStart = "$_" + Alpha;
internal const string DefaultIdentifierPart = "$_" + AlphaNumeric;
internal const string HexDigits = "0123456789abcdefABCDEF";
internal const string NewLines = "\n\r\v";

internal static readonly SearchValues<char> _decimalDigits = SearchValues.Create(DecimalDigits);
internal static readonly SearchValues<char> _hexDigits = SearchValues.Create(HexDigits);
internal static readonly SearchValues<char> _identifierStart = SearchValues.Create(DefaultIdentifierStart);
internal static readonly SearchValues<char> _identifierPart = SearchValues.Create(DefaultIdentifierPart);
internal static readonly SearchValues<char> _newLines = SearchValues.Create(NewLines);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsDecimalDigit(char ch) => _decimalDigits.Contains(ch);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsIdentifierStart(char ch) => _identifierStart.Contains(ch);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsIdentifierPart(char ch) => _identifierPart.Contains(ch);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsHexDigit(char ch) => _hexDigits.Contains(ch);
}
#endif
50 changes: 13 additions & 37 deletions src/Parlot/Character.cs
Original file line number Diff line number Diff line change
@@ -1,51 +1,15 @@
using System;
using System;
using System.Buffers;
using System.Runtime.CompilerServices;

namespace Parlot;

[Flags]
internal enum CharacterMask : byte
{
None = 0,
IdentifierStart = 1,
IdentifierPart = 2,
WhiteSpace = 4,
WhiteSpaceOrNewLine = 8
}

public static partial class Character
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsDecimalDigit(char ch) => IsInRange(ch, '0', '9');

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsInRange(char ch, char min, char max) => ch - (uint)min <= max - (uint)min;

public static bool IsHexDigit(char ch) => HexConverter.IsHexChar(ch);

public static bool IsIdentifierStart(char ch)
{
return (_characterData[ch] & (byte)CharacterMask.IdentifierStart) != 0;
}

public static bool IsIdentifierPart(char ch)
{
return (_characterData[ch] & (byte)CharacterMask.IdentifierPart) != 0;
}

public static bool IsWhiteSpace(char ch)
{
return (_characterData[ch] & (byte)CharacterMask.WhiteSpace) != 0;
}

public static bool IsWhiteSpaceOrNewLine(char ch)
{
return (_characterData[ch] & (byte)CharacterMask.WhiteSpaceOrNewLine) != 0;
}

public static bool IsNewLine(char ch) => ch is '\n' or '\r' or '\v';

public static char ScanHexEscape(string text, int index, out int length)
{
return ScanHexEscape(text.AsSpan(index), out length);
Expand Down Expand Up @@ -156,4 +120,16 @@ public static TextSpan DecodeString(TextSpan span)
}

private static int HexValue(char ch) => HexConverter.FromChar(ch);

public static bool IsWhiteSpace(char ch)
{
return (_characterData[ch] & (byte)CharacterMask.WhiteSpace) != 0;
}

public static bool IsWhiteSpaceOrNewLine(char ch)
{
return (_characterData[ch] & (byte)CharacterMask.WhiteSpaceOrNewLine) != 0;
}

public static bool IsNewLine(char ch) => ch is '\n' or '\r' or '\v';
}
6 changes: 3 additions & 3 deletions src/Parlot/Cursor.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Runtime.CompilerServices;

namespace Parlot;
Expand Down Expand Up @@ -67,7 +67,7 @@ public void Advance()
}

/// <summary>
/// Advances the cursor.
/// Advances the cursor and tracks its current location (line and column).
/// </summary>
public void Advance(int count)
{
Expand Down Expand Up @@ -115,7 +115,7 @@ public void Advance(int count)
}

/// <summary>
/// Advances the cursor with the knowledge there are no new lines.
/// Advances the cursor and tracks its current location (line and column) with the knowledge there are no new lines (\r or \n).
/// </summary>
public void AdvanceNoNewLines(int offset)
{
Expand Down
46 changes: 46 additions & 0 deletions src/Parlot/Fluent/IdentifierLiteral.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#if NET8_0_OR_GREATER
using System;
using System.Buffers;

namespace Parlot.Fluent;

internal sealed class IdentifierLiteral : Parser<TextSpan>
{
private readonly SearchValues<char> _startSearchValues;
private readonly SearchValues<char> _partSearchValues;

public IdentifierLiteral(SearchValues<char> startSearchValues, SearchValues<char> partSearchValues)
{
_startSearchValues = startSearchValues;
_partSearchValues = partSearchValues;

// Since we assume these can't container new lines, we can check this here.
if (partSearchValues.Contains('\n') || startSearchValues.Contains('\r'))
{
throw new InvalidOperationException("Identifiers cannot contain new lines.");
}
}

public override bool Parse(ParseContext context, ref ParseResult<TextSpan> result)
{
context.EnterParser(this);

var span = context.Scanner.Cursor.Span;

if (span.Length == 0 || !_startSearchValues.Contains(span[0]))
{
return false;
}

var index = span.Slice(1).IndexOfAnyExcept(_partSearchValues);

// If index == -1 the whole input is a match
var size = index == -1 ? span.Length : index + 1;

var start = context.Scanner.Cursor.Position.Offset;
context.Scanner.Cursor.AdvanceNoNewLines(size);
result.Set(start, start + size, new TextSpan(context.Scanner.Buffer, start, size));
return true;
}
}
#endif
2 changes: 0 additions & 2 deletions src/Parlot/Fluent/NumberLiteral.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,8 @@ public CompilationResult Compile(CompilationContext context)
{
var result = context.CreateCompilationResult<T>();

// var start = context.Scanner.Cursor.Offset;
// var reset = context.Scanner.Cursor.Position;

var start = context.DeclareOffsetVariable(result);
var reset = context.DeclarePositionVariable(result);

var numberStyles = result.DeclareVariable<NumberStyles>($"numberStyles{context.NextNumber}", Expression.Constant(_numberStyles));
Expand Down
Loading