namespace DigitalSamurai.SpellSharp.InputProcessing.Processors
{
public partial class CSharpProcessor
{
public partial class CSharpScanner : Scanner<ScanMethod>
{
public const char hashChar = '#';
public const char singleQuoteChar = '\'';
public const char doubleQuoteChar = '\"';
public const char verbatimStringChar = '@';
public const char backSlashChar = '\\';
public const char forwardSlashChar = '/';
public const char asterixChar = '*';
protected override ScanningActions DetermineScanningAction (ScanningState state)
{
var scanMethod = state.CurrentScannerState;
try
{
switch (state.CurrentScannerState)
{
case ScanMethod.Preprocessor:
return DetermineScanningActionTillNotLetter (state, ref scanMethod);
case ScanMethod.PreprocessorDefine:
case ScanMethod.PreprocessorUndefine:
case ScanMethod.PreprocessorRegion:
case ScanMethod.PreprocessorEndRegion:
return DetermineScanningActionTillEndOfLine (state, ref scanMethod);
case ScanMethod.EscapedChar:
return DetermineScanningActionInEscapedChar (state, ref scanMethod);
case ScanMethod.EscapedString:
return DetermineScanningActionInEscapedString (state, ref scanMethod);
case ScanMethod.VerbatimString:
return DetermineScanningActionInVerbatimString (state, ref scanMethod);
case ScanMethod.SingleLineComment:
return DetermineScanningActionTillEndOfLine (state, ref scanMethod);
case ScanMethod.MultiLineComment:
return DetermineScanningActionInMultiLineComment (state, ref scanMethod);
case ScanMethod.XmlComment:
return DetermineScanningActionInXmlComment (state, ref scanMethod);
case ScanMethod.Number:
case ScanMethod.NumberReal:
return NumberRecognizer.DetermineScanningAction (state, ref scanMethod);
case ScanMethod.SymbolOperator:
return DetermineScanningActionInSymbolOperator (state, ref scanMethod);
default:
return DetermineScanningActionDefault (state, ref scanMethod);
}
}
finally
{
state.CurrentScannerState = scanMethod;
}
}
private ScanningActions DetermineScanningActionTillNotLetter (ScanningState state, ref ScanMethod scanMethod)
{
if (!char.IsLetter (state.CurrentInputChar))
{
scanMethod = ScanMethod.Default;
return ScanningActions.YieldCurrentToken;
}
return ScanningActions.AppendCurrentChar;
}
public ScanningActions DetermineScanningActionTillEndOfLine (ScanningState state, ref ScanMethod scanMethod)
{
if (ScanningRules.IsEndOfLine (state))
{
scanMethod = ScanMethod.Default;
return ScanningActions.YieldCurrentTokenAndSuppressCurrentChar;
}
return ScanningActions.AppendCurrentChar;
}
public static ScanningActions DetermineScanningActionDefault (ScanningState state, ref ScanMethod scanMethod)
{
ScanningActions onScanMethodChange;
if (RequiresScanMethodChange (state, ref scanMethod, out onScanMethodChange))
{
return onScanMethodChange;
}
return
ScanningRules.HasStartedWith_UnderScoreOrLetter_ContinuesWith_UnderScoreOrLetterOrDigit (state)
||
ScanningRules.IsContinuesCharsOfNumberOrPunctuationOrSymbolOrWhiteSpace (state)
?
ScanningActions.AppendCurrentChar
:
ScanningActions.YieldCurrentToken;
}
public static bool RequiresScanMethodChange (ScanningState state, ref ScanMethod scanMethod, out ScanningActions onScanMethodChange)
{
switch (state.CurrentInputChar)
{
case hashChar:
if (IsPreprocessing (state, ref scanMethod, out onScanMethodChange))
{
return true;
}
break;
case singleQuoteChar:
scanMethod = ScanMethod.EscapedChar;
onScanMethodChange = ScanningActions.YieldCurrentTokenAndSuppressCurrentChar;
return true;
case verbatimStringChar:
if (IsVerbatimString (state, ref scanMethod, out onScanMethodChange))
{
return true;
}
break;
case doubleQuoteChar:
scanMethod = ScanMethod.EscapedString;
onScanMethodChange = ScanningActions.YieldCurrentTokenAndSuppressCurrentChar;
return true;
case forwardSlashChar:
if (IsComment (state, ref scanMethod, out onScanMethodChange))
{
return true;
}
break;
}
if (NumberRecognizer.ShouldScanAsNumber (state))
{
scanMethod = ScanMethod.Number;
onScanMethodChange = ScanningActions.YieldCurrentToken;
return true;
}
if (SymbolRecognizer.ShouldScanAsSymbolOperator (state))
{
scanMethod = ScanMethod.SymbolOperator;
onScanMethodChange = ScanningActions.YieldCurrentToken;
return true;
}
onScanMethodChange = 0;
return false;
}
private static bool IsPreprocessing (ScanningState state, ref ScanMethod scanMethod, out ScanningActions onScanMethodChange)
{
if (state.CanPeekString (1, "define") && char.IsWhiteSpace (state.PeekInputChar (7) ?? 'x'))
{
state.InputIncrement = 7;
scanMethod = ScanMethod.PreprocessorDefine;
onScanMethodChange = ScanningActions.YieldCurrentTokenAndSuppressCurrentChar;
return true;
}
if (state.CanPeekString (1, "undef") && char.IsWhiteSpace (state.PeekInputChar (6) ?? 'x'))
{
state.InputIncrement = 6;
scanMethod = ScanMethod.PreprocessorUndefine;
onScanMethodChange = ScanningActions.YieldCurrentTokenAndSuppressCurrentChar;
return true;
}
if (state.CanPeekString (1, "region") && char.IsWhiteSpace (state.PeekInputChar (7) ?? 'x'))
{
state.InputIncrement = 7;
scanMethod = ScanMethod.PreprocessorRegion;
onScanMethodChange = ScanningActions.YieldCurrentTokenAndSuppressCurrentChar;
return true;
}
if (state.CanPeekString (1, "endregion") && char.IsWhiteSpace (state.PeekInputChar (10) ?? 'x'))
{
state.InputIncrement = 10;
scanMethod = ScanMethod.PreprocessorEndRegion;
onScanMethodChange = ScanningActions.YieldCurrentTokenAndSuppressCurrentChar;
return true;
}
scanMethod = ScanMethod.Preprocessor;
onScanMethodChange = ScanningActions.YieldCurrentToken;
return true;
}
private static bool IsVerbatimString (ScanningState state, ref ScanMethod scanMethod, out ScanningActions onScanMethodChange)
{
if (state.NextInputChar != doubleQuoteChar)
{
onScanMethodChange = 0;
return false;
}
state.InputIncrement = 2;
scanMethod = ScanMethod.VerbatimString;
onScanMethodChange = ScanningActions.YieldCurrentTokenAndSuppressCurrentChar;
return true;
}
private static bool IsComment (ScanningState state, ref ScanMethod scanMethod, out ScanningActions onScanMethodChange)
{
switch (state.NextInputChar)
{
case asterixChar:
state.InputIncrement = 2;
scanMethod = ScanMethod.MultiLineComment;
onScanMethodChange = ScanningActions.YieldCurrentTokenAndSuppressCurrentChar;
return true;
case forwardSlashChar:
if (state.PeekInputChar (2) == forwardSlashChar)
{
state.InputIncrement = 3;
scanMethod = ScanMethod.XmlComment;
onScanMethodChange = ScanningActions.YieldCurrentTokenAndSuppressCurrentChar;
return true;
}
state.InputIncrement = 2;
scanMethod = ScanMethod.SingleLineComment;
onScanMethodChange = ScanningActions.YieldCurrentTokenAndSuppressCurrentChar;
return true;
default:
onScanMethodChange = 0;
return false;
}
}
public static ScanningActions DetermineScanningActionInEscapedChar (ScanningState state, ref ScanMethod scanMethod)
{
var currentChar = state.CurrentInputChar;
if (currentChar == backSlashChar)
{
return EscapedCharRecognizer.DetermineScanningAction (state);
}
if (currentChar == singleQuoteChar)
{
scanMethod = ScanMethod.Default;
return ScanningActions.YieldCurrentTokenAndSuppressCurrentChar;
}
return ScanningActions.AppendCurrentChar;
}
public static ScanningActions DetermineScanningActionInEscapedString (ScanningState state, ref ScanMethod scanMethod)
{
var currentChar = state.CurrentInputChar;
if (currentChar == backSlashChar)
{
return EscapedCharRecognizer.DetermineScanningAction (state);
}
if (currentChar == doubleQuoteChar)
{
scanMethod = ScanMethod.Default;
return ScanningActions.YieldCurrentTokenAndSuppressCurrentChar;
}
return ScanningActions.AppendCurrentChar;
}
public static ScanningActions DetermineScanningActionInVerbatimString (ScanningState state, ref ScanMethod scanMethod)
{
var currentChar = state.CurrentInputChar;
if (currentChar == doubleQuoteChar)
{
if (state.NextInputChar == doubleQuoteChar)
{
state.InputIncrement = 2;
return ScanningActions.AppendCurrentChar;
}
else
{
scanMethod = ScanMethod.Default;
return ScanningActions.YieldCurrentTokenAndSuppressCurrentChar;
}
}
return ScanningActions.AppendCurrentChar;
}
public static ScanningActions DetermineScanningActionInMultiLineComment (ScanningState state, ref ScanMethod scanMethod)
{
if ((state.CurrentInputChar == asterixChar) && (state.NextInputChar == forwardSlashChar))
{
state.InputIncrement = 2;
scanMethod = ScanMethod.Default;
return ScanningActions.YieldCurrentTokenAndSuppressCurrentChar;
}
return ScanningActions.AppendCurrentChar;
}
public static ScanningActions DetermineScanningActionInXmlComment (ScanningState state, ref ScanMethod scanMethod)
{
if (ScanningRules.IsEndOfLine (state))
{
scanMethod = ScanMethod.Default;
return ScanningActions.YieldCurrentTokenAndSuppressCurrentChar;
}
return ScanningActions.AppendCurrentChar;
}
public static ScanningActions DetermineScanningActionInSymbolOperator (ScanningState state, ref ScanMethod scanMethod)
{
if (!SymbolRecognizer.ShouldYieldAsToken (state))
{
return ScanningActions.AppendCurrentChar;
}
scanMethod = ScanMethod.Default;
ScanningActions onScanMethodChange;
if (RequiresScanMethodChange (state, ref scanMethod, out onScanMethodChange))
{
return onScanMethodChange;
}
return ScanningActions.YieldCurrentToken;
}
protected override LexicalElements DetermineLexicalElement (string text, ScanMethod scanMethod)
{
if (string.IsNullOrWhiteSpace (text))
{
return LexicalElements.WhiteSpace;
}
switch (scanMethod)
{
case ScanMethod.PreprocessorDefine:
return LexicalElements.PreprocessorDefine;
case ScanMethod.PreprocessorUndefine:
return LexicalElements.PreprocessorUndefine;
case ScanMethod.PreprocessorRegion:
return LexicalElements.PreprocessorRegion;
case ScanMethod.PreprocessorEndRegion:
return LexicalElements.PreprocessorEndRegion;
case ScanMethod.EscapedChar:
return LexicalElements.CharValue;
case ScanMethod.EscapedString:
case ScanMethod.VerbatimString:
return LexicalElements.StringValue;
case ScanMethod.SingleLineComment:
case ScanMethod.MultiLineComment:
return LexicalElements.Comment;
case ScanMethod.XmlComment:
return LexicalElements.XmlComment;
case ScanMethod.Number:
if (text == ".")
{
break;
}
return LexicalElements.IntegerValue;
case ScanMethod.NumberReal:
return LexicalElements.RealValue;
}
LexicalElements recognized;
if (LiteralToElementRecognizer.TryDetermine (text, out recognized))
{
return recognized;
}
return LexicalElements.Unknown;
}
protected override bool IsTokenIgnored (Token token)
{
return token.LexicalElement == LexicalElements.WhiteSpace;
}
}
}
}