Files
PowerShell-PowerShell/src/System.Management.Automation/engine/parser/CharTraits.cs
T
Steve Lee 4bc52d2358 Use consistent '(c)' for copyright symbol (#5210)
- Remove the year about copyright
- Fix casing of `All rights reserved`
- Replace Unicode characters representing single quote with a single quote
2017-10-26 14:12:19 -07:00

367 lines
16 KiB
C#

/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
namespace System.Management.Automation.Language
{
internal static class SpecialChars
{
// Uncommon whitespace
internal const char NoBreakSpace = (char)0x00a0;
internal const char NextLine = (char)0x0085;
// Special dashes
internal const char EnDash = (char)0x2013;
internal const char EmDash = (char)0x2014;
internal const char HorizontalBar = (char)0x2015;
// Special quotes
internal const char QuoteSingleLeft = (char)0x2018; // left single quotation mark
internal const char QuoteSingleRight = (char)0x2019; // right single quotation mark
internal const char QuoteSingleBase = (char)0x201a; // single low-9 quotation mark
internal const char QuoteReversed = (char)0x201b; // single high-reversed-9 quotation mark
internal const char QuoteDoubleLeft = (char)0x201c; // left double quotation mark
internal const char QuoteDoubleRight = (char)0x201d; // right double quotation mark
internal const char QuoteLowDoubleLeft = (char)0x201E; // low double left quote used in german.
}
[Flags]
internal enum CharTraits
{
None = 0x0000,
// For identifiers, is the character a letter?
IdentifierStart = 0x0002,
// The character is a valid first character of a multiplier
MultiplierStart = 0x0004,
// The character is a valid type suffix for numeric literals
TypeSuffix = 0x0008,
// The character is a whitespace character
Whitespace = 0x0010,
// The character terminates a line.
Newline = 0x0020,
// The character is a hexadecimal digit.
HexDigit = 0x0040,
// The character is a decimal digit.
Digit = 0x0080,
// The character is allowed as the first character in an unbraced variable name.
VarNameFirst = 0x0100,
// The character is not part of the token being scanned.
ForceStartNewToken = 0x0200,
// The character is not part of the token being scanned, when the token is known to be part of an assembly name.
ForceStartNewAssemblyNameSpecToken = 0x0400,
// The character is the first character of some operator (and hence is not part of a token that starts a number)
ForceStartNewTokenAfterNumber = 0x0800,
}
internal static class CharExtensions
{
static CharExtensions()
{
Diagnostics.Assert(s_traits.Length == 128, "Extension methods rely on this table size.");
}
private static readonly CharTraits[] s_traits = new CharTraits[]
{
/* 0x0 */ CharTraits.ForceStartNewToken | CharTraits.ForceStartNewAssemblyNameSpecToken,
/* 0x1 */ CharTraits.None,
/* 0x2 */ CharTraits.None,
/* 0x3 */ CharTraits.None,
/* 0x4 */ CharTraits.None,
/* 0x5 */ CharTraits.None,
/* 0x6 */ CharTraits.None,
/* 0x7 */ CharTraits.None,
/* 0x8 */ CharTraits.None,
/* 0x9 */ CharTraits.Whitespace | CharTraits.ForceStartNewToken | CharTraits.ForceStartNewAssemblyNameSpecToken,
/* 0xA */ CharTraits.Newline | CharTraits.ForceStartNewToken | CharTraits.ForceStartNewAssemblyNameSpecToken,
/* 0xB */ CharTraits.Whitespace | CharTraits.ForceStartNewToken | CharTraits.ForceStartNewAssemblyNameSpecToken,
/* 0xC */ CharTraits.Whitespace | CharTraits.ForceStartNewToken | CharTraits.ForceStartNewAssemblyNameSpecToken,
/* 0xD */ CharTraits.Newline | CharTraits.ForceStartNewToken | CharTraits.ForceStartNewAssemblyNameSpecToken,
/* 0xE */ CharTraits.None,
/* 0xF */ CharTraits.None,
/* 0x10 */ CharTraits.None,
/* 0x11 */ CharTraits.None,
/* 0x12 */ CharTraits.None,
/* 0x13 */ CharTraits.None,
/* 0x14 */ CharTraits.None,
/* 0x15 */ CharTraits.None,
/* 0x16 */ CharTraits.None,
/* 0x17 */ CharTraits.None,
/* 0x18 */ CharTraits.None,
/* 0x19 */ CharTraits.None,
/* 0x1A */ CharTraits.None,
/* 0x1B */ CharTraits.None,
/* 0x1C */ CharTraits.None,
/* 0x1D */ CharTraits.None,
/* 0x1E */ CharTraits.None,
/* 0x1F */ CharTraits.None,
/* */ CharTraits.Whitespace | CharTraits.ForceStartNewToken | CharTraits.ForceStartNewAssemblyNameSpecToken,
/* ! */ CharTraits.ForceStartNewTokenAfterNumber,
/* " */ CharTraits.None,
/* # */ CharTraits.ForceStartNewTokenAfterNumber,
/* $ */ CharTraits.VarNameFirst,
/* % */ CharTraits.ForceStartNewTokenAfterNumber,
/* & */ CharTraits.ForceStartNewToken,
/* ' */ CharTraits.None,
/* ( */ CharTraits.ForceStartNewToken,
/* ) */ CharTraits.ForceStartNewToken,
/* * */ CharTraits.ForceStartNewTokenAfterNumber,
/* + */ CharTraits.ForceStartNewTokenAfterNumber,
/* , */ CharTraits.ForceStartNewToken | CharTraits.ForceStartNewAssemblyNameSpecToken,
/* - */ CharTraits.ForceStartNewTokenAfterNumber,
/* . */ CharTraits.ForceStartNewTokenAfterNumber,
/* / */ CharTraits.ForceStartNewTokenAfterNumber,
/* 0 */ CharTraits.Digit | CharTraits.HexDigit | CharTraits.VarNameFirst,
/* 1 */ CharTraits.Digit | CharTraits.HexDigit | CharTraits.VarNameFirst,
/* 2 */ CharTraits.Digit | CharTraits.HexDigit | CharTraits.VarNameFirst,
/* 3 */ CharTraits.Digit | CharTraits.HexDigit | CharTraits.VarNameFirst,
/* 4 */ CharTraits.Digit | CharTraits.HexDigit | CharTraits.VarNameFirst,
/* 5 */ CharTraits.Digit | CharTraits.HexDigit | CharTraits.VarNameFirst,
/* 6 */ CharTraits.Digit | CharTraits.HexDigit | CharTraits.VarNameFirst,
/* 7 */ CharTraits.Digit | CharTraits.HexDigit | CharTraits.VarNameFirst,
/* 8 */ CharTraits.Digit | CharTraits.HexDigit | CharTraits.VarNameFirst,
/* 9 */ CharTraits.Digit | CharTraits.HexDigit | CharTraits.VarNameFirst,
/* : */ CharTraits.VarNameFirst,
/* ; */ CharTraits.ForceStartNewToken,
/* < */ CharTraits.ForceStartNewTokenAfterNumber,
/* = */ CharTraits.ForceStartNewAssemblyNameSpecToken | CharTraits.ForceStartNewTokenAfterNumber,
/* > */ CharTraits.ForceStartNewTokenAfterNumber,
/* ? */ CharTraits.VarNameFirst,
/* @ */ CharTraits.None,
/* A */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.HexDigit,
/* B */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.HexDigit,
/* C */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.HexDigit,
/* D */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.HexDigit | CharTraits.TypeSuffix,
/* E */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.HexDigit,
/* F */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.HexDigit,
/* G */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.MultiplierStart,
/* H */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* I */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* J */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* K */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.MultiplierStart,
/* L */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.TypeSuffix,
/* M */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.MultiplierStart,
/* N */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* O */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* P */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.MultiplierStart,
/* Q */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* R */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* S */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* T */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.MultiplierStart,
/* U */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* V */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* W */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* X */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* Y */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* Z */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* [ */ CharTraits.None,
/* \ */ CharTraits.None,
/* ] */ CharTraits.ForceStartNewAssemblyNameSpecToken | CharTraits.ForceStartNewTokenAfterNumber,
/* ^ */ CharTraits.VarNameFirst,
/* _ */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* ` */ CharTraits.None,
/* a */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.HexDigit,
/* b */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.HexDigit,
/* c */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.HexDigit,
/* d */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.HexDigit | CharTraits.TypeSuffix,
/* e */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.HexDigit,
/* f */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.HexDigit,
/* g */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.MultiplierStart,
/* h */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* i */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* j */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* k */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.MultiplierStart,
/* l */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.TypeSuffix,
/* m */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.MultiplierStart,
/* n */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* o */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* p */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.MultiplierStart,
/* q */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* r */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* s */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* t */ CharTraits.IdentifierStart | CharTraits.VarNameFirst | CharTraits.MultiplierStart,
/* u */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* v */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* w */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* x */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* y */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* z */ CharTraits.IdentifierStart | CharTraits.VarNameFirst,
/* { */ CharTraits.ForceStartNewToken,
/* | */ CharTraits.ForceStartNewToken,
/* } */ CharTraits.ForceStartNewToken,
/* ~ */ CharTraits.None,
/* 0x7F */ CharTraits.None,
};
// Return true if the character is a whitespace character.
// Newlines are not whitespace.
internal static bool IsWhitespace(this char c)
{
if (c < 128)
{
return (s_traits[c] & CharTraits.Whitespace) != 0;
}
if (c <= 256)
{
return (c == SpecialChars.NoBreakSpace
|| c == SpecialChars.NextLine);
}
return char.IsSeparator(c);
}
// Return true if the character is any of the normal or special
// dash characters.
internal static bool IsDash(this char c)
{
return (c == '-'
|| c == SpecialChars.EnDash
|| c == SpecialChars.EmDash
|| c == SpecialChars.HorizontalBar);
}
// Return true if the character is any of the normal or special
// single quote characters.
internal static bool IsSingleQuote(this char c)
{
return (c == '\''
|| c == SpecialChars.QuoteSingleLeft
|| c == SpecialChars.QuoteSingleRight
|| c == SpecialChars.QuoteSingleBase
|| c == SpecialChars.QuoteReversed);
}
// Return true if the character is any of the normal or special
// double quote characters.
internal static bool IsDoubleQuote(this char c)
{
return (c == '"'
|| c == SpecialChars.QuoteDoubleLeft
|| c == SpecialChars.QuoteDoubleRight
|| c == SpecialChars.QuoteLowDoubleLeft);
}
// Return true if the character can be the first character of
// the variable name for unbraced variable tokens.
internal static bool IsVariableStart(this char c)
{
if (c < 128)
{
return (s_traits[c] & CharTraits.VarNameFirst) != 0;
}
return char.IsLetterOrDigit(c);
}
// Return true if the character can be the first character of
// an identifier or label.
internal static bool IsIdentifierStart(this char c)
{
if (c < 128)
{
return (s_traits[c] & CharTraits.IdentifierStart) != 0;
}
return char.IsLetter(c);
}
// Return true if the character can follow the first character of
// an identifier or label.
internal static bool IsIdentifierFollow(this char c)
{
if (c < 128)
{
return (s_traits[c] & (CharTraits.IdentifierStart | CharTraits.Digit)) != 0;
}
return char.IsLetterOrDigit(c);
}
// Return true if the character is a hexadecimal digit.
internal static bool IsHexDigit(this char c)
{
if (c < 128)
{
return (s_traits[c] & CharTraits.HexDigit) != 0;
}
return false;
}
// Return true if the character is a decimal digit.
internal static bool IsDecimalDigit(this char c)
{
if (c < 128)
{
return (s_traits[c] & CharTraits.Digit) != 0;
}
return false;
}
// Return true if the character is a type suffix character.
internal static bool IsTypeSuffix(this char c)
{
if (c < 128)
{
return (s_traits[c] & CharTraits.TypeSuffix) != 0;
}
return false;
}
// Return true if the character is the first character in a multiplier.
internal static bool IsMultiplierStart(this char c)
{
if (c < 128)
{
return (s_traits[c] & CharTraits.MultiplierStart) != 0;
}
return false;
}
// Return true if the character ends the current token while scanning
// a token beginning with a letter or number, regardless of the tokenizing
// mode. This helps ensure that we tokenize 'a#b' as a single token, but
// 'a{' as 2 tokens.
internal static bool ForceStartNewToken(this char c)
{
if (c < 128)
{
return (s_traits[c] & CharTraits.ForceStartNewToken) != 0;
}
return c.IsWhitespace();
}
// Return true if the character ends the current number token. This allows the tokenizer
// to scan '7z' as a single token, but '7+' as 2 tokens.
internal static bool ForceStartNewTokenAfterNumber(this char c)
{
if (c < 128)
{
return (s_traits[c] & CharTraits.ForceStartNewTokenAfterNumber) != 0;
}
return c.IsDash();
}
// Return true if the character ends the current token while scanning
// a token in the assembly name spec.
internal static bool ForceStartNewTokenInAssemblyNameSpec(this char c)
{
if (c < 128)
{
return (s_traits[c] & CharTraits.ForceStartNewAssemblyNameSpecToken) != 0;
}
return c.IsWhitespace();
}
}
}