5769 lines
179 KiB
C#
5769 lines
179 KiB
C#
#define DEBUG
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using Microsoft.VisualBasic.CompilerServices;
|
|
|
|
namespace AspClassic.Parser;
|
|
|
|
/// <summary>
|
|
/// A parser for the Visual Basic .NET language based on the grammar
|
|
/// documented in the Language Specification.
|
|
/// </summary>
|
|
public sealed class Parser : IDisposable
|
|
{
|
|
private enum PrecedenceLevel
|
|
{
|
|
None,
|
|
Xor,
|
|
Or,
|
|
And,
|
|
Not,
|
|
Relational,
|
|
Shift,
|
|
Concatenate,
|
|
Plus,
|
|
Modulus,
|
|
IntegralDivide,
|
|
Multiply,
|
|
Negate,
|
|
Power,
|
|
Range
|
|
}
|
|
|
|
private sealed class ExternalSourceContext
|
|
{
|
|
public Location Start;
|
|
|
|
public string File;
|
|
|
|
public long Line;
|
|
}
|
|
|
|
private sealed class RegionContext
|
|
{
|
|
public Location Start;
|
|
|
|
public string Description;
|
|
}
|
|
|
|
private sealed class ConditionalCompilationContext
|
|
{
|
|
public bool BlockActive;
|
|
|
|
public bool AnyBlocksActive;
|
|
|
|
public bool SeenElse;
|
|
}
|
|
|
|
private Scanner Scanner;
|
|
|
|
private IList<SyntaxError> ErrorTable;
|
|
|
|
private IList<ExternalLineMapping> ExternalLineMappings;
|
|
|
|
private IList<SourceRegion> SourceRegions;
|
|
|
|
private IList<ExternalChecksum> ExternalChecksums;
|
|
|
|
private IDictionary<string, object> ConditionalCompilationConstants;
|
|
|
|
private bool ErrorInConstruct;
|
|
|
|
private bool AtBeginningOfLine;
|
|
|
|
private bool Preprocess;
|
|
|
|
private bool CanContinueWithoutLineTerminator;
|
|
|
|
private Stack<TreeType> BlockContextStack;
|
|
|
|
private ExternalSourceContext CurrentExternalSourceContext;
|
|
|
|
private Stack<RegionContext> RegionContextStack;
|
|
|
|
private Stack<ConditionalCompilationContext> ConditionalCompilationContextStack;
|
|
|
|
private bool Disposed;
|
|
|
|
public Parser()
|
|
{
|
|
BlockContextStack = new Stack<TreeType>();
|
|
RegionContextStack = new Stack<RegionContext>();
|
|
ConditionalCompilationContextStack = new Stack<ConditionalCompilationContext>();
|
|
Disposed = false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Disposes the parser.
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
if (!Disposed)
|
|
{
|
|
Disposed = true;
|
|
Scanner.Close();
|
|
}
|
|
}
|
|
|
|
void IDisposable.Dispose()
|
|
{
|
|
//ILSpy generated this explicit interface implementation from .override directive in Dispose
|
|
this.Dispose();
|
|
}
|
|
|
|
private Token Peek()
|
|
{
|
|
return Scanner.Peek();
|
|
}
|
|
|
|
private Token PeekAheadOne()
|
|
{
|
|
Token Start = Read();
|
|
Token NextToken = Peek();
|
|
Backtrack(Start);
|
|
return NextToken;
|
|
}
|
|
|
|
private TokenType PeekAheadFor(params TokenType[] tokens)
|
|
{
|
|
Token Start = Peek();
|
|
Token Current = Start;
|
|
while (!CanEndStatement(Current))
|
|
{
|
|
foreach (TokenType Token in tokens)
|
|
{
|
|
if (Current.AsUnreservedKeyword() == Token)
|
|
{
|
|
Backtrack(Start);
|
|
return Token;
|
|
}
|
|
}
|
|
Current = Read();
|
|
}
|
|
Backtrack(Start);
|
|
return TokenType.None;
|
|
}
|
|
|
|
private Token Read()
|
|
{
|
|
return Scanner.Read();
|
|
}
|
|
|
|
private Location ReadLocation()
|
|
{
|
|
return Read().Span.Start;
|
|
}
|
|
|
|
private void Backtrack(Token token)
|
|
{
|
|
Scanner.Seek(token);
|
|
}
|
|
|
|
private void ResyncAt(params TokenType[] tokenTypes)
|
|
{
|
|
Token CurrentToken = Peek();
|
|
while (CurrentToken.Type != TokenType.Colon && CurrentToken.Type != TokenType.EndOfStream && CurrentToken.Type != TokenType.LineTerminator && !BeginsStatement(CurrentToken))
|
|
{
|
|
foreach (TokenType TokenType in tokenTypes)
|
|
{
|
|
if (CurrentToken.Type == TokenType)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
Read();
|
|
CurrentToken = Peek();
|
|
}
|
|
}
|
|
|
|
private List<Comment> ParseTrailingComments()
|
|
{
|
|
List<Comment> Comments = new List<Comment>();
|
|
while (Peek().Type == TokenType.Comment)
|
|
{
|
|
CommentToken CommentToken = (CommentToken)Scanner.Read();
|
|
Comments.Add(new Comment(CommentToken.Comment, CommentToken.IsREM, CommentToken.Span));
|
|
}
|
|
if (Comments.Count > 0)
|
|
{
|
|
return Comments;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private void PushBlockContext(TreeType type)
|
|
{
|
|
BlockContextStack.Push(type);
|
|
}
|
|
|
|
private void PopBlockContext()
|
|
{
|
|
BlockContextStack.Pop();
|
|
}
|
|
|
|
private TreeType CurrentBlockContextType()
|
|
{
|
|
if (BlockContextStack.Count == 0)
|
|
{
|
|
return TreeType.SyntaxError;
|
|
}
|
|
return BlockContextStack.Peek();
|
|
}
|
|
|
|
private static OperatorType GetBinaryOperator(TokenType type, bool allowRange = false)
|
|
{
|
|
switch (type)
|
|
{
|
|
case TokenType.Ampersand:
|
|
return OperatorType.Concatenate;
|
|
case TokenType.Star:
|
|
return OperatorType.Multiply;
|
|
case TokenType.ForwardSlash:
|
|
return OperatorType.Divide;
|
|
case TokenType.BackwardSlash:
|
|
return OperatorType.IntegralDivide;
|
|
case TokenType.Caret:
|
|
return OperatorType.Power;
|
|
case TokenType.Plus:
|
|
return OperatorType.Plus;
|
|
case TokenType.Minus:
|
|
return OperatorType.Minus;
|
|
case TokenType.LessThan:
|
|
return OperatorType.LessThan;
|
|
case TokenType.LessThanEquals:
|
|
return OperatorType.LessThanEquals;
|
|
case TokenType.Equals:
|
|
return OperatorType.Equals;
|
|
case TokenType.NotEquals:
|
|
return OperatorType.NotEquals;
|
|
case TokenType.GreaterThan:
|
|
return OperatorType.GreaterThan;
|
|
case TokenType.GreaterThanEquals:
|
|
return OperatorType.GreaterThanEquals;
|
|
case TokenType.LessThanLessThan:
|
|
return OperatorType.ShiftLeft;
|
|
case TokenType.GreaterThanGreaterThan:
|
|
return OperatorType.ShiftRight;
|
|
case TokenType.Mod:
|
|
return OperatorType.Modulus;
|
|
case TokenType.Or:
|
|
return OperatorType.Or;
|
|
case TokenType.OrElse:
|
|
return OperatorType.OrElse;
|
|
case TokenType.And:
|
|
return OperatorType.And;
|
|
case TokenType.AndAlso:
|
|
return OperatorType.AndAlso;
|
|
case TokenType.Xor:
|
|
return OperatorType.Xor;
|
|
case TokenType.Like:
|
|
return OperatorType.Like;
|
|
case TokenType.Is:
|
|
return OperatorType.Is;
|
|
case TokenType.IsNot:
|
|
return OperatorType.IsNot;
|
|
case TokenType.To:
|
|
if (allowRange)
|
|
{
|
|
return OperatorType.To;
|
|
}
|
|
return OperatorType.None;
|
|
default:
|
|
return OperatorType.None;
|
|
}
|
|
}
|
|
|
|
private static PrecedenceLevel GetOperatorPrecedence(OperatorType @operator)
|
|
{
|
|
switch (@operator)
|
|
{
|
|
case OperatorType.To:
|
|
return PrecedenceLevel.Range;
|
|
case OperatorType.Power:
|
|
return PrecedenceLevel.Power;
|
|
case OperatorType.UnaryPlus:
|
|
case OperatorType.Negate:
|
|
return PrecedenceLevel.Negate;
|
|
case OperatorType.Multiply:
|
|
case OperatorType.Divide:
|
|
return PrecedenceLevel.Multiply;
|
|
case OperatorType.IntegralDivide:
|
|
return PrecedenceLevel.IntegralDivide;
|
|
case OperatorType.Modulus:
|
|
return PrecedenceLevel.Modulus;
|
|
case OperatorType.Plus:
|
|
case OperatorType.Minus:
|
|
return PrecedenceLevel.Plus;
|
|
case OperatorType.Concatenate:
|
|
return PrecedenceLevel.Concatenate;
|
|
case OperatorType.ShiftLeft:
|
|
case OperatorType.ShiftRight:
|
|
return PrecedenceLevel.Shift;
|
|
case OperatorType.Like:
|
|
case OperatorType.Is:
|
|
case OperatorType.IsNot:
|
|
case OperatorType.Equals:
|
|
case OperatorType.NotEquals:
|
|
case OperatorType.LessThan:
|
|
case OperatorType.LessThanEquals:
|
|
case OperatorType.GreaterThan:
|
|
case OperatorType.GreaterThanEquals:
|
|
return PrecedenceLevel.Relational;
|
|
case OperatorType.Not:
|
|
return PrecedenceLevel.Not;
|
|
case OperatorType.And:
|
|
case OperatorType.AndAlso:
|
|
return PrecedenceLevel.And;
|
|
case OperatorType.Or:
|
|
case OperatorType.OrElse:
|
|
return PrecedenceLevel.Or;
|
|
case OperatorType.Xor:
|
|
return PrecedenceLevel.Xor;
|
|
default:
|
|
return PrecedenceLevel.None;
|
|
}
|
|
}
|
|
|
|
private static OperatorType GetCompoundAssignmentOperatorType(TokenType tokenType)
|
|
{
|
|
return tokenType switch
|
|
{
|
|
TokenType.PlusEquals => OperatorType.Plus,
|
|
TokenType.AmpersandEquals => OperatorType.Concatenate,
|
|
TokenType.StarEquals => OperatorType.Multiply,
|
|
TokenType.MinusEquals => OperatorType.Minus,
|
|
TokenType.ForwardSlashEquals => OperatorType.Divide,
|
|
TokenType.BackwardSlashEquals => OperatorType.IntegralDivide,
|
|
TokenType.CaretEquals => OperatorType.Power,
|
|
TokenType.LessThanLessThanEquals => OperatorType.ShiftLeft,
|
|
TokenType.GreaterThanGreaterThanEquals => OperatorType.ShiftRight,
|
|
_ => OperatorType.None,
|
|
};
|
|
}
|
|
|
|
private static TreeType GetAssignmentOperator(TokenType tokenType)
|
|
{
|
|
switch (tokenType)
|
|
{
|
|
case TokenType.Equals:
|
|
return TreeType.AssignmentStatement;
|
|
case TokenType.AmpersandEquals:
|
|
case TokenType.StarEquals:
|
|
case TokenType.PlusEquals:
|
|
case TokenType.MinusEquals:
|
|
case TokenType.ForwardSlashEquals:
|
|
case TokenType.BackwardSlashEquals:
|
|
case TokenType.CaretEquals:
|
|
case TokenType.LessThanLessThanEquals:
|
|
case TokenType.GreaterThanGreaterThanEquals:
|
|
return TreeType.CompoundAssignmentStatement;
|
|
default:
|
|
return TreeType.SyntaxError;
|
|
}
|
|
}
|
|
|
|
private static bool IsRelationalOperator(TokenType type)
|
|
{
|
|
return type >= TokenType.LessThan && type <= TokenType.GreaterThanEquals;
|
|
}
|
|
|
|
private static bool IsOverloadableOperator(Token op)
|
|
{
|
|
switch (op.Type)
|
|
{
|
|
case TokenType.And:
|
|
case TokenType.CType:
|
|
case TokenType.Like:
|
|
case TokenType.Mod:
|
|
case TokenType.Not:
|
|
case TokenType.Or:
|
|
case TokenType.Xor:
|
|
case TokenType.Ampersand:
|
|
case TokenType.Star:
|
|
case TokenType.Plus:
|
|
case TokenType.Minus:
|
|
case TokenType.ForwardSlash:
|
|
case TokenType.BackwardSlash:
|
|
case TokenType.Caret:
|
|
case TokenType.LessThan:
|
|
case TokenType.LessThanEquals:
|
|
case TokenType.Equals:
|
|
case TokenType.NotEquals:
|
|
case TokenType.GreaterThan:
|
|
case TokenType.GreaterThanEquals:
|
|
case TokenType.LessThanLessThan:
|
|
case TokenType.GreaterThanGreaterThan:
|
|
return true;
|
|
case TokenType.Identifier:
|
|
if (op.AsUnreservedKeyword() == TokenType.IsTrue || op.AsUnreservedKeyword() == TokenType.IsFalse)
|
|
{
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static BlockType GetContinueType(TokenType tokenType)
|
|
{
|
|
return tokenType switch
|
|
{
|
|
TokenType.Do => BlockType.Do,
|
|
TokenType.For => BlockType.For,
|
|
TokenType.While => BlockType.While,
|
|
_ => BlockType.None,
|
|
};
|
|
}
|
|
|
|
private static BlockType GetExitType(TokenType tokenType)
|
|
{
|
|
return tokenType switch
|
|
{
|
|
TokenType.Do => BlockType.Do,
|
|
TokenType.For => BlockType.For,
|
|
TokenType.While => BlockType.While,
|
|
TokenType.Select => BlockType.Select,
|
|
TokenType.Sub => BlockType.Sub,
|
|
TokenType.Function => BlockType.Function,
|
|
TokenType.Property => BlockType.Property,
|
|
TokenType.Try => BlockType.Try,
|
|
_ => BlockType.None,
|
|
};
|
|
}
|
|
|
|
private static BlockType GetBlockType(TokenType type)
|
|
{
|
|
return type switch
|
|
{
|
|
TokenType.While => BlockType.While,
|
|
TokenType.Select => BlockType.Select,
|
|
TokenType.If => BlockType.If,
|
|
TokenType.Try => BlockType.Try,
|
|
TokenType.SyncLock => BlockType.SyncLock,
|
|
TokenType.Using => BlockType.Using,
|
|
TokenType.With => BlockType.With,
|
|
TokenType.Sub => BlockType.Sub,
|
|
TokenType.Function => BlockType.Function,
|
|
TokenType.Operator => BlockType.Operator,
|
|
TokenType.Get => BlockType.Get,
|
|
TokenType.Set => BlockType.Set,
|
|
TokenType.Event => BlockType.Event,
|
|
TokenType.AddHandler => BlockType.AddHandler,
|
|
TokenType.RemoveHandler => BlockType.RemoveHandler,
|
|
TokenType.RaiseEvent => BlockType.RaiseEvent,
|
|
TokenType.Property => BlockType.Property,
|
|
TokenType.Class => BlockType.Class,
|
|
TokenType.Structure => BlockType.Structure,
|
|
TokenType.Module => BlockType.Module,
|
|
TokenType.Interface => BlockType.Interface,
|
|
TokenType.Enum => BlockType.Enum,
|
|
TokenType.Namespace => BlockType.Namespace,
|
|
_ => BlockType.None,
|
|
};
|
|
}
|
|
|
|
private void ReportSyntaxError(SyntaxError syntaxError)
|
|
{
|
|
if (!ErrorInConstruct)
|
|
{
|
|
ErrorInConstruct = true;
|
|
if (ErrorTable != null)
|
|
{
|
|
ErrorTable.Add(syntaxError);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ReportSyntaxError(SyntaxErrorType errorType, Span span)
|
|
{
|
|
ReportSyntaxError(new SyntaxError(errorType, span));
|
|
}
|
|
|
|
private void ReportSyntaxError(SyntaxErrorType errorType, Token firstToken, Token lastToken)
|
|
{
|
|
if (firstToken.Type == TokenType.LexicalError)
|
|
{
|
|
ReportSyntaxError(((ErrorToken)firstToken).SyntaxError);
|
|
}
|
|
else
|
|
{
|
|
ReportSyntaxError(errorType, SpanFrom(firstToken, lastToken));
|
|
}
|
|
}
|
|
|
|
private void ReportSyntaxError(SyntaxErrorType errorType, Token token)
|
|
{
|
|
ReportSyntaxError(errorType, token, token);
|
|
}
|
|
|
|
private static bool StatementEndsBlock(TreeType blockStatementType, Statement endStatement)
|
|
{
|
|
switch (blockStatementType)
|
|
{
|
|
case TreeType.DoBlockStatement:
|
|
return endStatement.Type == TreeType.LoopStatement;
|
|
case TreeType.ForBlockStatement:
|
|
case TreeType.ForEachBlockStatement:
|
|
return endStatement.Type == TreeType.NextStatement;
|
|
case TreeType.WhileBlockStatement:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.While;
|
|
case TreeType.SyncLockBlockStatement:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.SyncLock;
|
|
case TreeType.UsingBlockStatement:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.Using;
|
|
case TreeType.WithBlockStatement:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.With;
|
|
case TreeType.TryBlockStatement:
|
|
case TreeType.CatchBlockStatement:
|
|
return endStatement.Type == TreeType.CatchStatement || endStatement.Type == TreeType.FinallyStatement || (endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.Try);
|
|
case TreeType.FinallyBlockStatement:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.Try;
|
|
case TreeType.SelectBlockStatement:
|
|
case TreeType.CaseBlockStatement:
|
|
return endStatement.Type == TreeType.CaseStatement || endStatement.Type == TreeType.CaseElseStatement || (endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.Select);
|
|
case TreeType.CaseElseBlockStatement:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.Select;
|
|
case TreeType.IfBlockStatement:
|
|
case TreeType.ElseIfBlockStatement:
|
|
return endStatement.Type == TreeType.ElseIfStatement || endStatement.Type == TreeType.ElseStatement || (endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.If);
|
|
case TreeType.ElseBlockStatement:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.If;
|
|
case TreeType.LineIfBlockStatement:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.If;
|
|
case TreeType.SubDeclaration:
|
|
case TreeType.ConstructorDeclaration:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.Sub;
|
|
case TreeType.FunctionDeclaration:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.Function;
|
|
case TreeType.OperatorDeclaration:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.Operator;
|
|
case TreeType.GetAccessorDeclaration:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.Get;
|
|
case TreeType.SetAccessorDeclaration:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.Set;
|
|
case TreeType.PropertyDeclaration:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.Property;
|
|
case TreeType.CustomEventDeclaration:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.Event;
|
|
case TreeType.AddHandlerAccessorDeclaration:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.AddHandler;
|
|
case TreeType.RemoveHandlerAccessorDeclaration:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.RemoveHandler;
|
|
case TreeType.RaiseEventAccessorDeclaration:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.RaiseEvent;
|
|
case TreeType.ClassDeclaration:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.Class;
|
|
case TreeType.StructureDeclaration:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.Structure;
|
|
case TreeType.ModuleDeclaration:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.Module;
|
|
case TreeType.InterfaceDeclaration:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.Interface;
|
|
case TreeType.EnumDeclaration:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.Enum;
|
|
case TreeType.NamespaceDeclaration:
|
|
return endStatement.Type == TreeType.EndBlockStatement && ((EndBlockStatement)endStatement).EndType == BlockType.Namespace;
|
|
default:
|
|
Debug.Assert(condition: false, "Unexpected.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static bool DeclarationEndsBlock(TreeType blockDeclarationType, EndBlockDeclaration endDeclaration)
|
|
{
|
|
switch (blockDeclarationType)
|
|
{
|
|
case TreeType.SubDeclaration:
|
|
case TreeType.ConstructorDeclaration:
|
|
return endDeclaration.EndType == BlockType.Sub;
|
|
case TreeType.FunctionDeclaration:
|
|
return endDeclaration.EndType == BlockType.Function;
|
|
case TreeType.OperatorDeclaration:
|
|
return endDeclaration.EndType == BlockType.Operator;
|
|
case TreeType.PropertyDeclaration:
|
|
return endDeclaration.EndType == BlockType.Property;
|
|
case TreeType.GetAccessorDeclaration:
|
|
return endDeclaration.EndType == BlockType.Get;
|
|
case TreeType.SetAccessorDeclaration:
|
|
return endDeclaration.EndType == BlockType.Set;
|
|
case TreeType.CustomEventDeclaration:
|
|
return endDeclaration.EndType == BlockType.Event;
|
|
case TreeType.AddHandlerAccessorDeclaration:
|
|
return endDeclaration.EndType == BlockType.AddHandler;
|
|
case TreeType.RemoveHandlerAccessorDeclaration:
|
|
return endDeclaration.EndType == BlockType.RemoveHandler;
|
|
case TreeType.RaiseEventAccessorDeclaration:
|
|
return endDeclaration.EndType == BlockType.RaiseEvent;
|
|
case TreeType.ClassDeclaration:
|
|
return endDeclaration.EndType == BlockType.Class;
|
|
case TreeType.StructureDeclaration:
|
|
return endDeclaration.EndType == BlockType.Structure;
|
|
case TreeType.ModuleDeclaration:
|
|
return endDeclaration.EndType == BlockType.Module;
|
|
case TreeType.InterfaceDeclaration:
|
|
return endDeclaration.EndType == BlockType.Interface;
|
|
case TreeType.EnumDeclaration:
|
|
return endDeclaration.EndType == BlockType.Enum;
|
|
case TreeType.NamespaceDeclaration:
|
|
return endDeclaration.EndType == BlockType.Namespace;
|
|
default:
|
|
Debug.Assert(condition: false, "Unexpected.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static bool ValidInContext(TreeType blockType, TreeType declarationType)
|
|
{
|
|
switch (declarationType)
|
|
{
|
|
case TreeType.ImportsDeclaration:
|
|
case TreeType.OptionDeclaration:
|
|
case TreeType.AttributeDeclaration:
|
|
return blockType == TreeType.File;
|
|
case TreeType.NamespaceDeclaration:
|
|
return blockType == TreeType.NamespaceDeclaration || blockType == TreeType.File;
|
|
case TreeType.ClassDeclaration:
|
|
case TreeType.StructureDeclaration:
|
|
case TreeType.InterfaceDeclaration:
|
|
case TreeType.EnumDeclaration:
|
|
case TreeType.DelegateSubDeclaration:
|
|
case TreeType.DelegateFunctionDeclaration:
|
|
return blockType == TreeType.ClassDeclaration || blockType == TreeType.StructureDeclaration || blockType == TreeType.ModuleDeclaration || blockType == TreeType.InterfaceDeclaration || blockType == TreeType.NamespaceDeclaration || blockType == TreeType.File;
|
|
case TreeType.ModuleDeclaration:
|
|
return blockType == TreeType.NamespaceDeclaration || blockType == TreeType.File;
|
|
case TreeType.SubDeclaration:
|
|
case TreeType.FunctionDeclaration:
|
|
case TreeType.PropertyDeclaration:
|
|
case TreeType.EventDeclaration:
|
|
return blockType == TreeType.ClassDeclaration || blockType == TreeType.StructureDeclaration || blockType == TreeType.ModuleDeclaration || blockType == TreeType.InterfaceDeclaration;
|
|
case TreeType.CustomEventDeclaration:
|
|
return blockType == TreeType.ClassDeclaration || blockType == TreeType.StructureDeclaration || blockType == TreeType.ModuleDeclaration;
|
|
case TreeType.AddHandlerAccessorDeclaration:
|
|
case TreeType.RemoveHandlerAccessorDeclaration:
|
|
case TreeType.RaiseEventAccessorDeclaration:
|
|
return blockType == TreeType.CustomEventDeclaration;
|
|
case TreeType.OperatorDeclaration:
|
|
return blockType == TreeType.ClassDeclaration || blockType == TreeType.StructureDeclaration;
|
|
case TreeType.VariableListDeclaration:
|
|
case TreeType.ExternalSubDeclaration:
|
|
case TreeType.ExternalFunctionDeclaration:
|
|
return blockType == TreeType.ClassDeclaration || blockType == TreeType.StructureDeclaration || blockType == TreeType.ModuleDeclaration;
|
|
case TreeType.ConstructorDeclaration:
|
|
return blockType == TreeType.ClassDeclaration || blockType == TreeType.StructureDeclaration;
|
|
case TreeType.GetAccessorDeclaration:
|
|
case TreeType.SetAccessorDeclaration:
|
|
return blockType == TreeType.PropertyDeclaration;
|
|
case TreeType.InheritsDeclaration:
|
|
return blockType == TreeType.ClassDeclaration || blockType == TreeType.InterfaceDeclaration;
|
|
case TreeType.ImplementsDeclaration:
|
|
return blockType == TreeType.ClassDeclaration || blockType == TreeType.StructureDeclaration;
|
|
case TreeType.EnumValueDeclaration:
|
|
return blockType == TreeType.EnumDeclaration;
|
|
case TreeType.EmptyDeclaration:
|
|
return true;
|
|
default:
|
|
{
|
|
Debug.Assert(condition: false, "Unexpected.");
|
|
bool ValidInContext = default(bool);
|
|
return ValidInContext;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static SyntaxErrorType ValidDeclaration(TreeType blockType, Declaration declaration, List<Declaration> declarations)
|
|
{
|
|
if (!ValidInContext(blockType, declaration.Type))
|
|
{
|
|
return InvalidDeclarationTypeError(blockType);
|
|
}
|
|
if (declaration.Type == TreeType.InheritsDeclaration)
|
|
{
|
|
foreach (Declaration ExistingDeclaration in declarations)
|
|
{
|
|
if (blockType == TreeType.ClassDeclaration || ExistingDeclaration.Type != TreeType.InheritsDeclaration)
|
|
{
|
|
return SyntaxErrorType.InheritsMustBeFirst;
|
|
}
|
|
}
|
|
if (((InheritsDeclaration)declaration).InheritedTypes.Count > 1 && blockType != TreeType.InterfaceDeclaration)
|
|
{
|
|
return SyntaxErrorType.NoMultipleInheritance;
|
|
}
|
|
}
|
|
if (declaration.Type == TreeType.ImplementsDeclaration)
|
|
{
|
|
foreach (Declaration ExistingDeclaration5 in declarations)
|
|
{
|
|
if (ExistingDeclaration5.Type != TreeType.InheritsDeclaration && ExistingDeclaration5.Type != TreeType.ImplementsDeclaration)
|
|
{
|
|
return SyntaxErrorType.ImplementsInWrongOrder;
|
|
}
|
|
}
|
|
}
|
|
if (declaration.Type == TreeType.OptionDeclaration)
|
|
{
|
|
foreach (Declaration ExistingDeclaration4 in declarations)
|
|
{
|
|
if (ExistingDeclaration4.Type != TreeType.OptionDeclaration)
|
|
{
|
|
return SyntaxErrorType.OptionStatementWrongOrder;
|
|
}
|
|
}
|
|
}
|
|
if (declaration.Type == TreeType.ImportsDeclaration)
|
|
{
|
|
foreach (Declaration ExistingDeclaration3 in declarations)
|
|
{
|
|
if (ExistingDeclaration3.Type != TreeType.OptionDeclaration && ExistingDeclaration3.Type != TreeType.ImportsDeclaration)
|
|
{
|
|
return SyntaxErrorType.ImportsStatementWrongOrder;
|
|
}
|
|
}
|
|
}
|
|
if (declaration.Type == TreeType.AttributeDeclaration)
|
|
{
|
|
foreach (Declaration ExistingDeclaration2 in declarations)
|
|
{
|
|
if (ExistingDeclaration2.Type != TreeType.OptionDeclaration && ExistingDeclaration2.Type != TreeType.ImportsDeclaration && ExistingDeclaration2.Type != TreeType.AttributeDeclaration)
|
|
{
|
|
return SyntaxErrorType.AttributesStatementWrongOrder;
|
|
}
|
|
}
|
|
}
|
|
return SyntaxErrorType.None;
|
|
}
|
|
|
|
private void ReportMismatchedEndError(TreeType blockType, Span actualEndSpan)
|
|
{
|
|
SyntaxErrorType ErrorType = default(SyntaxErrorType);
|
|
switch (blockType)
|
|
{
|
|
case TreeType.DoBlockStatement:
|
|
ErrorType = SyntaxErrorType.ExpectedLoop;
|
|
break;
|
|
case TreeType.ForBlockStatement:
|
|
case TreeType.ForEachBlockStatement:
|
|
ErrorType = SyntaxErrorType.ExpectedNext;
|
|
break;
|
|
case TreeType.WhileBlockStatement:
|
|
ErrorType = SyntaxErrorType.ExpectedEndWhile;
|
|
break;
|
|
case TreeType.SelectBlockStatement:
|
|
case TreeType.CaseBlockStatement:
|
|
case TreeType.CaseElseBlockStatement:
|
|
ErrorType = SyntaxErrorType.ExpectedEndSelect;
|
|
break;
|
|
case TreeType.SyncLockBlockStatement:
|
|
ErrorType = SyntaxErrorType.ExpectedEndSyncLock;
|
|
break;
|
|
case TreeType.UsingBlockStatement:
|
|
ErrorType = SyntaxErrorType.ExpectedEndUsing;
|
|
break;
|
|
case TreeType.IfBlockStatement:
|
|
case TreeType.ElseIfBlockStatement:
|
|
case TreeType.ElseBlockStatement:
|
|
ErrorType = SyntaxErrorType.ExpectedEndIf;
|
|
break;
|
|
case TreeType.TryBlockStatement:
|
|
case TreeType.CatchBlockStatement:
|
|
case TreeType.FinallyBlockStatement:
|
|
ErrorType = SyntaxErrorType.ExpectedEndTry;
|
|
break;
|
|
case TreeType.WithBlockStatement:
|
|
ErrorType = SyntaxErrorType.ExpectedEndWith;
|
|
break;
|
|
case TreeType.SubDeclaration:
|
|
case TreeType.ConstructorDeclaration:
|
|
ErrorType = SyntaxErrorType.ExpectedEndSub;
|
|
break;
|
|
case TreeType.FunctionDeclaration:
|
|
ErrorType = SyntaxErrorType.ExpectedEndFunction;
|
|
break;
|
|
case TreeType.OperatorDeclaration:
|
|
ErrorType = SyntaxErrorType.ExpectedEndOperator;
|
|
break;
|
|
case TreeType.PropertyDeclaration:
|
|
ErrorType = SyntaxErrorType.ExpectedEndProperty;
|
|
break;
|
|
case TreeType.GetAccessorDeclaration:
|
|
ErrorType = SyntaxErrorType.ExpectedEndGet;
|
|
break;
|
|
case TreeType.SetAccessorDeclaration:
|
|
ErrorType = SyntaxErrorType.ExpectedEndSet;
|
|
break;
|
|
case TreeType.CustomEventDeclaration:
|
|
ErrorType = SyntaxErrorType.ExpectedEndEvent;
|
|
break;
|
|
case TreeType.AddHandlerAccessorDeclaration:
|
|
ErrorType = SyntaxErrorType.ExpectedEndAddHandler;
|
|
break;
|
|
case TreeType.RemoveHandlerAccessorDeclaration:
|
|
ErrorType = SyntaxErrorType.ExpectedEndRemoveHandler;
|
|
break;
|
|
case TreeType.RaiseEventAccessorDeclaration:
|
|
ErrorType = SyntaxErrorType.ExpectedEndRaiseEvent;
|
|
break;
|
|
case TreeType.ClassDeclaration:
|
|
ErrorType = SyntaxErrorType.ExpectedEndClass;
|
|
break;
|
|
case TreeType.StructureDeclaration:
|
|
ErrorType = SyntaxErrorType.ExpectedEndStructure;
|
|
break;
|
|
case TreeType.ModuleDeclaration:
|
|
ErrorType = SyntaxErrorType.ExpectedEndModule;
|
|
break;
|
|
case TreeType.InterfaceDeclaration:
|
|
ErrorType = SyntaxErrorType.ExpectedEndInterface;
|
|
break;
|
|
case TreeType.EnumDeclaration:
|
|
ErrorType = SyntaxErrorType.ExpectedEndEnum;
|
|
break;
|
|
case TreeType.NamespaceDeclaration:
|
|
ErrorType = SyntaxErrorType.ExpectedEndNamespace;
|
|
break;
|
|
default:
|
|
Debug.Assert(condition: false, "Unexpected.");
|
|
break;
|
|
}
|
|
ReportSyntaxError(ErrorType, actualEndSpan);
|
|
}
|
|
|
|
private void ReportMissingBeginStatementError(TreeType blockStatementType, Statement endStatement)
|
|
{
|
|
SyntaxErrorType ErrorType = default(SyntaxErrorType);
|
|
switch (endStatement.Type)
|
|
{
|
|
case TreeType.LoopStatement:
|
|
ErrorType = SyntaxErrorType.LoopWithoutDo;
|
|
break;
|
|
case TreeType.NextStatement:
|
|
ErrorType = SyntaxErrorType.NextWithoutFor;
|
|
break;
|
|
case TreeType.EndBlockStatement:
|
|
switch (((EndBlockStatement)endStatement).EndType)
|
|
{
|
|
case BlockType.While:
|
|
ErrorType = SyntaxErrorType.EndWhileWithoutWhile;
|
|
break;
|
|
case BlockType.Select:
|
|
ErrorType = SyntaxErrorType.EndSelectWithoutSelect;
|
|
break;
|
|
case BlockType.SyncLock:
|
|
ErrorType = SyntaxErrorType.EndSyncLockWithoutSyncLock;
|
|
break;
|
|
case BlockType.Using:
|
|
ErrorType = SyntaxErrorType.EndUsingWithoutUsing;
|
|
break;
|
|
case BlockType.If:
|
|
ErrorType = SyntaxErrorType.EndIfWithoutIf;
|
|
break;
|
|
case BlockType.Try:
|
|
ErrorType = SyntaxErrorType.EndTryWithoutTry;
|
|
break;
|
|
case BlockType.With:
|
|
ErrorType = SyntaxErrorType.EndWithWithoutWith;
|
|
break;
|
|
case BlockType.Sub:
|
|
ErrorType = SyntaxErrorType.EndSubWithoutSub;
|
|
break;
|
|
case BlockType.Function:
|
|
ErrorType = SyntaxErrorType.EndFunctionWithoutFunction;
|
|
break;
|
|
case BlockType.Operator:
|
|
ErrorType = SyntaxErrorType.EndOperatorWithoutOperator;
|
|
break;
|
|
case BlockType.Get:
|
|
ErrorType = SyntaxErrorType.EndGetWithoutGet;
|
|
break;
|
|
case BlockType.Set:
|
|
ErrorType = SyntaxErrorType.EndSetWithoutSet;
|
|
break;
|
|
case BlockType.Property:
|
|
ErrorType = SyntaxErrorType.EndPropertyWithoutProperty;
|
|
break;
|
|
case BlockType.Event:
|
|
ErrorType = SyntaxErrorType.EndEventWithoutEvent;
|
|
break;
|
|
case BlockType.AddHandler:
|
|
ErrorType = SyntaxErrorType.EndAddHandlerWithoutAddHandler;
|
|
break;
|
|
case BlockType.RemoveHandler:
|
|
ErrorType = SyntaxErrorType.EndRemoveHandlerWithoutRemoveHandler;
|
|
break;
|
|
case BlockType.RaiseEvent:
|
|
ErrorType = SyntaxErrorType.EndRaiseEventWithoutRaiseEvent;
|
|
break;
|
|
case BlockType.Class:
|
|
ErrorType = SyntaxErrorType.EndClassWithoutClass;
|
|
break;
|
|
case BlockType.Structure:
|
|
ErrorType = SyntaxErrorType.EndStructureWithoutStructure;
|
|
break;
|
|
case BlockType.Module:
|
|
ErrorType = SyntaxErrorType.EndModuleWithoutModule;
|
|
break;
|
|
case BlockType.Interface:
|
|
ErrorType = SyntaxErrorType.EndInterfaceWithoutInterface;
|
|
break;
|
|
case BlockType.Enum:
|
|
ErrorType = SyntaxErrorType.EndEnumWithoutEnum;
|
|
break;
|
|
case BlockType.Namespace:
|
|
ErrorType = SyntaxErrorType.EndNamespaceWithoutNamespace;
|
|
break;
|
|
default:
|
|
Debug.Assert(condition: false, "Unexpected.");
|
|
break;
|
|
}
|
|
break;
|
|
case TreeType.CatchStatement:
|
|
ErrorType = ((blockStatementType != TreeType.FinallyBlockStatement) ? SyntaxErrorType.CatchWithoutTry : SyntaxErrorType.CatchAfterFinally);
|
|
break;
|
|
case TreeType.FinallyStatement:
|
|
ErrorType = ((blockStatementType != TreeType.FinallyBlockStatement) ? SyntaxErrorType.FinallyWithoutTry : SyntaxErrorType.FinallyAfterFinally);
|
|
break;
|
|
case TreeType.CaseStatement:
|
|
ErrorType = ((blockStatementType != TreeType.CaseElseBlockStatement) ? SyntaxErrorType.CaseWithoutSelect : SyntaxErrorType.CaseAfterCaseElse);
|
|
break;
|
|
case TreeType.CaseElseStatement:
|
|
ErrorType = ((blockStatementType != TreeType.CaseElseBlockStatement) ? SyntaxErrorType.CaseElseWithoutSelect : SyntaxErrorType.CaseElseAfterCaseElse);
|
|
break;
|
|
case TreeType.ElseIfStatement:
|
|
ErrorType = ((blockStatementType != TreeType.ElseBlockStatement) ? SyntaxErrorType.ElseIfWithoutIf : SyntaxErrorType.ElseIfAfterElse);
|
|
break;
|
|
case TreeType.ElseStatement:
|
|
ErrorType = ((blockStatementType != TreeType.ElseBlockStatement) ? SyntaxErrorType.ElseWithoutIf : SyntaxErrorType.ElseAfterElse);
|
|
break;
|
|
default:
|
|
Debug.Assert(condition: false, "Unexpected.");
|
|
break;
|
|
}
|
|
ReportSyntaxError(ErrorType, endStatement.Span);
|
|
}
|
|
|
|
private void ReportMissingBeginDeclarationError(EndBlockDeclaration endDeclaration)
|
|
{
|
|
SyntaxErrorType ErrorType = default(SyntaxErrorType);
|
|
switch (endDeclaration.EndType)
|
|
{
|
|
case BlockType.Sub:
|
|
ErrorType = SyntaxErrorType.EndSubWithoutSub;
|
|
break;
|
|
case BlockType.Function:
|
|
ErrorType = SyntaxErrorType.EndFunctionWithoutFunction;
|
|
break;
|
|
case BlockType.Operator:
|
|
ErrorType = SyntaxErrorType.EndOperatorWithoutOperator;
|
|
break;
|
|
case BlockType.Property:
|
|
ErrorType = SyntaxErrorType.EndPropertyWithoutProperty;
|
|
break;
|
|
case BlockType.Get:
|
|
ErrorType = SyntaxErrorType.EndGetWithoutGet;
|
|
break;
|
|
case BlockType.Set:
|
|
ErrorType = SyntaxErrorType.EndSetWithoutSet;
|
|
break;
|
|
case BlockType.Event:
|
|
ErrorType = SyntaxErrorType.EndEventWithoutEvent;
|
|
break;
|
|
case BlockType.AddHandler:
|
|
ErrorType = SyntaxErrorType.EndAddHandlerWithoutAddHandler;
|
|
break;
|
|
case BlockType.RemoveHandler:
|
|
ErrorType = SyntaxErrorType.EndRemoveHandlerWithoutRemoveHandler;
|
|
break;
|
|
case BlockType.RaiseEvent:
|
|
ErrorType = SyntaxErrorType.EndRaiseEventWithoutRaiseEvent;
|
|
break;
|
|
case BlockType.Class:
|
|
ErrorType = SyntaxErrorType.EndClassWithoutClass;
|
|
break;
|
|
case BlockType.Structure:
|
|
ErrorType = SyntaxErrorType.EndStructureWithoutStructure;
|
|
break;
|
|
case BlockType.Module:
|
|
ErrorType = SyntaxErrorType.EndModuleWithoutModule;
|
|
break;
|
|
case BlockType.Interface:
|
|
ErrorType = SyntaxErrorType.EndInterfaceWithoutInterface;
|
|
break;
|
|
case BlockType.Enum:
|
|
ErrorType = SyntaxErrorType.EndEnumWithoutEnum;
|
|
break;
|
|
case BlockType.Namespace:
|
|
ErrorType = SyntaxErrorType.EndNamespaceWithoutNamespace;
|
|
break;
|
|
default:
|
|
Debug.Assert(condition: false, "Unexpected.");
|
|
break;
|
|
}
|
|
ReportSyntaxError(ErrorType, endDeclaration.Span);
|
|
}
|
|
|
|
private static SyntaxErrorType InvalidDeclarationTypeError(TreeType blockType)
|
|
{
|
|
switch (blockType)
|
|
{
|
|
case TreeType.PropertyDeclaration:
|
|
return SyntaxErrorType.InvalidInsideProperty;
|
|
case TreeType.ClassDeclaration:
|
|
return SyntaxErrorType.InvalidInsideClass;
|
|
case TreeType.StructureDeclaration:
|
|
return SyntaxErrorType.InvalidInsideStructure;
|
|
case TreeType.ModuleDeclaration:
|
|
return SyntaxErrorType.InvalidInsideModule;
|
|
case TreeType.InterfaceDeclaration:
|
|
return SyntaxErrorType.InvalidInsideInterface;
|
|
case TreeType.EnumDeclaration:
|
|
return SyntaxErrorType.InvalidInsideEnum;
|
|
case TreeType.NamespaceDeclaration:
|
|
case TreeType.File:
|
|
return SyntaxErrorType.InvalidInsideNamespace;
|
|
default:
|
|
{
|
|
Debug.Assert(condition: false, "Unexpected.");
|
|
SyntaxErrorType ErrorType = default(SyntaxErrorType);
|
|
return ErrorType;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void HandleUnexpectedToken(TokenType type)
|
|
{
|
|
SyntaxErrorType ErrorType;
|
|
switch (type)
|
|
{
|
|
case TokenType.Comma:
|
|
ErrorType = SyntaxErrorType.ExpectedComma;
|
|
break;
|
|
case TokenType.LeftParenthesis:
|
|
ErrorType = SyntaxErrorType.ExpectedLeftParenthesis;
|
|
break;
|
|
case TokenType.RightParenthesis:
|
|
ErrorType = SyntaxErrorType.ExpectedRightParenthesis;
|
|
break;
|
|
case TokenType.Equals:
|
|
ErrorType = SyntaxErrorType.ExpectedEquals;
|
|
break;
|
|
case TokenType.As:
|
|
ErrorType = SyntaxErrorType.ExpectedAs;
|
|
break;
|
|
case TokenType.RightCurlyBrace:
|
|
ErrorType = SyntaxErrorType.ExpectedRightCurlyBrace;
|
|
break;
|
|
case TokenType.Period:
|
|
ErrorType = SyntaxErrorType.ExpectedPeriod;
|
|
break;
|
|
case TokenType.Minus:
|
|
ErrorType = SyntaxErrorType.ExpectedMinus;
|
|
break;
|
|
case TokenType.Is:
|
|
ErrorType = SyntaxErrorType.ExpectedIs;
|
|
break;
|
|
case TokenType.GreaterThan:
|
|
ErrorType = SyntaxErrorType.ExpectedGreaterThan;
|
|
break;
|
|
case TokenType.Of:
|
|
ErrorType = SyntaxErrorType.ExpectedOf;
|
|
break;
|
|
default:
|
|
Debug.Assert(condition: false, "Should give a more specific error.");
|
|
ErrorType = SyntaxErrorType.SyntaxError;
|
|
break;
|
|
}
|
|
ReportSyntaxError(ErrorType, Peek());
|
|
}
|
|
|
|
private Location VerifyExpectedToken(TokenType type)
|
|
{
|
|
Token Token = Peek();
|
|
if (Token.Type == type)
|
|
{
|
|
return ReadLocation();
|
|
}
|
|
HandleUnexpectedToken(type);
|
|
return default(Location);
|
|
}
|
|
|
|
private bool CanEndStatement(Token token)
|
|
{
|
|
return token.Type == TokenType.Colon || token.Type == TokenType.LineTerminator || token.Type == TokenType.EndOfStream || token.Type == TokenType.Comment || (BlockContextStack.Count > 0 && CurrentBlockContextType() == TreeType.LineIfBlockStatement && token.Type == TokenType.Else);
|
|
}
|
|
|
|
private bool BeginsStatement(Token token)
|
|
{
|
|
if (!CanEndStatement(token))
|
|
{
|
|
return false;
|
|
}
|
|
switch (token.Type)
|
|
{
|
|
case TokenType.AddHandler:
|
|
case TokenType.Call:
|
|
case TokenType.Case:
|
|
case TokenType.Catch:
|
|
case TokenType.Class:
|
|
case TokenType.Const:
|
|
case TokenType.Declare:
|
|
case TokenType.Delegate:
|
|
case TokenType.Dim:
|
|
case TokenType.Do:
|
|
case TokenType.Else:
|
|
case TokenType.ElseIf:
|
|
case TokenType.End:
|
|
case TokenType.EndIf:
|
|
case TokenType.Enum:
|
|
case TokenType.Erase:
|
|
case TokenType.Error:
|
|
case TokenType.Event:
|
|
case TokenType.Exit:
|
|
case TokenType.Finally:
|
|
case TokenType.For:
|
|
case TokenType.Friend:
|
|
case TokenType.Function:
|
|
case TokenType.Get:
|
|
case TokenType.GoSub:
|
|
case TokenType.GoTo:
|
|
case TokenType.If:
|
|
case TokenType.Implements:
|
|
case TokenType.Imports:
|
|
case TokenType.Inherits:
|
|
case TokenType.Interface:
|
|
case TokenType.Loop:
|
|
case TokenType.Module:
|
|
case TokenType.MustInherit:
|
|
case TokenType.MustOverride:
|
|
case TokenType.Namespace:
|
|
case TokenType.Narrowing:
|
|
case TokenType.Next:
|
|
case TokenType.NotInheritable:
|
|
case TokenType.NotOverridable:
|
|
case TokenType.Option:
|
|
case TokenType.Overloads:
|
|
case TokenType.Overridable:
|
|
case TokenType.Overrides:
|
|
case TokenType.Partial:
|
|
case TokenType.Private:
|
|
case TokenType.Property:
|
|
case TokenType.Protected:
|
|
case TokenType.Public:
|
|
case TokenType.RaiseEvent:
|
|
case TokenType.ReadOnly:
|
|
case TokenType.ReDim:
|
|
case TokenType.RemoveHandler:
|
|
case TokenType.Resume:
|
|
case TokenType.Return:
|
|
case TokenType.Select:
|
|
case TokenType.Shadows:
|
|
case TokenType.Shared:
|
|
case TokenType.Static:
|
|
case TokenType.Stop:
|
|
case TokenType.Structure:
|
|
case TokenType.Sub:
|
|
case TokenType.SyncLock:
|
|
case TokenType.Throw:
|
|
case TokenType.Try:
|
|
case TokenType.Using:
|
|
case TokenType.Wend:
|
|
case TokenType.While:
|
|
case TokenType.Widening:
|
|
case TokenType.With:
|
|
case TokenType.WithEvents:
|
|
case TokenType.WriteOnly:
|
|
case TokenType.Pound:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private Token VerifyEndOfStatement()
|
|
{
|
|
Token NextToken = Peek();
|
|
Debug.Assert(NextToken.Type != TokenType.Comment, "Should have dealt with these by now!");
|
|
if (NextToken.Type == TokenType.LineTerminator || NextToken.Type == TokenType.EndOfStream)
|
|
{
|
|
AtBeginningOfLine = true;
|
|
CanContinueWithoutLineTerminator = false;
|
|
}
|
|
else if (NextToken.Type == TokenType.Colon)
|
|
{
|
|
AtBeginningOfLine = false;
|
|
}
|
|
else if (NextToken.Type == TokenType.Else && CurrentBlockContextType() == TreeType.LineIfBlockStatement)
|
|
{
|
|
AtBeginningOfLine = false;
|
|
}
|
|
else
|
|
{
|
|
if (NextToken.Type != TokenType.End || CurrentBlockContextType() != TreeType.LineIfBlockStatement)
|
|
{
|
|
if (CanContinueWithoutLineTerminator)
|
|
{
|
|
return NextToken;
|
|
}
|
|
ResyncAt();
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedEndOfStatement, NextToken);
|
|
return VerifyEndOfStatement();
|
|
}
|
|
AtBeginningOfLine = false;
|
|
}
|
|
return Read();
|
|
}
|
|
|
|
private static bool MustEndStatement(Token token)
|
|
{
|
|
return token.Type == TokenType.Colon || token.Type == TokenType.EndOfStream || token.Type == TokenType.LineTerminator || token.Type == TokenType.Comment;
|
|
}
|
|
|
|
private Span SpanFrom(Location location)
|
|
{
|
|
Location EndLocation = ((Peek().Type != TokenType.EndOfStream) ? Peek().Span.Start : Scanner.Previous().Span.Finish);
|
|
return new Span(location, EndLocation);
|
|
}
|
|
|
|
private Span SpanFrom(Token token)
|
|
{
|
|
Location StartLocation;
|
|
Location EndLocation;
|
|
if (token.Type == TokenType.EndOfStream && !Scanner.IsOnFirstToken)
|
|
{
|
|
StartLocation = Scanner.Previous().Span.Finish;
|
|
EndLocation = StartLocation;
|
|
}
|
|
else
|
|
{
|
|
StartLocation = token.Span.Start;
|
|
EndLocation = ((Peek().Type != TokenType.EndOfStream || Scanner.IsOnFirstToken) ? Peek().Span.Start : Scanner.Previous().Span.Finish);
|
|
}
|
|
return new Span(StartLocation, EndLocation);
|
|
}
|
|
|
|
private Span SpanFrom(Token startToken, Token endToken)
|
|
{
|
|
Location StartLocation;
|
|
Location EndLocation;
|
|
if (startToken.Type == TokenType.EndOfStream && !Scanner.IsOnFirstToken)
|
|
{
|
|
StartLocation = Scanner.Previous().Span.Finish;
|
|
EndLocation = StartLocation;
|
|
}
|
|
else
|
|
{
|
|
StartLocation = startToken.Span.Start;
|
|
EndLocation = ((endToken.Type == TokenType.EndOfStream && !Scanner.IsOnFirstToken) ? Scanner.Previous().Span.Finish : ((endToken.Span.Start.Index != startToken.Span.Start.Index) ? endToken.Span.Start : endToken.Span.Finish));
|
|
}
|
|
return new Span(StartLocation, EndLocation);
|
|
}
|
|
|
|
private static Span SpanFrom(Token startToken, Tree endTree)
|
|
{
|
|
Span SpanFrom = new Span(startToken.Span.Start, endTree.Span.Finish);
|
|
return SpanFrom;
|
|
}
|
|
|
|
private Span SpanFrom(Statement startStatement, Statement endStatement)
|
|
{
|
|
if (endStatement == null)
|
|
{
|
|
return this.SpanFrom(startStatement.Span.Start);
|
|
}
|
|
Span SpanFrom = new Span(startStatement.Span.Start, endStatement.Span.Start);
|
|
return SpanFrom;
|
|
}
|
|
|
|
private SimpleName ParseSimpleName(bool allowKeyword)
|
|
{
|
|
if (Peek().Type == TokenType.Identifier)
|
|
{
|
|
IdentifierToken IdentifierToken = (IdentifierToken)Read();
|
|
return new SimpleName(IdentifierToken.Identifier, IdentifierToken.TypeCharacter, IdentifierToken.Escaped, IdentifierToken.Span);
|
|
}
|
|
if (IdentifierToken.IsKeyword(Peek().Type))
|
|
{
|
|
IdentifierToken IdentifierToken2 = (IdentifierToken)Read();
|
|
if (!allowKeyword)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.InvalidUseOfKeyword, IdentifierToken2);
|
|
}
|
|
return new SimpleName(IdentifierToken2.Identifier, IdentifierToken2.TypeCharacter, IdentifierToken2.Escaped, IdentifierToken2.Span);
|
|
}
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedIdentifier, Peek());
|
|
return SimpleName.GetBadSimpleName(SpanFrom(Peek(), Peek()));
|
|
}
|
|
|
|
private Name ParseName(bool AllowGlobal)
|
|
{
|
|
Token Start = Peek();
|
|
bool QualificationRequired = false;
|
|
Name Result;
|
|
if (Start.Type == TokenType.Global)
|
|
{
|
|
if (!AllowGlobal)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.InvalidUseOfGlobal, Peek());
|
|
}
|
|
Read();
|
|
Result = new SpecialName(TreeType.GlobalNamespaceName, SpanFrom(Start));
|
|
QualificationRequired = true;
|
|
}
|
|
else
|
|
{
|
|
Result = ParseSimpleName(allowKeyword: false);
|
|
}
|
|
if (Peek().Type == TokenType.Period)
|
|
{
|
|
do
|
|
{
|
|
Location DotLocation = ReadLocation();
|
|
SimpleName Qualifier = ParseSimpleName(allowKeyword: true);
|
|
Result = new QualifiedName(Result, DotLocation, Qualifier, SpanFrom(Start));
|
|
}
|
|
while (Peek().Type == TokenType.Period);
|
|
}
|
|
else if (QualificationRequired)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedPeriod, Peek());
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
private VariableName ParseVariableName(bool allowExplicitArraySizes)
|
|
{
|
|
Token Start = Peek();
|
|
ArrayTypeName ArrayType = null;
|
|
SimpleName Name = ParseSimpleName(allowKeyword: false);
|
|
if (Peek().Type == TokenType.LeftParenthesis)
|
|
{
|
|
ArrayType = ParseArrayTypeName(null, null, allowExplicitArraySizes, innerArrayType: false);
|
|
}
|
|
return new VariableName(Name, ArrayType, SpanFrom(Start));
|
|
}
|
|
|
|
private Name ParseNameListName(bool allowLeadingMeOrMyBase = false)
|
|
{
|
|
Token Start = Peek();
|
|
Name Result = ((Start.Type == TokenType.MyBase && allowLeadingMeOrMyBase) ? new SpecialName(TreeType.MyBaseName, SpanFrom(ReadLocation())) : ((Start.Type != TokenType.Me || !allowLeadingMeOrMyBase || Scanner.Version < LanguageVersion.VisualBasic80) ? ((Name)ParseSimpleName(allowKeyword: false)) : ((Name)new SpecialName(TreeType.MeName, SpanFrom(ReadLocation())))));
|
|
if (Peek().Type == TokenType.Period)
|
|
{
|
|
do
|
|
{
|
|
Location DotLocation = ReadLocation();
|
|
SimpleName Qualifier = ParseSimpleName(allowKeyword: true);
|
|
Result = new QualifiedName(Result, DotLocation, Qualifier, SpanFrom(Start));
|
|
}
|
|
while (Peek().Type == TokenType.Period);
|
|
}
|
|
else
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedPeriod, Peek());
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
private TypeName ParseTypeName(bool allowArrayType, bool allowOpenType = false)
|
|
{
|
|
Token Start = Peek();
|
|
TypeName Result = null;
|
|
IntrinsicType Types = default(IntrinsicType);
|
|
switch (Start.Type)
|
|
{
|
|
case TokenType.Boolean:
|
|
Types = IntrinsicType.Boolean;
|
|
break;
|
|
case TokenType.SByte:
|
|
Types = IntrinsicType.SByte;
|
|
break;
|
|
case TokenType.Byte:
|
|
Types = IntrinsicType.Byte;
|
|
break;
|
|
case TokenType.Short:
|
|
Types = IntrinsicType.Short;
|
|
break;
|
|
case TokenType.UShort:
|
|
Types = IntrinsicType.UShort;
|
|
break;
|
|
case TokenType.Integer:
|
|
Types = IntrinsicType.Integer;
|
|
break;
|
|
case TokenType.UInteger:
|
|
Types = IntrinsicType.UInteger;
|
|
break;
|
|
case TokenType.Long:
|
|
Types = IntrinsicType.Long;
|
|
break;
|
|
case TokenType.ULong:
|
|
Types = IntrinsicType.ULong;
|
|
break;
|
|
case TokenType.Decimal:
|
|
Types = IntrinsicType.Decimal;
|
|
break;
|
|
case TokenType.Single:
|
|
Types = IntrinsicType.Single;
|
|
break;
|
|
case TokenType.Double:
|
|
Types = IntrinsicType.Double;
|
|
break;
|
|
case TokenType.Date:
|
|
Types = IntrinsicType.Date;
|
|
break;
|
|
case TokenType.Char:
|
|
Types = IntrinsicType.Char;
|
|
break;
|
|
case TokenType.String:
|
|
Types = IntrinsicType.String;
|
|
break;
|
|
case TokenType.Object:
|
|
Types = IntrinsicType.Object;
|
|
break;
|
|
case TokenType.Identifier:
|
|
case TokenType.Global:
|
|
Result = ParseNamedTypeName(allowGlobal: true, allowOpenType);
|
|
break;
|
|
default:
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedType, Start);
|
|
Result = NamedTypeName.GetBadNamedType(SpanFrom(Start));
|
|
break;
|
|
}
|
|
if (Result == null)
|
|
{
|
|
Read();
|
|
Result = new IntrinsicTypeName(Types, Start.Span);
|
|
}
|
|
if (allowArrayType && Peek().Type == TokenType.LeftParenthesis)
|
|
{
|
|
return ParseArrayTypeName(Start, Result, allowExplicitSizes: false, innerArrayType: false);
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
private NamedTypeName ParseNamedTypeName(bool allowGlobal, bool allowOpenType = false)
|
|
{
|
|
Token Start = Peek();
|
|
Name Name = ParseName(allowGlobal);
|
|
if (Peek().Type == TokenType.LeftParenthesis)
|
|
{
|
|
Token LeftParenthesis = Read();
|
|
if (Peek().Type == TokenType.Of)
|
|
{
|
|
return new ConstructedTypeName(Name, ParseTypeArguments(LeftParenthesis, allowOpenType), SpanFrom(Start));
|
|
}
|
|
Backtrack(LeftParenthesis);
|
|
}
|
|
return new NamedTypeName(Name, Name.Span);
|
|
}
|
|
|
|
private TypeArgumentCollection ParseTypeArguments(Token leftParenthesis, bool allowOpenType = false)
|
|
{
|
|
List<TypeName> TypeArguments = new List<TypeName>();
|
|
List<Location> CommaLocations = new List<Location>();
|
|
bool OpenType = false;
|
|
Debug.Assert(Peek().Type == TokenType.Of);
|
|
Location OfLocation = ReadLocation();
|
|
if ((Peek().Type == TokenType.Comma || Peek().Type == TokenType.RightParenthesis) && allowOpenType)
|
|
{
|
|
OpenType = true;
|
|
}
|
|
if (!OpenType || Peek().Type != TokenType.RightParenthesis)
|
|
{
|
|
do
|
|
{
|
|
if (TypeArguments.Count > 0 || OpenType)
|
|
{
|
|
CommaLocations.Add(ReadLocation());
|
|
}
|
|
if (!OpenType)
|
|
{
|
|
TypeName TypeArgument = ParseTypeName(allowArrayType: true);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Comma, TokenType.RightParenthesis);
|
|
}
|
|
TypeArguments.Add(TypeArgument);
|
|
}
|
|
}
|
|
while (ArrayBoundsContinue());
|
|
}
|
|
Location RightParenthesisLocation = VerifyExpectedToken(TokenType.RightParenthesis);
|
|
return new TypeArgumentCollection(OfLocation, TypeArguments, CommaLocations, RightParenthesisLocation, SpanFrom(leftParenthesis));
|
|
}
|
|
|
|
private bool ArrayBoundsContinue()
|
|
{
|
|
Token NextToken = Peek();
|
|
if (NextToken.Type == TokenType.Comma)
|
|
{
|
|
return true;
|
|
}
|
|
if (NextToken.Type == TokenType.RightParenthesis || MustEndStatement(NextToken))
|
|
{
|
|
return false;
|
|
}
|
|
ReportSyntaxError(SyntaxErrorType.ArgumentSyntax, NextToken);
|
|
ResyncAt(TokenType.Comma, TokenType.RightParenthesis);
|
|
if (Peek().Type == TokenType.Comma)
|
|
{
|
|
ErrorInConstruct = false;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private ArrayTypeName ParseArrayTypeName(Token startType, TypeName elementType, bool allowExplicitSizes, bool innerArrayType)
|
|
{
|
|
Token ArgumentsStart = Peek();
|
|
List<Location> CommaLocations = new List<Location>();
|
|
Debug.Assert(Peek().Type == TokenType.LeftParenthesis);
|
|
if (startType == null)
|
|
{
|
|
startType = Peek();
|
|
}
|
|
Read();
|
|
List<Argument> Arguments;
|
|
if (Peek().Type == TokenType.RightParenthesis || Peek().Type == TokenType.Comma)
|
|
{
|
|
Arguments = null;
|
|
while (Peek().Type == TokenType.Comma)
|
|
{
|
|
CommaLocations.Add(ReadLocation());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!allowExplicitSizes)
|
|
{
|
|
if (innerArrayType)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.NoConstituentArraySizes, Peek());
|
|
}
|
|
else
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.NoExplicitArraySizes, Peek());
|
|
}
|
|
}
|
|
Arguments = new List<Argument>();
|
|
do
|
|
{
|
|
if (Arguments.Count > 0)
|
|
{
|
|
CommaLocations.Add(ReadLocation());
|
|
}
|
|
Token SizeStart = Peek();
|
|
Expression Size = ParseExpression(Scanner.Version > LanguageVersion.VisualBasic71);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Comma, TokenType.RightParenthesis, TokenType.As);
|
|
}
|
|
Arguments.Add(new Argument(null, default(Location), Size, SpanFrom(SizeStart)));
|
|
}
|
|
while (ArrayBoundsContinue());
|
|
}
|
|
Location RightParenthesisLocation = VerifyExpectedToken(TokenType.RightParenthesis);
|
|
ArgumentCollection ArgumentCollection = new ArgumentCollection(Arguments, CommaLocations, RightParenthesisLocation, SpanFrom(ArgumentsStart));
|
|
if (Peek().Type == TokenType.LeftParenthesis)
|
|
{
|
|
elementType = ParseArrayTypeName(Peek(), elementType, allowExplicitSizes: false, innerArrayType: true);
|
|
}
|
|
return new ArrayTypeName(elementType, checked(CommaLocations.Count + 1), ArgumentCollection, SpanFrom(startType));
|
|
}
|
|
|
|
private Initializer ParseInitializer()
|
|
{
|
|
if (Peek().Type == TokenType.LeftCurlyBrace)
|
|
{
|
|
return ParseAggregateInitializer();
|
|
}
|
|
Expression Expression = ParseExpression();
|
|
return new ExpressionInitializer(Expression, Expression.Span);
|
|
}
|
|
|
|
private bool InitializersContinue()
|
|
{
|
|
Token NextToken = Peek();
|
|
if (NextToken.Type == TokenType.Comma)
|
|
{
|
|
return true;
|
|
}
|
|
if (NextToken.Type == TokenType.RightCurlyBrace || MustEndStatement(NextToken))
|
|
{
|
|
return false;
|
|
}
|
|
ReportSyntaxError(SyntaxErrorType.InitializerSyntax, NextToken);
|
|
ResyncAt(TokenType.Comma, TokenType.RightCurlyBrace);
|
|
if (Peek().Type == TokenType.Comma)
|
|
{
|
|
ErrorInConstruct = false;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private AggregateInitializer ParseAggregateInitializer()
|
|
{
|
|
Token Start = Peek();
|
|
List<Initializer> Initializers = new List<Initializer>();
|
|
List<Location> CommaLocations = new List<Location>();
|
|
Debug.Assert(Start.Type == TokenType.LeftCurlyBrace);
|
|
Read();
|
|
if (Peek().Type != TokenType.RightCurlyBrace)
|
|
{
|
|
do
|
|
{
|
|
if (Initializers.Count > 0)
|
|
{
|
|
CommaLocations.Add(ReadLocation());
|
|
}
|
|
Initializers.Add(ParseInitializer());
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Comma, TokenType.RightCurlyBrace);
|
|
}
|
|
}
|
|
while (InitializersContinue());
|
|
}
|
|
Location RightBracketLocation = VerifyExpectedToken(TokenType.RightCurlyBrace);
|
|
return new AggregateInitializer(new InitializerCollection(Initializers, CommaLocations, RightBracketLocation, SpanFrom(Start)), SpanFrom(Start));
|
|
}
|
|
|
|
private Argument ParseArgument(ref bool foundNamedArgument)
|
|
{
|
|
Token Start = Read();
|
|
if (Peek().Type == TokenType.ColonEquals)
|
|
{
|
|
if (!foundNamedArgument)
|
|
{
|
|
foundNamedArgument = true;
|
|
}
|
|
}
|
|
else if (foundNamedArgument)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedNamedArgument, Start);
|
|
foundNamedArgument = false;
|
|
}
|
|
Backtrack(Start);
|
|
SimpleName Name;
|
|
Location ColonEqualsLocation = default(Location);
|
|
Expression Value;
|
|
if (foundNamedArgument)
|
|
{
|
|
Name = ParseSimpleName(allowKeyword: true);
|
|
ColonEqualsLocation = ReadLocation();
|
|
Value = ParseExpression();
|
|
}
|
|
else
|
|
{
|
|
Name = null;
|
|
Value = ParseExpression();
|
|
}
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Comma, TokenType.RightParenthesis);
|
|
if (Peek().Type == TokenType.Comma)
|
|
{
|
|
ErrorInConstruct = false;
|
|
}
|
|
}
|
|
return new Argument(Name, ColonEqualsLocation, Value, SpanFrom(Start));
|
|
}
|
|
|
|
private bool ArgumentsContinue()
|
|
{
|
|
Token NextToken = Peek();
|
|
if (NextToken.Type == TokenType.Comma)
|
|
{
|
|
return true;
|
|
}
|
|
if (NextToken.Type == TokenType.RightParenthesis || MustEndStatement(NextToken))
|
|
{
|
|
return false;
|
|
}
|
|
if (NextToken.Type == TokenType.End && CurrentBlockContextType() == TreeType.LineIfBlockStatement)
|
|
{
|
|
return false;
|
|
}
|
|
ReportSyntaxError(SyntaxErrorType.ArgumentSyntax, NextToken);
|
|
ResyncAt(TokenType.Comma, TokenType.RightParenthesis);
|
|
if (Peek().Type == TokenType.Comma)
|
|
{
|
|
ErrorInConstruct = false;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private ArgumentCollection ParseArguments(bool requireParenthesis = true)
|
|
{
|
|
Token Start = Peek();
|
|
List<Argument> Arguments = new List<Argument>();
|
|
List<Location> CommaLocations = new List<Location>();
|
|
if (Start.Type != TokenType.LeftParenthesis)
|
|
{
|
|
if (requireParenthesis)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
requireParenthesis = true;
|
|
Read();
|
|
}
|
|
if (Peek().Type != TokenType.RightParenthesis)
|
|
{
|
|
bool FoundNamedArgument = false;
|
|
do
|
|
{
|
|
if (Arguments.Count > 0)
|
|
{
|
|
CommaLocations.Add(ReadLocation());
|
|
}
|
|
Token ArgumentStart = Peek();
|
|
Argument Argument;
|
|
if (ArgumentStart.Type == TokenType.Comma || ArgumentStart.Type == TokenType.RightParenthesis)
|
|
{
|
|
if (FoundNamedArgument)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedNamedArgument, Peek());
|
|
}
|
|
Argument = null;
|
|
}
|
|
else
|
|
{
|
|
Argument = ParseArgument(ref FoundNamedArgument);
|
|
}
|
|
Arguments.Add(Argument);
|
|
}
|
|
while (ArgumentsContinue());
|
|
}
|
|
Location RightParenthesisLocation = default(Location);
|
|
if (Peek().Type == TokenType.RightParenthesis)
|
|
{
|
|
RightParenthesisLocation = ReadLocation();
|
|
}
|
|
else if (requireParenthesis)
|
|
{
|
|
Token Current = Peek();
|
|
ResyncAt(TokenType.LeftParenthesis, TokenType.RightParenthesis);
|
|
if (Peek().Type == TokenType.RightParenthesis)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.SyntaxError, Peek());
|
|
RightParenthesisLocation = ReadLocation();
|
|
}
|
|
else
|
|
{
|
|
Backtrack(Current);
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedRightParenthesis, Peek());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RightParenthesisLocation = Peek().Span.Start;
|
|
}
|
|
return new ArgumentCollection(Arguments, CommaLocations, RightParenthesisLocation, SpanFrom(Start));
|
|
}
|
|
|
|
private LiteralExpression ParseLiteralExpression()
|
|
{
|
|
Token Start = Read();
|
|
switch (Start.Type)
|
|
{
|
|
case TokenType.False:
|
|
case TokenType.True:
|
|
return new BooleanLiteralExpression(Start.Type == TokenType.True, Start.Span);
|
|
case TokenType.IntegerLiteral:
|
|
{
|
|
IntegerLiteralToken Literal6 = (IntegerLiteralToken)Start;
|
|
return new IntegerLiteralExpression(Literal6.Literal, Literal6.IntegerBase, Literal6.TypeCharacter, Literal6.Span);
|
|
}
|
|
case TokenType.FloatingPointLiteral:
|
|
{
|
|
FloatingPointLiteralToken Literal4 = (FloatingPointLiteralToken)Start;
|
|
return new FloatingPointLiteralExpression(Literal4.Literal, Literal4.TypeCharacter, Literal4.Span);
|
|
}
|
|
case TokenType.DecimalLiteral:
|
|
{
|
|
DecimalLiteralToken Literal2 = (DecimalLiteralToken)Start;
|
|
return new DecimalLiteralExpression(Literal2.Literal, Literal2.TypeCharacter, Literal2.Span);
|
|
}
|
|
case TokenType.CharacterLiteral:
|
|
{
|
|
CharacterLiteralToken Literal3 = (CharacterLiteralToken)Start;
|
|
return new CharacterLiteralExpression(Literal3.Literal, Literal3.Span);
|
|
}
|
|
case TokenType.StringLiteral:
|
|
{
|
|
StringLiteralToken Literal = (StringLiteralToken)Start;
|
|
return new StringLiteralExpression(Literal.Literal, Literal.Span);
|
|
}
|
|
case TokenType.DateLiteral:
|
|
{
|
|
DateLiteralToken Literal5 = (DateLiteralToken)Start;
|
|
return new DateLiteralExpression(Literal5.Literal, Literal5.Span);
|
|
}
|
|
default:
|
|
Debug.Assert(condition: false, "Unexpected.");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private Expression ParseCastExpression()
|
|
{
|
|
Token Start = Read();
|
|
IntrinsicType OperatorType;
|
|
switch (Start.Type)
|
|
{
|
|
case TokenType.CBool:
|
|
OperatorType = IntrinsicType.Boolean;
|
|
break;
|
|
case TokenType.CChar:
|
|
OperatorType = IntrinsicType.Char;
|
|
break;
|
|
case TokenType.CDate:
|
|
OperatorType = IntrinsicType.Date;
|
|
break;
|
|
case TokenType.CDbl:
|
|
OperatorType = IntrinsicType.Double;
|
|
break;
|
|
case TokenType.CByte:
|
|
OperatorType = IntrinsicType.Byte;
|
|
break;
|
|
case TokenType.CShort:
|
|
OperatorType = IntrinsicType.Short;
|
|
break;
|
|
case TokenType.CInt:
|
|
OperatorType = IntrinsicType.Integer;
|
|
break;
|
|
case TokenType.CLng:
|
|
OperatorType = IntrinsicType.Long;
|
|
break;
|
|
case TokenType.CSng:
|
|
OperatorType = IntrinsicType.Single;
|
|
break;
|
|
case TokenType.CStr:
|
|
OperatorType = IntrinsicType.String;
|
|
break;
|
|
case TokenType.CDec:
|
|
OperatorType = IntrinsicType.Decimal;
|
|
break;
|
|
case TokenType.CObj:
|
|
OperatorType = IntrinsicType.Object;
|
|
break;
|
|
case TokenType.CSByte:
|
|
OperatorType = IntrinsicType.SByte;
|
|
break;
|
|
case TokenType.CUShort:
|
|
OperatorType = IntrinsicType.UShort;
|
|
break;
|
|
case TokenType.CUInt:
|
|
OperatorType = IntrinsicType.UInteger;
|
|
break;
|
|
case TokenType.CULng:
|
|
OperatorType = IntrinsicType.ULong;
|
|
break;
|
|
default:
|
|
Debug.Assert(condition: false, "Unexpected.");
|
|
return null;
|
|
}
|
|
Location LeftParenthesisLocation = VerifyExpectedToken(TokenType.LeftParenthesis);
|
|
Expression Operand = ParseExpression();
|
|
Location RightParenthesisLocation = VerifyExpectedToken(TokenType.RightParenthesis);
|
|
return new IntrinsicCastExpression(OperatorType, LeftParenthesisLocation, Operand, RightParenthesisLocation, SpanFrom(Start));
|
|
}
|
|
|
|
private Expression ParseCTypeExpression()
|
|
{
|
|
Token Start = Read();
|
|
Debug.Assert(Start.Type == TokenType.CType || Start.Type == TokenType.DirectCast || Start.Type == TokenType.TryCast);
|
|
Location LeftParenthesisLocation = VerifyExpectedToken(TokenType.LeftParenthesis);
|
|
Expression Operand = ParseExpression();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Comma, TokenType.RightParenthesis);
|
|
}
|
|
Location CommaLocation = VerifyExpectedToken(TokenType.Comma);
|
|
TypeName Target = ParseTypeName(allowArrayType: true);
|
|
Location RightParenthesisLocation = VerifyExpectedToken(TokenType.RightParenthesis);
|
|
if (Start.Type == TokenType.CType)
|
|
{
|
|
return new CTypeExpression(LeftParenthesisLocation, Operand, CommaLocation, Target, RightParenthesisLocation, SpanFrom(Start));
|
|
}
|
|
if (Start.Type == TokenType.DirectCast)
|
|
{
|
|
return new DirectCastExpression(LeftParenthesisLocation, Operand, CommaLocation, Target, RightParenthesisLocation, SpanFrom(Start));
|
|
}
|
|
return new TryCastExpression(LeftParenthesisLocation, Operand, CommaLocation, Target, RightParenthesisLocation, SpanFrom(Start));
|
|
}
|
|
|
|
private Expression ParseInstanceExpression()
|
|
{
|
|
Token Start = Read();
|
|
InstanceType InstanceType = default(InstanceType);
|
|
switch (Start.Type)
|
|
{
|
|
case TokenType.Me:
|
|
InstanceType = InstanceType.Me;
|
|
break;
|
|
case TokenType.MyClass:
|
|
InstanceType = InstanceType.MyClass;
|
|
if (Peek().Type != TokenType.Period)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedPeriodAfterMyClass, Start);
|
|
}
|
|
break;
|
|
case TokenType.MyBase:
|
|
InstanceType = InstanceType.MyBase;
|
|
if (Peek().Type != TokenType.Period)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedPeriodAfterMyBase, Start);
|
|
}
|
|
break;
|
|
default:
|
|
Debug.Assert(condition: false, "Unexpected.");
|
|
break;
|
|
}
|
|
return new InstanceExpression(InstanceType, Start.Span);
|
|
}
|
|
|
|
private Expression ParseParentheticalExpression()
|
|
{
|
|
Token Start = Read();
|
|
Debug.Assert(Start.Type == TokenType.LeftParenthesis);
|
|
Expression Operand = ParseExpression();
|
|
Location RightParenthesisLocation = VerifyExpectedToken(TokenType.RightParenthesis);
|
|
return new ParentheticalExpression(Operand, RightParenthesisLocation, SpanFrom(Start));
|
|
}
|
|
|
|
private Expression ParseSimpleNameExpression()
|
|
{
|
|
Token Start = Peek();
|
|
return new SimpleNameExpression(ParseSimpleName(allowKeyword: false), SpanFrom(Start));
|
|
}
|
|
|
|
private Expression ParseDotBangExpression(Token start, Expression terminal)
|
|
{
|
|
Debug.Assert(Peek().Type == TokenType.Period || Peek().Type == TokenType.Exclamation);
|
|
Token DotBang = Read();
|
|
SimpleName Name = ParseSimpleName(allowKeyword: true);
|
|
if (DotBang.Type == TokenType.Period)
|
|
{
|
|
return new QualifiedExpression(terminal, DotBang.Span.Start, Name, SpanFrom(start));
|
|
}
|
|
return new DictionaryLookupExpression(terminal, DotBang.Span.Start, Name, SpanFrom(start));
|
|
}
|
|
|
|
private Expression ParseCallOrIndexExpression(Token start, Expression terminal)
|
|
{
|
|
ArgumentCollection Arguments = ParseArguments();
|
|
return new CallOrIndexExpression(terminal, Arguments, SpanFrom(start));
|
|
}
|
|
|
|
private Expression ParseTypeOfExpression()
|
|
{
|
|
Token Start = Peek();
|
|
Debug.Assert(Start.Type == TokenType.TypeOf);
|
|
Read();
|
|
Expression Value = ParseBinaryOperatorExpression(PrecedenceLevel.Relational);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Is);
|
|
}
|
|
Location IsLocation = VerifyExpectedToken(TokenType.Is);
|
|
TypeName Target = ParseTypeName(allowArrayType: true);
|
|
return new TypeOfExpression(Value, IsLocation, Target, SpanFrom(Start));
|
|
}
|
|
|
|
private Expression ParseGetTypeExpression()
|
|
{
|
|
Token Start = Read();
|
|
Debug.Assert(Start.Type == TokenType.GetType);
|
|
Location LeftParenthesisLocation = VerifyExpectedToken(TokenType.LeftParenthesis);
|
|
TypeName Target = ParseTypeName(allowArrayType: true, allowOpenType: true);
|
|
Location RightParenthesisLocation = VerifyExpectedToken(TokenType.RightParenthesis);
|
|
return new GetTypeExpression(LeftParenthesisLocation, Target, RightParenthesisLocation, SpanFrom(Start));
|
|
}
|
|
|
|
private Expression ParseNewExpression()
|
|
{
|
|
Token Start = Read();
|
|
Debug.Assert(Start.Type == TokenType.New);
|
|
Token TypeStart = Peek();
|
|
TypeName Type = ParseTypeName(allowArrayType: false);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.LeftParenthesis);
|
|
}
|
|
Token ArgumentsStart = Peek();
|
|
ArgumentCollection Arguments = ParseArguments();
|
|
if ((Peek().Type == TokenType.LeftCurlyBrace || Peek().Type == TokenType.LeftParenthesis) && Arguments != null)
|
|
{
|
|
Backtrack(ArgumentsStart);
|
|
ArrayTypeName ArrayType = ParseArrayTypeName(TypeStart, Type, allowExplicitSizes: true, innerArrayType: false);
|
|
if (Peek().Type == TokenType.LeftCurlyBrace)
|
|
{
|
|
AggregateInitializer Initializer = ParseAggregateInitializer();
|
|
return new NewAggregateExpression(ArrayType, Initializer, SpanFrom(Start));
|
|
}
|
|
HandleUnexpectedToken(TokenType.LeftCurlyBrace);
|
|
}
|
|
return new NewExpression(Type, Arguments, SpanFrom(Start));
|
|
}
|
|
|
|
private Expression ParseTerminalExpression()
|
|
{
|
|
Token Start = Peek();
|
|
Expression Terminal;
|
|
switch (Start.Type)
|
|
{
|
|
case TokenType.Identifier:
|
|
Terminal = ParseSimpleNameExpression();
|
|
break;
|
|
case TokenType.StringLiteral:
|
|
case TokenType.CharacterLiteral:
|
|
case TokenType.DateLiteral:
|
|
case TokenType.IntegerLiteral:
|
|
case TokenType.FloatingPointLiteral:
|
|
case TokenType.DecimalLiteral:
|
|
case TokenType.False:
|
|
case TokenType.True:
|
|
Terminal = ParseLiteralExpression();
|
|
break;
|
|
case TokenType.CBool:
|
|
case TokenType.CByte:
|
|
case TokenType.CChar:
|
|
case TokenType.CDate:
|
|
case TokenType.CDec:
|
|
case TokenType.CDbl:
|
|
case TokenType.CInt:
|
|
case TokenType.CLng:
|
|
case TokenType.CObj:
|
|
case TokenType.CSByte:
|
|
case TokenType.CShort:
|
|
case TokenType.CSng:
|
|
case TokenType.CStr:
|
|
case TokenType.CUInt:
|
|
case TokenType.CULng:
|
|
case TokenType.CUShort:
|
|
Terminal = ParseCastExpression();
|
|
break;
|
|
case TokenType.CType:
|
|
case TokenType.DirectCast:
|
|
case TokenType.TryCast:
|
|
Terminal = ParseCTypeExpression();
|
|
break;
|
|
case TokenType.Me:
|
|
case TokenType.MyBase:
|
|
case TokenType.MyClass:
|
|
Terminal = ParseInstanceExpression();
|
|
break;
|
|
case TokenType.Global:
|
|
Terminal = new GlobalExpression(Read().Span);
|
|
if (Peek().Type != TokenType.Period)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedPeriodAfterGlobal, Start);
|
|
}
|
|
break;
|
|
case TokenType.Nothing:
|
|
Terminal = new NothingExpression(Read().Span);
|
|
break;
|
|
case TokenType.LeftParenthesis:
|
|
Terminal = ParseParentheticalExpression();
|
|
break;
|
|
case TokenType.Exclamation:
|
|
case TokenType.Period:
|
|
Terminal = ParseDotBangExpression(Start, null);
|
|
break;
|
|
case TokenType.TypeOf:
|
|
Terminal = ParseTypeOfExpression();
|
|
break;
|
|
case TokenType.GetType:
|
|
Terminal = ParseGetTypeExpression();
|
|
break;
|
|
case TokenType.New:
|
|
Terminal = ParseNewExpression();
|
|
break;
|
|
case TokenType.Boolean:
|
|
case TokenType.Byte:
|
|
case TokenType.Char:
|
|
case TokenType.Date:
|
|
case TokenType.Decimal:
|
|
case TokenType.Double:
|
|
case TokenType.Integer:
|
|
case TokenType.Long:
|
|
case TokenType.Object:
|
|
case TokenType.Short:
|
|
case TokenType.Single:
|
|
case TokenType.String:
|
|
Terminal = new SimpleNameExpression(ParseSimpleName(allowKeyword: true), SpanFrom(Start));
|
|
if (Scanner.Peek().Type == TokenType.Period)
|
|
{
|
|
Terminal = ParseDotBangExpression(Start, Terminal);
|
|
}
|
|
break;
|
|
default:
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedExpression, Peek());
|
|
Terminal = Expression.GetBadExpression(SpanFrom(Peek(), Peek()));
|
|
break;
|
|
}
|
|
while (true)
|
|
{
|
|
Token NextToken = Peek();
|
|
if (NextToken.Type == TokenType.Period || NextToken.Type == TokenType.Exclamation)
|
|
{
|
|
Terminal = ParseDotBangExpression(Start, Terminal);
|
|
continue;
|
|
}
|
|
if (NextToken.Type == TokenType.LeftParenthesis)
|
|
{
|
|
Token LeftParenthesis = Read();
|
|
if (Peek().Type == TokenType.Of)
|
|
{
|
|
return new GenericQualifiedExpression(Terminal, ParseTypeArguments(LeftParenthesis), SpanFrom(Start));
|
|
}
|
|
Backtrack(LeftParenthesis);
|
|
Terminal = ParseCallOrIndexExpression(Start, Terminal);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
return Terminal;
|
|
}
|
|
|
|
private Expression ParseUnaryOperatorExpression()
|
|
{
|
|
Token Start = Peek();
|
|
OperatorType OperatorType;
|
|
Expression Operand;
|
|
switch (Start.Type)
|
|
{
|
|
case TokenType.Minus:
|
|
OperatorType = OperatorType.Negate;
|
|
break;
|
|
case TokenType.Plus:
|
|
OperatorType = OperatorType.UnaryPlus;
|
|
break;
|
|
case TokenType.Not:
|
|
OperatorType = OperatorType.Not;
|
|
break;
|
|
case TokenType.AddressOf:
|
|
Read();
|
|
Operand = ParseBinaryOperatorExpression(PrecedenceLevel.None);
|
|
return new AddressOfExpression(Operand, SpanFrom(Start, Operand));
|
|
default:
|
|
return ParseTerminalExpression();
|
|
}
|
|
Read();
|
|
Operand = ParseBinaryOperatorExpression(GetOperatorPrecedence(OperatorType));
|
|
return new UnaryOperatorExpression(OperatorType, Operand, SpanFrom(Start, Operand));
|
|
}
|
|
|
|
private Expression ParseBinaryOperatorExpression(PrecedenceLevel pendingPrecedence, bool allowRange = false)
|
|
{
|
|
Token Start = Peek();
|
|
Expression Expression = ParseUnaryOperatorExpression();
|
|
while (true)
|
|
{
|
|
OperatorType OperatorType = GetBinaryOperator(Peek().Type, allowRange);
|
|
if (OperatorType == OperatorType.None)
|
|
{
|
|
break;
|
|
}
|
|
PrecedenceLevel Precedence = GetOperatorPrecedence(OperatorType);
|
|
if (Precedence <= pendingPrecedence)
|
|
{
|
|
break;
|
|
}
|
|
Location OperatorLocation = ReadLocation();
|
|
Expression Right = ParseBinaryOperatorExpression(Precedence);
|
|
Expression = new BinaryOperatorExpression(Expression, OperatorType, OperatorLocation, Right, SpanFrom(Start, Right));
|
|
}
|
|
return Expression;
|
|
}
|
|
|
|
private ExpressionCollection ParseExpressionList(bool requireExpression = false)
|
|
{
|
|
Token Start = Peek();
|
|
List<Expression> Expressions = new List<Expression>();
|
|
List<Location> CommaLocations = new List<Location>();
|
|
if (CanEndStatement(Start) && !requireExpression)
|
|
{
|
|
return null;
|
|
}
|
|
do
|
|
{
|
|
if (Expressions.Count > 0)
|
|
{
|
|
CommaLocations.Add(ReadLocation());
|
|
}
|
|
Expressions.Add(ParseExpression());
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Comma);
|
|
}
|
|
}
|
|
while (Peek().Type == TokenType.Comma);
|
|
if (Expressions.Count == 0 && CommaLocations.Count == 0)
|
|
{
|
|
return null;
|
|
}
|
|
return new ExpressionCollection(Expressions, CommaLocations, SpanFrom(Start));
|
|
}
|
|
|
|
private Expression ParseExpression(bool allowRange = false)
|
|
{
|
|
return ParseBinaryOperatorExpression(PrecedenceLevel.None, allowRange);
|
|
}
|
|
|
|
private Statement ParseExpressionStatement(TreeType type, bool operandOptional)
|
|
{
|
|
Token Start = Peek();
|
|
Expression Operand = null;
|
|
Read();
|
|
if (!operandOptional || !CanEndStatement(Peek()))
|
|
{
|
|
Operand = ParseExpression();
|
|
}
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
switch (type)
|
|
{
|
|
case TreeType.ReturnStatement:
|
|
return new ReturnStatement(Operand, SpanFrom(Start), ParseTrailingComments());
|
|
case TreeType.ErrorStatement:
|
|
return new ErrorStatement(Operand, SpanFrom(Start), ParseTrailingComments());
|
|
case TreeType.ThrowStatement:
|
|
return new ThrowStatement(Operand, SpanFrom(Start), ParseTrailingComments());
|
|
default:
|
|
Debug.Assert(condition: false, "Unexpected!");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private void ParseLabelReference(ref SimpleName name, ref bool isLineNumber)
|
|
{
|
|
Token Start = Peek();
|
|
if (Start.Type == TokenType.Identifier)
|
|
{
|
|
name = ParseSimpleName(allowKeyword: false);
|
|
isLineNumber = false;
|
|
}
|
|
else if (Start.Type == TokenType.IntegerLiteral)
|
|
{
|
|
IntegerLiteralToken IntegerLiteral = (IntegerLiteralToken)Start;
|
|
if (IntegerLiteral.TypeCharacter != 0)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.SyntaxError, Start);
|
|
}
|
|
name = new SimpleName(Conversions.ToString(IntegerLiteral.Literal), TypeCharacter.None, escaped: false, IntegerLiteral.Span);
|
|
isLineNumber = true;
|
|
Read();
|
|
}
|
|
else
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedIdentifier, Start);
|
|
name = SimpleName.GetBadSimpleName(SpanFrom(Start));
|
|
isLineNumber = false;
|
|
}
|
|
}
|
|
|
|
private Statement ParseGotoStatement()
|
|
{
|
|
Token Start = Peek();
|
|
SimpleName Name = null;
|
|
Read();
|
|
bool IsLineNumber = default(bool);
|
|
ParseLabelReference(ref Name, ref IsLineNumber);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
return new GotoStatement(Name, IsLineNumber, SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
|
|
private Statement ParseContinueStatement()
|
|
{
|
|
Token Start = Peek();
|
|
Read();
|
|
BlockType ContinueType = GetContinueType(Peek().Type);
|
|
Location ContinueArgumentLocation = default(Location);
|
|
if (ContinueType == BlockType.None)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedContinueKind, Peek());
|
|
ResyncAt();
|
|
}
|
|
else
|
|
{
|
|
ContinueArgumentLocation = ReadLocation();
|
|
}
|
|
return new ContinueStatement(ContinueType, ContinueArgumentLocation, SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
|
|
private Statement ParseExitStatement()
|
|
{
|
|
Token Start = Peek();
|
|
Read();
|
|
BlockType ExitType = GetExitType(Peek().Type);
|
|
Location ExitArgumentLocation = default(Location);
|
|
if (ExitType == BlockType.None)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedExitKind, Peek());
|
|
ResyncAt();
|
|
}
|
|
else
|
|
{
|
|
ExitArgumentLocation = ReadLocation();
|
|
}
|
|
return new ExitStatement(ExitType, ExitArgumentLocation, SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
|
|
private Statement ParseEndStatement()
|
|
{
|
|
Token Start = Read();
|
|
BlockType EndType = GetBlockType(Peek().Type);
|
|
if (EndType == BlockType.None)
|
|
{
|
|
return new EndStatement(SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
return new EndBlockStatement(EndType, ReadLocation(), SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
|
|
private Statement ParseWendStatement()
|
|
{
|
|
Token Start = Read();
|
|
return new EndBlockStatement(BlockType.While, Start.Span.Finish, SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
|
|
private Statement ParseRaiseEventStatement()
|
|
{
|
|
Token Start = Peek();
|
|
Read();
|
|
SimpleName Name = ParseSimpleName(allowKeyword: true);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
ArgumentCollection Arguments = ParseArguments();
|
|
return new RaiseEventStatement(Name, Arguments, SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
|
|
private Statement ParseHandlerStatement()
|
|
{
|
|
Token Start = Peek();
|
|
Read();
|
|
Expression EventName = ParseExpression();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Comma);
|
|
}
|
|
Location CommaLocation = VerifyExpectedToken(TokenType.Comma);
|
|
Expression DelegateExpression = ParseExpression();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
if (Start.Type == TokenType.AddHandler)
|
|
{
|
|
return new AddHandlerStatement(EventName, CommaLocation, DelegateExpression, SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
return new RemoveHandlerStatement(EventName, CommaLocation, DelegateExpression, SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
|
|
private Statement ParseOnErrorStatement()
|
|
{
|
|
Token Start = Read();
|
|
SimpleName Name = null;
|
|
Location ErrorLocation = default(Location);
|
|
Location ResumeOrGoToLocation = default(Location);
|
|
Location NextOrZeroOrMinusLocation = default(Location);
|
|
OnErrorType OnErrorType;
|
|
Location OneLocation = default(Location);
|
|
bool IsLineNumber = default(bool);
|
|
if (Peek().Type == TokenType.Error)
|
|
{
|
|
ErrorLocation = ReadLocation();
|
|
Token NextToken = Peek();
|
|
if (NextToken.Type == TokenType.Resume)
|
|
{
|
|
ResumeOrGoToLocation = ReadLocation();
|
|
if (Peek().Type == TokenType.Next)
|
|
{
|
|
NextOrZeroOrMinusLocation = ReadLocation();
|
|
}
|
|
else
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedNext, Peek());
|
|
}
|
|
OnErrorType = OnErrorType.Next;
|
|
}
|
|
else if (NextToken.Type == TokenType.GoTo)
|
|
{
|
|
ResumeOrGoToLocation = ReadLocation();
|
|
NextToken = Peek();
|
|
if (NextToken.Type == TokenType.IntegerLiteral && ((IntegerLiteralToken)NextToken).Literal == 0)
|
|
{
|
|
NextOrZeroOrMinusLocation = ReadLocation();
|
|
OnErrorType = OnErrorType.Zero;
|
|
}
|
|
else
|
|
{
|
|
if (NextToken.Type == TokenType.Minus)
|
|
{
|
|
NextOrZeroOrMinusLocation = ReadLocation();
|
|
Token NextNextToken = Peek();
|
|
if (NextNextToken.Type == TokenType.IntegerLiteral && ((IntegerLiteralToken)NextNextToken).Literal == 1)
|
|
{
|
|
OneLocation = ReadLocation();
|
|
OnErrorType = OnErrorType.MinusOne;
|
|
goto IL_01ab;
|
|
}
|
|
Backtrack(NextToken);
|
|
}
|
|
OnErrorType = OnErrorType.Label;
|
|
ParseLabelReference(ref Name, ref IsLineNumber);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedResumeOrGoto, Peek());
|
|
OnErrorType = OnErrorType.Bad;
|
|
ResyncAt();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedError, Peek());
|
|
OnErrorType = OnErrorType.Bad;
|
|
ResyncAt();
|
|
}
|
|
goto IL_01ab;
|
|
IL_01ab:
|
|
return new OnErrorStatement(OnErrorType, ErrorLocation, ResumeOrGoToLocation, NextOrZeroOrMinusLocation, OneLocation, Name, IsLineNumber, SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
|
|
private Statement ParseResumeStatement()
|
|
{
|
|
Token Start = Read();
|
|
ResumeType ResumeType = ResumeType.None;
|
|
SimpleName Name = null;
|
|
Location NextLocation = default(Location);
|
|
bool IsLineNumber = default(bool);
|
|
if (!CanEndStatement(Peek()))
|
|
{
|
|
if (Peek().Type == TokenType.Next)
|
|
{
|
|
NextLocation = ReadLocation();
|
|
ResumeType = ResumeType.Next;
|
|
}
|
|
else
|
|
{
|
|
ParseLabelReference(ref Name, ref IsLineNumber);
|
|
ResumeType = ((!ErrorInConstruct) ? ResumeType.Label : ResumeType.None);
|
|
}
|
|
}
|
|
return new ResumeStatement(ResumeType, NextLocation, Name, IsLineNumber, SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
|
|
private Statement ParseReDimStatement()
|
|
{
|
|
Token Start = Read();
|
|
Location PreserveLocation = default(Location);
|
|
if (Peek().AsUnreservedKeyword() == TokenType.Preserve)
|
|
{
|
|
PreserveLocation = ReadLocation();
|
|
}
|
|
ExpressionCollection Variables = ParseExpressionList(requireExpression: true);
|
|
return new ReDimStatement(PreserveLocation, Variables, SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
|
|
private Statement ParseEraseStatement()
|
|
{
|
|
Token Start = Read();
|
|
ExpressionCollection Variables = ParseExpressionList(requireExpression: true);
|
|
return new EraseStatement(Variables, SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
|
|
private Statement ParseCallStatement(Expression target = null)
|
|
{
|
|
Token Start = Peek();
|
|
ArgumentCollection Arguments = null;
|
|
Location StartLocation;
|
|
Location CallLocation = default(Location);
|
|
if (target == null)
|
|
{
|
|
StartLocation = Start.Span.Start;
|
|
if (Start.Type == TokenType.Call)
|
|
{
|
|
CallLocation = ReadLocation();
|
|
}
|
|
target = ParseExpression();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StartLocation = target.Span.Start;
|
|
}
|
|
if (target.Type == TreeType.CallOrIndexExpression)
|
|
{
|
|
CallOrIndexExpression CallOrIndexExpression = (CallOrIndexExpression)target;
|
|
target = CallOrIndexExpression.TargetExpression;
|
|
Arguments = CallOrIndexExpression.Arguments;
|
|
}
|
|
else if (!MustEndStatement(Peek()))
|
|
{
|
|
Arguments = ParseArguments(requireParenthesis: false);
|
|
}
|
|
return new CallStatement(CallLocation, target, Arguments, SpanFrom(StartLocation), ParseTrailingComments());
|
|
}
|
|
|
|
private Statement ParseMidAssignmentStatement()
|
|
{
|
|
Token Start = Read();
|
|
IdentifierToken Identifier = (IdentifierToken)Start;
|
|
Location LengthCommaLocation = default(Location);
|
|
Expression LengthExpression = null;
|
|
bool HasTypeCharacter = default(bool);
|
|
if (Identifier.TypeCharacter == TypeCharacter.StringSymbol)
|
|
{
|
|
HasTypeCharacter = true;
|
|
}
|
|
else if (Identifier.TypeCharacter != 0)
|
|
{
|
|
goto IL_0196;
|
|
}
|
|
if (Peek().Type == TokenType.LeftParenthesis)
|
|
{
|
|
Location LeftParenthesisLocation = VerifyExpectedToken(TokenType.LeftParenthesis);
|
|
Expression Target = ParseExpression();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Comma);
|
|
}
|
|
Location StartCommaLocation = VerifyExpectedToken(TokenType.Comma);
|
|
Expression StartExpression = ParseExpression();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Comma, TokenType.RightParenthesis);
|
|
}
|
|
if (Peek().Type == TokenType.Comma)
|
|
{
|
|
LengthCommaLocation = VerifyExpectedToken(TokenType.Comma);
|
|
LengthExpression = ParseExpression();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.RightParenthesis);
|
|
}
|
|
}
|
|
Location RightParenthesisLocation = VerifyExpectedToken(TokenType.RightParenthesis);
|
|
Location OperatorLocation = VerifyExpectedToken(TokenType.Equals);
|
|
Expression Source = ParseExpression();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
return new MidAssignmentStatement(HasTypeCharacter, LeftParenthesisLocation, Target, StartCommaLocation, StartExpression, LengthCommaLocation, LengthExpression, RightParenthesisLocation, OperatorLocation, Source, SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
goto IL_0196;
|
|
IL_0196:
|
|
Backtrack(Start);
|
|
return null;
|
|
}
|
|
|
|
private Statement ParseAssignmentStatement(Expression target, bool isSetStatement)
|
|
{
|
|
Token Operator = Read();
|
|
OperatorType CompoundOperator = GetCompoundAssignmentOperatorType(Operator.Type);
|
|
Expression Source = ParseExpression();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
if (CompoundOperator == OperatorType.None)
|
|
{
|
|
return new AssignmentStatement(target, Operator.Span.Start, Source, SpanFrom(target.Span.Start), ParseTrailingComments(), isSetStatement);
|
|
}
|
|
return new CompoundAssignmentStatement(CompoundOperator, target, Operator.Span.Start, Source, SpanFrom(target.Span.Start), ParseTrailingComments());
|
|
}
|
|
|
|
private Statement ParseLocalDeclarationStatement()
|
|
{
|
|
Token Start = Peek();
|
|
ModifierCollection Modifiers = ParseDeclarationModifierList();
|
|
ValidateModifierList(Modifiers, ModifierTypes.Static | ModifierTypes.Dim | ModifierTypes.Const);
|
|
if (Modifiers == null)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedModifier, Peek());
|
|
}
|
|
else if (Modifiers.Count > 1)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.InvalidVariableModifiers, Modifiers.Span);
|
|
}
|
|
return new LocalDeclarationStatement(Modifiers, ParseVariableDeclarators(), SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
|
|
private Statement ParseLabelStatement()
|
|
{
|
|
SimpleName Name = null;
|
|
Token Start = Peek();
|
|
bool IsLineNumber = default(bool);
|
|
ParseLabelReference(ref Name, ref IsLineNumber);
|
|
return new LabelStatement(Name, IsLineNumber, SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
|
|
private Statement ParseExpressionBlockStatement(TreeType blockType)
|
|
{
|
|
Token Start = Read();
|
|
Expression Expression = ParseExpression();
|
|
Statement EndStatement = null;
|
|
List<Comment> Comments = null;
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
StatementCollection StatementCollection = ParseStatementBlock(SpanFrom(Start), blockType, ref Comments, ref EndStatement);
|
|
switch (blockType)
|
|
{
|
|
case TreeType.WithBlockStatement:
|
|
return new WithBlockStatement(Expression, StatementCollection, (EndBlockStatement)EndStatement, SpanFrom(Start), Comments);
|
|
case TreeType.SyncLockBlockStatement:
|
|
return new SyncLockBlockStatement(Expression, StatementCollection, (EndBlockStatement)EndStatement, SpanFrom(Start), Comments);
|
|
case TreeType.WhileBlockStatement:
|
|
return new WhileBlockStatement(Expression, StatementCollection, (EndBlockStatement)EndStatement, SpanFrom(Start), Comments);
|
|
default:
|
|
Debug.Assert(condition: false, "Unexpected!");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private Statement ParseUsingBlockStatement()
|
|
{
|
|
Token Start = Read();
|
|
Expression Expression = null;
|
|
VariableDeclaratorCollection VariableDeclarators = null;
|
|
Statement EndStatement = null;
|
|
List<Comment> Comments = null;
|
|
Token NextToken = PeekAheadOne();
|
|
if (NextToken.Type == TokenType.As || NextToken.Type == TokenType.Equals)
|
|
{
|
|
VariableDeclarators = ParseVariableDeclarators();
|
|
}
|
|
else
|
|
{
|
|
Expression = ParseExpression();
|
|
}
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
StatementCollection StatementCollection = ParseStatementBlock(SpanFrom(Start), TreeType.UsingBlockStatement, ref Comments, ref EndStatement);
|
|
if (Expression == null)
|
|
{
|
|
return new UsingBlockStatement(VariableDeclarators, StatementCollection, (EndBlockStatement)EndStatement, SpanFrom(Start), Comments);
|
|
}
|
|
return new UsingBlockStatement(Expression, StatementCollection, (EndBlockStatement)EndStatement, SpanFrom(Start), Comments);
|
|
}
|
|
|
|
private Expression ParseOptionalWhileUntilClause(ref bool isWhile, ref Location whileOrUntilLocation)
|
|
{
|
|
Expression Expression = null;
|
|
if (!CanEndStatement(Peek()))
|
|
{
|
|
Token Token = Peek();
|
|
if (Token.Type == TokenType.While || Token.AsUnreservedKeyword() == TokenType.Until)
|
|
{
|
|
isWhile = Token.Type == TokenType.While;
|
|
whileOrUntilLocation = ReadLocation();
|
|
Expression = ParseExpression();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.SyntaxError, Peek());
|
|
ResyncAt();
|
|
}
|
|
}
|
|
return Expression;
|
|
}
|
|
|
|
private Statement ParseDoBlockStatement()
|
|
{
|
|
Token Start = Read();
|
|
Statement EndStatement = null;
|
|
List<Comment> Comments = null;
|
|
bool IsWhile = default(bool);
|
|
Location WhileOrUntilLocation = default(Location);
|
|
Expression Expression = ParseOptionalWhileUntilClause(ref IsWhile, ref WhileOrUntilLocation);
|
|
StatementCollection StatementCollection = ParseStatementBlock(SpanFrom(Start), TreeType.DoBlockStatement, ref Comments, ref EndStatement);
|
|
LoopStatement LoopStatement = (LoopStatement)EndStatement;
|
|
if (Expression != null && LoopStatement != null && LoopStatement.Expression != null)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.LoopDoubleCondition, LoopStatement.Expression.Span);
|
|
}
|
|
return new DoBlockStatement(Expression, IsWhile, WhileOrUntilLocation, StatementCollection, LoopStatement, SpanFrom(Start), Comments);
|
|
}
|
|
|
|
private Statement ParseLoopStatement()
|
|
{
|
|
Token Start = Read();
|
|
bool IsWhile = default(bool);
|
|
Location WhileOrUntilLocation = default(Location);
|
|
Expression Expression = ParseOptionalWhileUntilClause(ref IsWhile, ref WhileOrUntilLocation);
|
|
return new LoopStatement(Expression, IsWhile, WhileOrUntilLocation, SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
|
|
private Expression ParseForLoopControlVariable(ref VariableDeclarator variableDeclarator)
|
|
{
|
|
Token Start = Peek();
|
|
if (Start.Type == TokenType.Identifier)
|
|
{
|
|
Token NextToken = PeekAheadOne();
|
|
Expression Expression = null;
|
|
if (NextToken.Type == TokenType.As)
|
|
{
|
|
variableDeclarator = ParseForLoopVariableDeclarator(ref Expression);
|
|
return Expression;
|
|
}
|
|
if (NextToken.Type == TokenType.LeftParenthesis && PeekAheadFor(TokenType.As, TokenType.In, TokenType.Equals) == TokenType.As)
|
|
{
|
|
variableDeclarator = ParseForLoopVariableDeclarator(ref Expression);
|
|
return Expression;
|
|
}
|
|
}
|
|
return ParseBinaryOperatorExpression(PrecedenceLevel.Relational);
|
|
}
|
|
|
|
private Statement ParseForBlockStatement()
|
|
{
|
|
Token Start = Read();
|
|
if (Peek().Type != TokenType.Each)
|
|
{
|
|
Expression LowerBoundExpression = null;
|
|
Expression UpperBoundExpression = null;
|
|
Expression StepExpression = null;
|
|
VariableDeclarator VariableDeclarator2 = null;
|
|
Statement NextStatement2 = null;
|
|
List<Comment> Comments2 = null;
|
|
Expression ControlExpression2 = ParseForLoopControlVariable(ref VariableDeclarator2);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Equals, TokenType.To);
|
|
}
|
|
Location EqualLocation = default(Location);
|
|
if (Peek().Type == TokenType.Equals)
|
|
{
|
|
EqualLocation = ReadLocation();
|
|
LowerBoundExpression = ParseExpression();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.To);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.SyntaxError, Peek());
|
|
ResyncAt(TokenType.To);
|
|
}
|
|
Location ToLocation = default(Location);
|
|
if (Peek().Type == TokenType.To)
|
|
{
|
|
ToLocation = ReadLocation();
|
|
UpperBoundExpression = ParseExpression();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Step);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.SyntaxError, Peek());
|
|
ResyncAt(TokenType.Step);
|
|
}
|
|
Location StepLocation = default(Location);
|
|
if (Peek().Type == TokenType.Step)
|
|
{
|
|
StepLocation = ReadLocation();
|
|
StepExpression = ParseExpression();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
}
|
|
StatementCollection Statements2 = ParseStatementBlock(SpanFrom(Start), TreeType.ForBlockStatement, ref Comments2, ref NextStatement2);
|
|
return new ForBlockStatement(ControlExpression2, VariableDeclarator2, EqualLocation, LowerBoundExpression, ToLocation, UpperBoundExpression, StepLocation, StepExpression, Statements2, (NextStatement)NextStatement2, SpanFrom(Start), Comments2);
|
|
}
|
|
VariableDeclarator VariableDeclarator = null;
|
|
Expression CollectionExpression = null;
|
|
Statement NextStatement = null;
|
|
List<Comment> Comments = null;
|
|
Location EachLocation = ReadLocation();
|
|
Expression ControlExpression = ParseForLoopControlVariable(ref VariableDeclarator);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.In);
|
|
}
|
|
Location InLocation = default(Location);
|
|
if (Peek().Type == TokenType.In)
|
|
{
|
|
InLocation = ReadLocation();
|
|
CollectionExpression = ParseExpression();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.SyntaxError, Peek());
|
|
ResyncAt();
|
|
}
|
|
StatementCollection Statements = ParseStatementBlock(SpanFrom(Start), TreeType.ForBlockStatement, ref Comments, ref NextStatement);
|
|
return new ForEachBlockStatement(EachLocation, ControlExpression, VariableDeclarator, InLocation, CollectionExpression, Statements, (NextStatement)NextStatement, SpanFrom(Start), Comments);
|
|
}
|
|
|
|
private Statement ParseNextStatement()
|
|
{
|
|
Token Start = Read();
|
|
return new NextStatement(ParseExpressionList(), SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
|
|
private Statement ParseTryBlockStatement()
|
|
{
|
|
Token Start = Read();
|
|
Statement EndBlockStatement = null;
|
|
List<Statement> CatchBlocks = new List<Statement>();
|
|
StatementCollection CatchBlockList = null;
|
|
FinallyBlockStatement FinallyBlock = null;
|
|
List<Comment> Comments = null;
|
|
StatementCollection TryStatementList = ParseStatementBlock(SpanFrom(Start), TreeType.TryBlockStatement, ref Comments, ref EndBlockStatement);
|
|
while (EndBlockStatement != null && EndBlockStatement.Type != TreeType.EndBlockStatement)
|
|
{
|
|
if (EndBlockStatement.Type == TreeType.CatchStatement)
|
|
{
|
|
CatchStatement CatchStatement = (CatchStatement)EndBlockStatement;
|
|
Span span = CatchStatement.Span;
|
|
List<Comment> Comments2 = null;
|
|
StatementCollection StatementCollection = ParseStatementBlock(span, TreeType.CatchBlockStatement, ref Comments2, ref EndBlockStatement);
|
|
CatchBlocks.Add(new CatchBlockStatement(CatchStatement, StatementCollection, SpanFrom(CatchStatement, EndBlockStatement), null));
|
|
}
|
|
else
|
|
{
|
|
FinallyStatement FinallyStatement = (FinallyStatement)EndBlockStatement;
|
|
Span span2 = FinallyStatement.Span;
|
|
List<Comment> Comments2 = null;
|
|
StatementCollection StatementCollection = ParseStatementBlock(span2, TreeType.FinallyBlockStatement, ref Comments2, ref EndBlockStatement);
|
|
FinallyBlock = new FinallyBlockStatement(FinallyStatement, StatementCollection, SpanFrom(FinallyStatement, EndBlockStatement), null);
|
|
}
|
|
}
|
|
if (CatchBlocks.Count > 0)
|
|
{
|
|
CatchBlockList = new StatementCollection(CatchBlocks, null, new Span(((CatchBlockStatement)CatchBlocks[0]).Span.Start, ((CatchBlockStatement)CatchBlocks[checked(CatchBlocks.Count - 1)]).Span.Finish));
|
|
}
|
|
return new TryBlockStatement(TryStatementList, CatchBlockList, FinallyBlock, (EndBlockStatement)EndBlockStatement, SpanFrom(Start), Comments);
|
|
}
|
|
|
|
private Statement ParseCatchStatement()
|
|
{
|
|
Token Start = Read();
|
|
SimpleName Name = null;
|
|
TypeName Type = null;
|
|
Expression Filter = null;
|
|
Location AsLocation = default(Location);
|
|
if (Peek().Type == TokenType.Identifier)
|
|
{
|
|
Name = ParseSimpleName(allowKeyword: false);
|
|
if (Peek().Type == TokenType.As)
|
|
{
|
|
AsLocation = ReadLocation();
|
|
Type = ParseTypeName(allowArrayType: false);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.When);
|
|
}
|
|
}
|
|
}
|
|
Location WhenLocation = default(Location);
|
|
if (Peek().Type == TokenType.When)
|
|
{
|
|
WhenLocation = ReadLocation();
|
|
Filter = ParseExpression();
|
|
}
|
|
return new CatchStatement(Name, AsLocation, Type, WhenLocation, Filter, SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
|
|
private Statement ParseCaseStatement()
|
|
{
|
|
Token Start = Read();
|
|
Token CasesStart = Peek();
|
|
if (Peek().Type == TokenType.Else)
|
|
{
|
|
return new CaseElseStatement(ReadLocation(), SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
List<Location> CommaLocations = new List<Location>();
|
|
List<CaseClause> Cases = new List<CaseClause>();
|
|
do
|
|
{
|
|
if (Cases.Count > 0)
|
|
{
|
|
CommaLocations.Add(ReadLocation());
|
|
}
|
|
Cases.Add(ParseCase());
|
|
}
|
|
while (Peek().Type == TokenType.Comma);
|
|
return new CaseStatement(new CaseClauseCollection(Cases, CommaLocations, SpanFrom(CasesStart)), SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
|
|
private Statement ParseSelectBlockStatement()
|
|
{
|
|
Token Start = Read();
|
|
Statement EndBlockStatement = null;
|
|
List<Statement> CaseBlocks = new List<Statement>();
|
|
StatementCollection CaseBlockList = null;
|
|
CaseElseBlockStatement CaseElseBlockStatement = null;
|
|
List<Comment> Comments = null;
|
|
Location CaseLocation = default(Location);
|
|
if (Peek().Type == TokenType.Case)
|
|
{
|
|
CaseLocation = ReadLocation();
|
|
}
|
|
Expression SelectExpression = ParseExpression();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
StatementCollection Statements = ParseStatementBlock(SpanFrom(Start), TreeType.SelectBlockStatement, ref Comments, ref EndBlockStatement);
|
|
if (Statements != null && Statements.Count != 0)
|
|
{
|
|
foreach (Statement Statement in Statements)
|
|
{
|
|
if (Statement.Type != TreeType.EmptyStatement)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedCase, Statements.Span);
|
|
}
|
|
}
|
|
}
|
|
while (EndBlockStatement != null && EndBlockStatement.Type != TreeType.EndBlockStatement)
|
|
{
|
|
Statement CaseStatement = EndBlockStatement;
|
|
if (CaseStatement.Type == TreeType.CaseStatement)
|
|
{
|
|
Span span = CaseStatement.Span;
|
|
List<Comment> Comments2 = null;
|
|
StatementCollection CaseStatements = ParseStatementBlock(span, TreeType.CaseBlockStatement, ref Comments2, ref EndBlockStatement);
|
|
CaseBlocks.Add(new CaseBlockStatement((CaseStatement)CaseStatement, CaseStatements, SpanFrom(CaseStatement, EndBlockStatement), null));
|
|
}
|
|
else
|
|
{
|
|
Span span2 = CaseStatement.Span;
|
|
List<Comment> Comments2 = null;
|
|
StatementCollection CaseStatements = ParseStatementBlock(span2, TreeType.CaseElseBlockStatement, ref Comments2, ref EndBlockStatement);
|
|
CaseElseBlockStatement = new CaseElseBlockStatement((CaseElseStatement)CaseStatement, CaseStatements, SpanFrom(CaseStatement, EndBlockStatement), null);
|
|
}
|
|
}
|
|
if (CaseBlocks.Count > 0)
|
|
{
|
|
CaseBlockList = new StatementCollection(CaseBlocks, null, new Span(((CaseBlockStatement)CaseBlocks[0]).Span.Start, ((CaseBlockStatement)CaseBlocks[checked(CaseBlocks.Count - 1)]).Span.Finish));
|
|
}
|
|
return new SelectBlockStatement(CaseLocation, SelectExpression, Statements, CaseBlockList, CaseElseBlockStatement, (EndBlockStatement)EndBlockStatement, SpanFrom(Start), Comments);
|
|
}
|
|
|
|
private Statement ParseElseIfStatement()
|
|
{
|
|
Token Start = Read();
|
|
Expression Expression = ParseExpression();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Then);
|
|
}
|
|
Location ThenLocation = default(Location);
|
|
if (Peek().Type == TokenType.Then)
|
|
{
|
|
ThenLocation = ReadLocation();
|
|
}
|
|
return new ElseIfStatement(Expression, ThenLocation, SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
|
|
private Statement ParseIfBlockStatement()
|
|
{
|
|
Token Start = Read();
|
|
Statement EndBlockStatement = null;
|
|
List<Statement> ElseIfBlocks = new List<Statement>();
|
|
StatementCollection ElseIfBlockList = null;
|
|
ElseBlockStatement ElseBlockStatement = null;
|
|
List<Comment> Comments = null;
|
|
Expression Expression = ParseExpression();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Then);
|
|
}
|
|
Location ThenLocation = default(Location);
|
|
StatementCollection IfStatements;
|
|
if (Peek().Type == TokenType.Then)
|
|
{
|
|
ThenLocation = ReadLocation();
|
|
if (!CanEndStatement(Peek()))
|
|
{
|
|
StatementCollection ElseStatements = null;
|
|
AtBeginningOfLine = false;
|
|
IfStatements = ParseLineIfStatementBlock();
|
|
Location ElseLocation = default(Location);
|
|
if (Peek().Type == TokenType.Else)
|
|
{
|
|
ElseLocation = ReadLocation();
|
|
ElseStatements = ParseLineIfStatementBlock();
|
|
}
|
|
return new LineIfStatement(Expression, ThenLocation, IfStatements, ElseLocation, ElseStatements, SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
}
|
|
IfStatements = ParseStatementBlock(SpanFrom(Start), TreeType.IfBlockStatement, ref Comments, ref EndBlockStatement);
|
|
while (EndBlockStatement != null && EndBlockStatement.Type != TreeType.EndBlockStatement)
|
|
{
|
|
Statement ElseStatement = EndBlockStatement;
|
|
if (ElseStatement.Type == TreeType.ElseIfStatement)
|
|
{
|
|
Span span = ElseStatement.Span;
|
|
List<Comment> Comments2 = null;
|
|
StatementCollection Statements = ParseStatementBlock(span, TreeType.ElseIfBlockStatement, ref Comments2, ref EndBlockStatement);
|
|
ElseIfBlocks.Add(new ElseIfBlockStatement((ElseIfStatement)ElseStatement, Statements, SpanFrom(ElseStatement, EndBlockStatement), null));
|
|
}
|
|
else
|
|
{
|
|
Span span2 = ElseStatement.Span;
|
|
List<Comment> Comments2 = null;
|
|
StatementCollection Statements = ParseStatementBlock(span2, TreeType.ElseBlockStatement, ref Comments2, ref EndBlockStatement);
|
|
ElseBlockStatement = new ElseBlockStatement((ElseStatement)ElseStatement, Statements, SpanFrom(ElseStatement, EndBlockStatement), null);
|
|
}
|
|
}
|
|
if (ElseIfBlocks.Count > 0)
|
|
{
|
|
ElseIfBlockList = new StatementCollection(ElseIfBlocks, null, new Span(ElseIfBlocks[0].Span.Start, ElseIfBlocks[checked(ElseIfBlocks.Count - 1)].Span.Finish));
|
|
}
|
|
return new IfBlockStatement(Expression, ThenLocation, IfStatements, ElseIfBlockList, ElseBlockStatement, (EndBlockStatement)EndBlockStatement, SpanFrom(Start), Comments);
|
|
}
|
|
|
|
private Statement ParseStatement(ref Token terminator)
|
|
{
|
|
Token Start = Peek();
|
|
Statement Statement = null;
|
|
ErrorInConstruct = false;
|
|
switch (Start.Type)
|
|
{
|
|
case TokenType.GoTo:
|
|
Statement = ParseGotoStatement();
|
|
break;
|
|
case TokenType.Exit:
|
|
Statement = ParseExitStatement();
|
|
break;
|
|
case TokenType.Continue:
|
|
Statement = ParseContinueStatement();
|
|
break;
|
|
case TokenType.Stop:
|
|
Statement = new StopStatement(SpanFrom(Read()), ParseTrailingComments());
|
|
break;
|
|
case TokenType.End:
|
|
Statement = ParseEndStatement();
|
|
break;
|
|
case TokenType.Wend:
|
|
Statement = ParseWendStatement();
|
|
break;
|
|
case TokenType.Return:
|
|
Statement = ParseExpressionStatement(TreeType.ReturnStatement, operandOptional: true);
|
|
break;
|
|
case TokenType.RaiseEvent:
|
|
Statement = ParseRaiseEventStatement();
|
|
break;
|
|
case TokenType.AddHandler:
|
|
case TokenType.RemoveHandler:
|
|
Statement = ParseHandlerStatement();
|
|
break;
|
|
case TokenType.Error:
|
|
Statement = ParseExpressionStatement(TreeType.ErrorStatement, operandOptional: false);
|
|
break;
|
|
case TokenType.On:
|
|
Statement = ParseOnErrorStatement();
|
|
break;
|
|
case TokenType.Resume:
|
|
Statement = ParseResumeStatement();
|
|
break;
|
|
case TokenType.ReDim:
|
|
Statement = ParseReDimStatement();
|
|
break;
|
|
case TokenType.Erase:
|
|
Statement = ParseEraseStatement();
|
|
break;
|
|
case TokenType.Call:
|
|
Statement = ParseCallStatement();
|
|
break;
|
|
case TokenType.IntegerLiteral:
|
|
if (AtBeginningOfLine)
|
|
{
|
|
Statement = ParseLabelStatement();
|
|
break;
|
|
}
|
|
goto default;
|
|
case TokenType.Set:
|
|
{
|
|
Read();
|
|
Expression Target2 = ParseBinaryOperatorExpression(PrecedenceLevel.Power);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Equals);
|
|
}
|
|
if (GetAssignmentOperator(Peek().Type) != 0)
|
|
{
|
|
Statement = ParseAssignmentStatement(Target2, isSetStatement: true);
|
|
break;
|
|
}
|
|
goto default;
|
|
}
|
|
case TokenType.Identifier:
|
|
if (AtBeginningOfLine)
|
|
{
|
|
Read();
|
|
bool IsLabel = Peek().Type == TokenType.Colon;
|
|
Backtrack(Start);
|
|
if (IsLabel)
|
|
{
|
|
Statement = ParseLabelStatement();
|
|
break;
|
|
}
|
|
}
|
|
if (Start.AsUnreservedKeyword() == TokenType.Mid)
|
|
{
|
|
Statement = ParseMidAssignmentStatement();
|
|
}
|
|
if (Statement == null)
|
|
{
|
|
goto case TokenType.Boolean;
|
|
}
|
|
break;
|
|
case TokenType.Boolean:
|
|
case TokenType.Byte:
|
|
case TokenType.CBool:
|
|
case TokenType.CByte:
|
|
case TokenType.CChar:
|
|
case TokenType.CDate:
|
|
case TokenType.CDec:
|
|
case TokenType.CDbl:
|
|
case TokenType.Char:
|
|
case TokenType.CInt:
|
|
case TokenType.CLng:
|
|
case TokenType.CObj:
|
|
case TokenType.CShort:
|
|
case TokenType.CSng:
|
|
case TokenType.CStr:
|
|
case TokenType.CType:
|
|
case TokenType.Date:
|
|
case TokenType.Decimal:
|
|
case TokenType.DirectCast:
|
|
case TokenType.Double:
|
|
case TokenType.GetType:
|
|
case TokenType.Integer:
|
|
case TokenType.Long:
|
|
case TokenType.Me:
|
|
case TokenType.MyBase:
|
|
case TokenType.MyClass:
|
|
case TokenType.Object:
|
|
case TokenType.Short:
|
|
case TokenType.Single:
|
|
case TokenType.String:
|
|
case TokenType.Exclamation:
|
|
case TokenType.Period:
|
|
{
|
|
Expression Target = ParseBinaryOperatorExpression(PrecedenceLevel.Power);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Equals);
|
|
}
|
|
Statement = ((GetAssignmentOperator(Peek().Type) == TreeType.SyntaxError) ? ParseCallStatement(Target) : ParseAssignmentStatement(Target, isSetStatement: false));
|
|
break;
|
|
}
|
|
case TokenType.Const:
|
|
case TokenType.Default:
|
|
case TokenType.Dim:
|
|
case TokenType.Friend:
|
|
case TokenType.MustInherit:
|
|
case TokenType.MustOverride:
|
|
case TokenType.Narrowing:
|
|
case TokenType.NotInheritable:
|
|
case TokenType.NotOverridable:
|
|
case TokenType.Overloads:
|
|
case TokenType.Overridable:
|
|
case TokenType.Overrides:
|
|
case TokenType.Partial:
|
|
case TokenType.Private:
|
|
case TokenType.Protected:
|
|
case TokenType.Public:
|
|
case TokenType.ReadOnly:
|
|
case TokenType.Shadows:
|
|
case TokenType.Shared:
|
|
case TokenType.Static:
|
|
case TokenType.Widening:
|
|
case TokenType.WithEvents:
|
|
case TokenType.WriteOnly:
|
|
Statement = ParseLocalDeclarationStatement();
|
|
break;
|
|
case TokenType.With:
|
|
Statement = ParseExpressionBlockStatement(TreeType.WithBlockStatement);
|
|
break;
|
|
case TokenType.SyncLock:
|
|
Statement = ParseExpressionBlockStatement(TreeType.SyncLockBlockStatement);
|
|
break;
|
|
case TokenType.Using:
|
|
Statement = ParseUsingBlockStatement();
|
|
break;
|
|
case TokenType.While:
|
|
Statement = ParseExpressionBlockStatement(TreeType.WhileBlockStatement);
|
|
break;
|
|
case TokenType.Do:
|
|
Statement = ParseDoBlockStatement();
|
|
break;
|
|
case TokenType.Loop:
|
|
Statement = ParseLoopStatement();
|
|
break;
|
|
case TokenType.For:
|
|
Statement = ParseForBlockStatement();
|
|
break;
|
|
case TokenType.Next:
|
|
Statement = ParseNextStatement();
|
|
break;
|
|
case TokenType.Throw:
|
|
Statement = ParseExpressionStatement(TreeType.ThrowStatement, operandOptional: true);
|
|
break;
|
|
case TokenType.Try:
|
|
Statement = ParseTryBlockStatement();
|
|
break;
|
|
case TokenType.Catch:
|
|
Statement = ParseCatchStatement();
|
|
break;
|
|
case TokenType.Finally:
|
|
Statement = new FinallyStatement(SpanFrom(Read()), ParseTrailingComments());
|
|
break;
|
|
case TokenType.Select:
|
|
Statement = ParseSelectBlockStatement();
|
|
break;
|
|
case TokenType.Case:
|
|
Statement = ParseCaseStatement();
|
|
CanContinueWithoutLineTerminator = true;
|
|
break;
|
|
case TokenType.If:
|
|
Statement = ParseIfBlockStatement();
|
|
break;
|
|
case TokenType.Else:
|
|
Statement = new ElseStatement(SpanFrom(Read()), ParseTrailingComments());
|
|
break;
|
|
case TokenType.ElseIf:
|
|
Statement = ParseElseIfStatement();
|
|
break;
|
|
case TokenType.Comment:
|
|
{
|
|
List<Comment> Comments = new List<Comment>();
|
|
Token LastTerminator;
|
|
do
|
|
{
|
|
CommentToken CommentToken = (CommentToken)Scanner.Read();
|
|
Comments.Add(new Comment(CommentToken.Comment, CommentToken.IsREM, CommentToken.Span));
|
|
LastTerminator = Read();
|
|
}
|
|
while (Peek().Type == TokenType.Comment);
|
|
Backtrack(LastTerminator);
|
|
Statement = new EmptyStatement(SpanFrom(Start), new List<Comment>(Comments));
|
|
break;
|
|
}
|
|
default:
|
|
ReportSyntaxError(SyntaxErrorType.SyntaxError, Peek());
|
|
break;
|
|
case TokenType.LineTerminator:
|
|
case TokenType.Colon:
|
|
break;
|
|
}
|
|
terminator = VerifyEndOfStatement();
|
|
return Statement;
|
|
}
|
|
|
|
private Statement ParseStatementOrDeclaration(ref Token terminator)
|
|
{
|
|
Token Start = Peek();
|
|
Statement Statement = null;
|
|
ErrorInConstruct = false;
|
|
Location StartLocation = Peek().Span.Start;
|
|
switch (Start.Type)
|
|
{
|
|
case TokenType.GoTo:
|
|
Statement = ParseGotoStatement();
|
|
break;
|
|
case TokenType.Exit:
|
|
Statement = ParseExitStatement();
|
|
break;
|
|
case TokenType.Continue:
|
|
Statement = ParseContinueStatement();
|
|
break;
|
|
case TokenType.Stop:
|
|
Statement = new StopStatement(SpanFrom(Read()), ParseTrailingComments());
|
|
break;
|
|
case TokenType.End:
|
|
Statement = ParseEndStatement();
|
|
break;
|
|
case TokenType.Wend:
|
|
Statement = ParseWendStatement();
|
|
break;
|
|
case TokenType.Return:
|
|
Statement = ParseExpressionStatement(TreeType.ReturnStatement, operandOptional: true);
|
|
break;
|
|
case TokenType.RaiseEvent:
|
|
Statement = ParseRaiseEventStatement();
|
|
break;
|
|
case TokenType.AddHandler:
|
|
case TokenType.RemoveHandler:
|
|
Statement = ParseHandlerStatement();
|
|
break;
|
|
case TokenType.Error:
|
|
Statement = ParseExpressionStatement(TreeType.ErrorStatement, operandOptional: false);
|
|
break;
|
|
case TokenType.On:
|
|
Statement = ParseOnErrorStatement();
|
|
break;
|
|
case TokenType.Resume:
|
|
Statement = ParseResumeStatement();
|
|
break;
|
|
case TokenType.ReDim:
|
|
Statement = ParseReDimStatement();
|
|
break;
|
|
case TokenType.Erase:
|
|
Statement = ParseEraseStatement();
|
|
break;
|
|
case TokenType.Call:
|
|
Statement = ParseCallStatement();
|
|
break;
|
|
case TokenType.IntegerLiteral:
|
|
if (AtBeginningOfLine)
|
|
{
|
|
Statement = ParseLabelStatement();
|
|
break;
|
|
}
|
|
goto default;
|
|
case TokenType.Set:
|
|
{
|
|
Read();
|
|
Expression Target2 = ParseBinaryOperatorExpression(PrecedenceLevel.Power);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Equals);
|
|
}
|
|
if (GetAssignmentOperator(Peek().Type) != 0)
|
|
{
|
|
Statement = ParseAssignmentStatement(Target2, isSetStatement: true);
|
|
break;
|
|
}
|
|
goto default;
|
|
}
|
|
case TokenType.Identifier:
|
|
if (AtBeginningOfLine)
|
|
{
|
|
Read();
|
|
bool IsLabel = Peek().Type == TokenType.Colon;
|
|
Backtrack(Start);
|
|
if (IsLabel)
|
|
{
|
|
Statement = ParseLabelStatement();
|
|
break;
|
|
}
|
|
}
|
|
if (Start.AsUnreservedKeyword() == TokenType.Mid)
|
|
{
|
|
Statement = ParseMidAssignmentStatement();
|
|
}
|
|
if (Statement == null)
|
|
{
|
|
goto case TokenType.Boolean;
|
|
}
|
|
break;
|
|
case TokenType.Boolean:
|
|
case TokenType.Byte:
|
|
case TokenType.CBool:
|
|
case TokenType.CByte:
|
|
case TokenType.CChar:
|
|
case TokenType.CDate:
|
|
case TokenType.CDec:
|
|
case TokenType.CDbl:
|
|
case TokenType.Char:
|
|
case TokenType.CInt:
|
|
case TokenType.CLng:
|
|
case TokenType.CObj:
|
|
case TokenType.CShort:
|
|
case TokenType.CSng:
|
|
case TokenType.CStr:
|
|
case TokenType.CType:
|
|
case TokenType.Date:
|
|
case TokenType.Decimal:
|
|
case TokenType.DirectCast:
|
|
case TokenType.Double:
|
|
case TokenType.GetType:
|
|
case TokenType.Integer:
|
|
case TokenType.Long:
|
|
case TokenType.Me:
|
|
case TokenType.MyBase:
|
|
case TokenType.MyClass:
|
|
case TokenType.Object:
|
|
case TokenType.Short:
|
|
case TokenType.Single:
|
|
case TokenType.String:
|
|
case TokenType.Exclamation:
|
|
case TokenType.Period:
|
|
{
|
|
Expression Target = ParseBinaryOperatorExpression(PrecedenceLevel.Power);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Equals);
|
|
}
|
|
Statement = ((GetAssignmentOperator(Peek().Type) == TreeType.SyntaxError) ? ParseCallStatement(Target) : ParseAssignmentStatement(Target, isSetStatement: false));
|
|
break;
|
|
}
|
|
case TokenType.Const:
|
|
case TokenType.Default:
|
|
case TokenType.Dim:
|
|
case TokenType.Friend:
|
|
case TokenType.MustInherit:
|
|
case TokenType.MustOverride:
|
|
case TokenType.Narrowing:
|
|
case TokenType.NotInheritable:
|
|
case TokenType.NotOverridable:
|
|
case TokenType.Overloads:
|
|
case TokenType.Overridable:
|
|
case TokenType.Overrides:
|
|
case TokenType.Partial:
|
|
case TokenType.Private:
|
|
case TokenType.Protected:
|
|
case TokenType.Public:
|
|
case TokenType.ReadOnly:
|
|
case TokenType.Shadows:
|
|
case TokenType.Shared:
|
|
case TokenType.Static:
|
|
case TokenType.Widening:
|
|
case TokenType.WithEvents:
|
|
case TokenType.WriteOnly:
|
|
{
|
|
Token NextToken = PeekAheadOne();
|
|
TokenType type = NextToken.Type;
|
|
if (type == TokenType.Default || type == TokenType.Function || type == TokenType.Sub)
|
|
{
|
|
ModifierCollection Modifiers = ParseDeclarationModifierList();
|
|
Statement = ParseMethodDeclaration(StartLocation, null, null);
|
|
}
|
|
else
|
|
{
|
|
Statement = ParseLocalDeclarationStatement();
|
|
}
|
|
break;
|
|
}
|
|
case TokenType.With:
|
|
Statement = ParseExpressionBlockStatement(TreeType.WithBlockStatement);
|
|
break;
|
|
case TokenType.SyncLock:
|
|
Statement = ParseExpressionBlockStatement(TreeType.SyncLockBlockStatement);
|
|
break;
|
|
case TokenType.Using:
|
|
Statement = ParseUsingBlockStatement();
|
|
break;
|
|
case TokenType.While:
|
|
Statement = ParseExpressionBlockStatement(TreeType.WhileBlockStatement);
|
|
break;
|
|
case TokenType.Do:
|
|
Statement = ParseDoBlockStatement();
|
|
break;
|
|
case TokenType.Loop:
|
|
Statement = ParseLoopStatement();
|
|
break;
|
|
case TokenType.For:
|
|
Statement = ParseForBlockStatement();
|
|
break;
|
|
case TokenType.Next:
|
|
Statement = ParseNextStatement();
|
|
break;
|
|
case TokenType.Throw:
|
|
Statement = ParseExpressionStatement(TreeType.ThrowStatement, operandOptional: true);
|
|
break;
|
|
case TokenType.Try:
|
|
Statement = ParseTryBlockStatement();
|
|
break;
|
|
case TokenType.Catch:
|
|
Statement = ParseCatchStatement();
|
|
break;
|
|
case TokenType.Finally:
|
|
Statement = new FinallyStatement(SpanFrom(Read()), ParseTrailingComments());
|
|
break;
|
|
case TokenType.Select:
|
|
Statement = ParseSelectBlockStatement();
|
|
break;
|
|
case TokenType.Case:
|
|
Statement = ParseCaseStatement();
|
|
break;
|
|
case TokenType.If:
|
|
Statement = ParseIfBlockStatement();
|
|
break;
|
|
case TokenType.Else:
|
|
Statement = new ElseStatement(SpanFrom(Read()), ParseTrailingComments());
|
|
break;
|
|
case TokenType.ElseIf:
|
|
Statement = ParseElseIfStatement();
|
|
break;
|
|
case TokenType.Function:
|
|
case TokenType.Sub:
|
|
Statement = ParseMethodDeclaration(StartLocation, null, null);
|
|
break;
|
|
case TokenType.Class:
|
|
Statement = ParseTypeDeclaration(StartLocation, null, null, TreeType.ClassDeclaration);
|
|
break;
|
|
case TokenType.Imports:
|
|
Statement = ParseImportsDeclaration(StartLocation, null, null);
|
|
break;
|
|
case TokenType.Option:
|
|
Statement = ParseOptionDeclaration(StartLocation, null, null);
|
|
break;
|
|
case TokenType.Comment:
|
|
{
|
|
List<Comment> Comments = new List<Comment>();
|
|
Token LastTerminator;
|
|
do
|
|
{
|
|
CommentToken CommentToken = (CommentToken)Scanner.Read();
|
|
Comments.Add(new Comment(CommentToken.Comment, CommentToken.IsREM, CommentToken.Span));
|
|
LastTerminator = Read();
|
|
}
|
|
while (Peek().Type == TokenType.Comment);
|
|
Backtrack(LastTerminator);
|
|
Statement = new EmptyStatement(SpanFrom(Start), new List<Comment>(Comments));
|
|
break;
|
|
}
|
|
default:
|
|
ReportSyntaxError(SyntaxErrorType.SyntaxError, Peek());
|
|
break;
|
|
case TokenType.LineTerminator:
|
|
case TokenType.Colon:
|
|
break;
|
|
}
|
|
terminator = VerifyEndOfStatement();
|
|
return Statement;
|
|
}
|
|
|
|
private StatementCollection ParseStatementBlock(Span blockStartSpan, TreeType blockType, ref List<Comment> Comments, ref Statement endStatement)
|
|
{
|
|
List<Statement> Statements = new List<Statement>();
|
|
List<Location> ColonLocations = new List<Location>();
|
|
bool BlockTerminated = false;
|
|
Debug.Assert(blockType != TreeType.LineIfBlockStatement);
|
|
Comments = ParseTrailingComments();
|
|
Token Terminator = VerifyEndOfStatement();
|
|
CanContinueWithoutLineTerminator = false;
|
|
if (Terminator.Type == TokenType.Colon)
|
|
{
|
|
if (blockType == TreeType.SubDeclaration || blockType == TreeType.FunctionDeclaration || blockType == TreeType.ConstructorDeclaration || blockType == TreeType.OperatorDeclaration || blockType == TreeType.GetAccessorDeclaration || blockType == TreeType.SetAccessorDeclaration || blockType == TreeType.AddHandlerAccessorDeclaration || blockType == TreeType.RemoveHandlerAccessorDeclaration || blockType == TreeType.RaiseEventAccessorDeclaration)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.MethodBodyNotAtLineStart, Terminator.Span);
|
|
}
|
|
ColonLocations.Add(Terminator.Span.Start);
|
|
}
|
|
Token Start = Peek();
|
|
Location StatementsEnd = Start.Span.Finish;
|
|
endStatement = null;
|
|
PushBlockContext(blockType);
|
|
while (Peek().Type != TokenType.EndOfStream)
|
|
{
|
|
Token PreviousTerminator = Terminator;
|
|
Statement Statement = ParseStatement(ref Terminator);
|
|
if (Statement != null)
|
|
{
|
|
if (Statement.Type >= TreeType.LoopStatement && Statement.Type <= TreeType.EndBlockStatement)
|
|
{
|
|
if (StatementEndsBlock(blockType, Statement))
|
|
{
|
|
endStatement = Statement;
|
|
Backtrack(Terminator);
|
|
BlockTerminated = true;
|
|
break;
|
|
}
|
|
bool StatementEndsOuterBlock = false;
|
|
foreach (TreeType BlockContext in BlockContextStack)
|
|
{
|
|
if (StatementEndsBlock(BlockContext, Statement))
|
|
{
|
|
StatementEndsOuterBlock = true;
|
|
break;
|
|
}
|
|
}
|
|
if (StatementEndsOuterBlock)
|
|
{
|
|
ReportMismatchedEndError(blockType, Statement.Span);
|
|
Backtrack(PreviousTerminator);
|
|
BlockTerminated = true;
|
|
break;
|
|
}
|
|
ReportMissingBeginStatementError(blockType, Statement);
|
|
}
|
|
Statements.Add(Statement);
|
|
}
|
|
if (Terminator.Type == TokenType.Colon)
|
|
{
|
|
ColonLocations.Add(Terminator.Span.Start);
|
|
StatementsEnd = Terminator.Span.Finish;
|
|
}
|
|
else
|
|
{
|
|
StatementsEnd = Terminator.Span.Finish;
|
|
}
|
|
}
|
|
if (!BlockTerminated)
|
|
{
|
|
ReportMismatchedEndError(blockType, blockStartSpan);
|
|
}
|
|
PopBlockContext();
|
|
if (Statements.Count == 0 && ColonLocations.Count == 0)
|
|
{
|
|
return null;
|
|
}
|
|
return new StatementCollection(Statements, ColonLocations, new Span(Start.Span.Start, StatementsEnd));
|
|
}
|
|
|
|
private StatementCollection ParseLineIfStatementBlock()
|
|
{
|
|
List<Statement> Statements = new List<Statement>();
|
|
List<Location> ColonLocations = new List<Location>();
|
|
Token Terminator = null;
|
|
Token Start = Peek();
|
|
Location StatementsEnd = Start.Span.Finish;
|
|
PushBlockContext(TreeType.LineIfBlockStatement);
|
|
while (!CanEndStatement(Peek()))
|
|
{
|
|
Statement Statement2 = ParseStatement(ref Terminator);
|
|
if (Statement2 != null)
|
|
{
|
|
if (Statement2.Type >= TreeType.LoopStatement && Statement2.Type <= TreeType.EndBlockStatement)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.EndInLineIf, Statement2.Span);
|
|
}
|
|
Statements.Add(Statement2);
|
|
}
|
|
if (Terminator.Type == TokenType.Colon)
|
|
{
|
|
ColonLocations.Add(Terminator.Span.Start);
|
|
StatementsEnd = Terminator.Span.Finish;
|
|
continue;
|
|
}
|
|
Backtrack(Terminator);
|
|
break;
|
|
}
|
|
if (Terminator.Type == TokenType.End)
|
|
{
|
|
Statement Statement = ParseStatement(ref Terminator);
|
|
if (StatementEndsBlock(CurrentBlockContextType(), Statement))
|
|
{
|
|
Backtrack(Terminator);
|
|
}
|
|
else
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedEndIf, Statement.Span);
|
|
}
|
|
}
|
|
PopBlockContext();
|
|
if (Statements.Count == 0 && ColonLocations.Count == 0)
|
|
{
|
|
return null;
|
|
}
|
|
return new StatementCollection(Statements, ColonLocations, new Span(Start.Span.Start, StatementsEnd));
|
|
}
|
|
|
|
private void ValidateModifierList(ModifierCollection modifiers, ModifierTypes validTypes)
|
|
{
|
|
if (modifiers == null)
|
|
{
|
|
return;
|
|
}
|
|
foreach (Modifier Modifier in modifiers)
|
|
{
|
|
if ((validTypes & Modifier.ModifierType) == 0)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.InvalidModifier, Modifier.Span);
|
|
}
|
|
}
|
|
}
|
|
|
|
private ModifierCollection ParseDeclarationModifierList()
|
|
{
|
|
List<Modifier> Modifiers = new List<Modifier>();
|
|
Token Start = Peek();
|
|
ModifierTypes FoundTypes = default(ModifierTypes);
|
|
while (true)
|
|
{
|
|
ModifierTypes ModifierTypes;
|
|
switch (Peek().Type)
|
|
{
|
|
case TokenType.Public:
|
|
ModifierTypes = ModifierTypes.Public;
|
|
goto IL_01f4;
|
|
case TokenType.Private:
|
|
ModifierTypes = ModifierTypes.Private;
|
|
goto IL_01f4;
|
|
case TokenType.Protected:
|
|
ModifierTypes = ModifierTypes.Protected;
|
|
goto IL_01f4;
|
|
case TokenType.Friend:
|
|
ModifierTypes = ModifierTypes.Friend;
|
|
goto IL_01f4;
|
|
case TokenType.Static:
|
|
ModifierTypes = ModifierTypes.Static;
|
|
goto IL_01f4;
|
|
case TokenType.Shared:
|
|
ModifierTypes = ModifierTypes.Shared;
|
|
goto IL_01f4;
|
|
case TokenType.Shadows:
|
|
ModifierTypes = ModifierTypes.Shadows;
|
|
goto IL_01f4;
|
|
case TokenType.Overloads:
|
|
ModifierTypes = ModifierTypes.Overloads;
|
|
goto IL_01f4;
|
|
case TokenType.MustInherit:
|
|
ModifierTypes = ModifierTypes.MustInherit;
|
|
goto IL_01f4;
|
|
case TokenType.NotInheritable:
|
|
ModifierTypes = ModifierTypes.NotInheritable;
|
|
goto IL_01f4;
|
|
case TokenType.Overrides:
|
|
ModifierTypes = ModifierTypes.Overrides;
|
|
goto IL_01f4;
|
|
case TokenType.Overridable:
|
|
ModifierTypes = ModifierTypes.Overridable;
|
|
goto IL_01f4;
|
|
case TokenType.NotOverridable:
|
|
ModifierTypes = ModifierTypes.NotOverridable;
|
|
goto IL_01f4;
|
|
case TokenType.MustOverride:
|
|
ModifierTypes = ModifierTypes.MustOverride;
|
|
goto IL_01f4;
|
|
case TokenType.Partial:
|
|
ModifierTypes = ModifierTypes.Partial;
|
|
goto IL_01f4;
|
|
case TokenType.ReadOnly:
|
|
ModifierTypes = ModifierTypes.ReadOnly;
|
|
goto IL_01f4;
|
|
case TokenType.WriteOnly:
|
|
ModifierTypes = ModifierTypes.WriteOnly;
|
|
goto IL_01f4;
|
|
case TokenType.Dim:
|
|
ModifierTypes = ModifierTypes.Dim;
|
|
goto IL_01f4;
|
|
case TokenType.Const:
|
|
ModifierTypes = ModifierTypes.Const;
|
|
goto IL_01f4;
|
|
case TokenType.Default:
|
|
ModifierTypes = ModifierTypes.Default;
|
|
goto IL_01f4;
|
|
case TokenType.WithEvents:
|
|
ModifierTypes = ModifierTypes.WithEvents;
|
|
goto IL_01f4;
|
|
case TokenType.Widening:
|
|
ModifierTypes = ModifierTypes.Widening;
|
|
goto IL_01f4;
|
|
case TokenType.Narrowing:
|
|
ModifierTypes = ModifierTypes.Narrowing;
|
|
goto IL_01f4;
|
|
default:
|
|
{
|
|
if (Modifiers.Count == 0)
|
|
{
|
|
return null;
|
|
}
|
|
return new ModifierCollection(Modifiers, SpanFrom(Start));
|
|
}
|
|
IL_01f4:
|
|
if ((FoundTypes & ModifierTypes) != 0)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.DuplicateModifier, Peek());
|
|
}
|
|
else
|
|
{
|
|
FoundTypes |= ModifierTypes;
|
|
}
|
|
break;
|
|
}
|
|
Modifiers.Add(new Modifier(ModifierTypes, SpanFrom(Read())));
|
|
}
|
|
}
|
|
|
|
private ModifierCollection ParseParameterModifierList()
|
|
{
|
|
List<Modifier> Modifiers = new List<Modifier>();
|
|
Token Start = Peek();
|
|
ModifierTypes FoundTypes = default(ModifierTypes);
|
|
while (true)
|
|
{
|
|
TokenType type = Peek().Type;
|
|
ModifierTypes ModifierTypes;
|
|
if (type <= TokenType.ByVal)
|
|
{
|
|
if (type != TokenType.ByRef)
|
|
{
|
|
if (type != TokenType.ByVal)
|
|
{
|
|
break;
|
|
}
|
|
ModifierTypes = ModifierTypes.ByVal;
|
|
}
|
|
else
|
|
{
|
|
ModifierTypes = ModifierTypes.ByRef;
|
|
}
|
|
}
|
|
else if (type != TokenType.Optional)
|
|
{
|
|
if (type != TokenType.ParamArray)
|
|
{
|
|
break;
|
|
}
|
|
ModifierTypes = ModifierTypes.ParamArray;
|
|
}
|
|
else
|
|
{
|
|
ModifierTypes = ModifierTypes.Optional;
|
|
}
|
|
if ((FoundTypes & ModifierTypes) != 0)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.DuplicateModifier, Peek());
|
|
}
|
|
else
|
|
{
|
|
FoundTypes |= ModifierTypes;
|
|
}
|
|
Modifiers.Add(new Modifier(ModifierTypes, SpanFrom(Read())));
|
|
}
|
|
if (Modifiers.Count == 0)
|
|
{
|
|
return null;
|
|
}
|
|
return new ModifierCollection(Modifiers, SpanFrom(Start));
|
|
}
|
|
|
|
private VariableDeclarator ParseVariableDeclarator()
|
|
{
|
|
Token DeclarationStart = Peek();
|
|
List<Location> VariableNamesCommaLocations = new List<Location>();
|
|
List<VariableName> VariableNames = new List<VariableName>();
|
|
TypeName Type = null;
|
|
ArgumentCollection NewArguments = null;
|
|
Initializer Initializer = null;
|
|
do
|
|
{
|
|
if (VariableNames.Count > 0)
|
|
{
|
|
VariableNamesCommaLocations.Add(ReadLocation());
|
|
}
|
|
VariableName VariableName = ParseVariableName(allowExplicitArraySizes: true);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.As, TokenType.Comma, TokenType.New, TokenType.Equals);
|
|
}
|
|
VariableNames.Add(VariableName);
|
|
}
|
|
while (Peek().Type == TokenType.Comma);
|
|
VariableNameCollection VariableNameCollection = new VariableNameCollection(VariableNames, VariableNamesCommaLocations, SpanFrom(DeclarationStart));
|
|
Location AsLocation = default(Location);
|
|
Location NewLocation = default(Location);
|
|
if (Peek().Type == TokenType.As)
|
|
{
|
|
AsLocation = ReadLocation();
|
|
if (Peek().Type == TokenType.New)
|
|
{
|
|
NewLocation = ReadLocation();
|
|
Type = ParseTypeName(allowArrayType: false);
|
|
NewArguments = ParseArguments();
|
|
}
|
|
else
|
|
{
|
|
Type = ParseTypeName(allowArrayType: true);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Comma, TokenType.Equals);
|
|
}
|
|
}
|
|
}
|
|
Location EqualsLocation = default(Location);
|
|
if (Peek().Type == TokenType.Equals && !NewLocation.IsValid)
|
|
{
|
|
EqualsLocation = ReadLocation();
|
|
Initializer = ParseInitializer();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Comma);
|
|
}
|
|
}
|
|
return new VariableDeclarator(VariableNameCollection, AsLocation, NewLocation, Type, NewArguments, EqualsLocation, Initializer, SpanFrom(DeclarationStart));
|
|
}
|
|
|
|
private VariableDeclaratorCollection ParseVariableDeclarators()
|
|
{
|
|
Token Start = Peek();
|
|
List<VariableDeclarator> VariableDeclarators = new List<VariableDeclarator>();
|
|
List<Location> DeclarationsCommaLocations = new List<Location>();
|
|
do
|
|
{
|
|
if (VariableDeclarators.Count > 0)
|
|
{
|
|
DeclarationsCommaLocations.Add(ReadLocation());
|
|
}
|
|
VariableDeclarators.Add(ParseVariableDeclarator());
|
|
}
|
|
while (Peek().Type == TokenType.Comma);
|
|
return new VariableDeclaratorCollection(VariableDeclarators, DeclarationsCommaLocations, SpanFrom(Start));
|
|
}
|
|
|
|
private VariableDeclarator ParseForLoopVariableDeclarator(ref Expression controlExpression)
|
|
{
|
|
Token Start = Peek();
|
|
TypeName Type = null;
|
|
List<VariableName> VariableNames = new List<VariableName>();
|
|
VariableName VariableName = ParseVariableName(allowExplicitArraySizes: false);
|
|
VariableNames.Add(VariableName);
|
|
VariableNameCollection VariableNameCollection = new VariableNameCollection(VariableNames, null, SpanFrom(Start));
|
|
if (ErrorInConstruct && PeekAheadFor(TokenType.As, TokenType.In, TokenType.Equals) == TokenType.As)
|
|
{
|
|
ResyncAt(TokenType.As);
|
|
}
|
|
Location AsLocation = default(Location);
|
|
if (Peek().Type == TokenType.As)
|
|
{
|
|
AsLocation = ReadLocation();
|
|
Type = ParseTypeName(allowArrayType: true);
|
|
}
|
|
controlExpression = new SimpleNameExpression(VariableName.Name, VariableName.Span);
|
|
return new VariableDeclarator(VariableNameCollection, AsLocation, default(Location), Type, null, default(Location), null, SpanFrom(Start));
|
|
}
|
|
|
|
private CaseClause ParseCase()
|
|
{
|
|
Token Start = Peek();
|
|
if (Start.Type == TokenType.Is || IsRelationalOperator(Start.Type))
|
|
{
|
|
OperatorType Operator = OperatorType.None;
|
|
Location IsLocation = default(Location);
|
|
if (Start.Type == TokenType.Is)
|
|
{
|
|
IsLocation = ReadLocation();
|
|
}
|
|
if (IsRelationalOperator(Peek().Type))
|
|
{
|
|
Token OperatorToken = Read();
|
|
Operator = GetBinaryOperator(OperatorToken.Type);
|
|
Expression Operand = ParseExpression();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
return new ComparisonCaseClause(IsLocation, Operator, OperatorToken.Span.Start, Operand, SpanFrom(Start));
|
|
}
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedRelationalOperator, Peek());
|
|
ResyncAt();
|
|
return null;
|
|
}
|
|
return new RangeCaseClause(ParseExpression(allowRange: true), SpanFrom(Start));
|
|
}
|
|
|
|
private AttributeCollection ParseAttributeBlock(AttributeTypes attributeTypesAllowed)
|
|
{
|
|
Token Start = Peek();
|
|
List<Attribute> Attributes = new List<Attribute>();
|
|
List<Location> CommaLocations = new List<Location>();
|
|
if (Start.Type != TokenType.LessThan)
|
|
{
|
|
return null;
|
|
}
|
|
Read();
|
|
do
|
|
{
|
|
AttributeTypes AttributeTypes = AttributeTypes.Regular;
|
|
Location AttributeTypeLocation = default(Location);
|
|
Location ColonLocation = default(Location);
|
|
if (Attributes.Count > 0)
|
|
{
|
|
CommaLocations.Add(ReadLocation());
|
|
}
|
|
Token AttributeStart = Peek();
|
|
if (AttributeStart.AsUnreservedKeyword() == TokenType.Assembly)
|
|
{
|
|
AttributeTypes = AttributeTypes.Assembly;
|
|
AttributeTypeLocation = ReadLocation();
|
|
ColonLocation = VerifyExpectedToken(TokenType.Colon);
|
|
}
|
|
else if (AttributeStart.Type == TokenType.Module)
|
|
{
|
|
AttributeTypes = AttributeTypes.Module;
|
|
AttributeTypeLocation = ReadLocation();
|
|
ColonLocation = VerifyExpectedToken(TokenType.Colon);
|
|
}
|
|
if ((AttributeTypes & attributeTypesAllowed) == 0)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.IncorrectAttributeType, AttributeStart);
|
|
}
|
|
Name Name = ParseName(AllowGlobal: true);
|
|
ArgumentCollection Arguments = ParseArguments();
|
|
Attributes.Add(new Attribute(AttributeTypes, AttributeTypeLocation, ColonLocation, Name, Arguments, SpanFrom(AttributeStart)));
|
|
}
|
|
while (Peek().Type == TokenType.Comma);
|
|
Location RightBracketLocation = VerifyExpectedToken(TokenType.GreaterThan);
|
|
return new AttributeCollection(Attributes, CommaLocations, RightBracketLocation, SpanFrom(Start));
|
|
}
|
|
|
|
private AttributeBlockCollection ParseAttributes(AttributeTypes attributeTypesAllowed = AttributeTypes.Regular)
|
|
{
|
|
Token Start = Peek();
|
|
List<AttributeCollection> AttributeBlocks = new List<AttributeCollection>();
|
|
while (Peek().Type == TokenType.LessThan)
|
|
{
|
|
AttributeBlocks.Add(ParseAttributeBlock(attributeTypesAllowed));
|
|
}
|
|
if (AttributeBlocks.Count == 0)
|
|
{
|
|
return null;
|
|
}
|
|
return new AttributeBlockCollection(AttributeBlocks, SpanFrom(Start));
|
|
}
|
|
|
|
private NameCollection ParseNameList(bool allowLeadingMeOrMyBase = false)
|
|
{
|
|
Token Start = Read();
|
|
List<Location> CommaLocations = new List<Location>();
|
|
List<Name> Names = new List<Name>();
|
|
do
|
|
{
|
|
if (Names.Count > 0)
|
|
{
|
|
CommaLocations.Add(ReadLocation());
|
|
}
|
|
Names.Add(ParseNameListName(allowLeadingMeOrMyBase));
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Comma);
|
|
}
|
|
}
|
|
while (Peek().Type == TokenType.Comma);
|
|
return new NameCollection(Names, CommaLocations, SpanFrom(Start));
|
|
}
|
|
|
|
private Declaration ParsePropertyDeclaration(Location startLocation, AttributeBlockCollection attributes, ModifierCollection modifiers)
|
|
{
|
|
TypeName ReturnType = null;
|
|
AttributeBlockCollection ReturnTypeAttributes = null;
|
|
NameCollection ImplementsList = null;
|
|
DeclarationCollection Accessors = null;
|
|
EndBlockDeclaration EndBlockDeclaration = null;
|
|
bool InInterface = CurrentBlockContextType() == TreeType.InterfaceDeclaration;
|
|
List<Comment> Comments = null;
|
|
ModifierTypes ValidModifiers = ((!InInterface) ? (ModifierTypes.AccessModifiers | ModifierTypes.Shared | ModifierTypes.Shadows | ModifierTypes.Overloads | ModifierTypes.Overrides | ModifierTypes.NotOverridable | ModifierTypes.Overridable | ModifierTypes.MustOverride | ModifierTypes.ReadOnly | ModifierTypes.WriteOnly | ModifierTypes.Default) : (ModifierTypes.Shadows | ModifierTypes.Overloads | ModifierTypes.ReadOnly | ModifierTypes.WriteOnly | ModifierTypes.Default));
|
|
ValidateModifierList(modifiers, ValidModifiers);
|
|
Location PropertyLocation = ReadLocation();
|
|
SimpleName Name = ParseSimpleName(allowKeyword: false);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.LeftParenthesis, TokenType.As);
|
|
}
|
|
TypeParameterCollection TypeParameters = ParseTypeParameters();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.LeftParenthesis, TokenType.As);
|
|
}
|
|
if (TypeParameters != null && TypeParameters.Count > 0)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.PropertiesCantBeGeneric, TypeParameters.Span);
|
|
}
|
|
ParameterCollection Parameters = ParseParameters();
|
|
Location AsLocation = default(Location);
|
|
if (Peek().Type == TokenType.As)
|
|
{
|
|
AsLocation = ReadLocation();
|
|
ReturnTypeAttributes = ParseAttributes();
|
|
ReturnType = ParseTypeName(allowArrayType: true);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Implements);
|
|
}
|
|
}
|
|
if (InInterface)
|
|
{
|
|
Comments = ParseTrailingComments();
|
|
}
|
|
else
|
|
{
|
|
if (Peek().Type == TokenType.Implements)
|
|
{
|
|
ImplementsList = ParseNameList();
|
|
}
|
|
if (modifiers == null || (modifiers.ModifierTypes & ModifierTypes.MustOverride) == 0)
|
|
{
|
|
Accessors = ParseDeclarationBlock(SpanFrom(startLocation), TreeType.PropertyDeclaration, ref Comments, ref EndBlockDeclaration);
|
|
}
|
|
else
|
|
{
|
|
Comments = ParseTrailingComments();
|
|
}
|
|
}
|
|
return new PropertyDeclaration(attributes, modifiers, PropertyLocation, Name, Parameters, AsLocation, ReturnTypeAttributes, ReturnType, ImplementsList, Accessors, EndBlockDeclaration, SpanFrom(startLocation), Comments);
|
|
}
|
|
|
|
private Declaration ParseExternalDeclaration(Location startLocation, AttributeBlockCollection attributes, ModifierCollection modifiers)
|
|
{
|
|
Charset Charset = Charset.Auto;
|
|
TreeType MethodType = TreeType.SyntaxError;
|
|
StringLiteralExpression LibLiteral = null;
|
|
StringLiteralExpression AliasLiteral = null;
|
|
TypeName ReturnType = null;
|
|
AttributeBlockCollection ReturnTypeAttributes = null;
|
|
ValidateModifierList(modifiers, ModifierTypes.AccessModifiers | ModifierTypes.Shadows | ModifierTypes.Overloads);
|
|
Location DeclareLocation = ReadLocation();
|
|
Location CharsetLocation = default(Location);
|
|
switch (Peek().AsUnreservedKeyword())
|
|
{
|
|
case TokenType.Ansi:
|
|
Charset = Charset.Ansi;
|
|
CharsetLocation = ReadLocation();
|
|
break;
|
|
case TokenType.Unicode:
|
|
Charset = Charset.Unicode;
|
|
CharsetLocation = ReadLocation();
|
|
break;
|
|
case TokenType.Auto:
|
|
Charset = Charset.Auto;
|
|
CharsetLocation = ReadLocation();
|
|
break;
|
|
}
|
|
Location SubOrFunctionLocation = default(Location);
|
|
if (Peek().Type == TokenType.Sub)
|
|
{
|
|
MethodType = TreeType.ExternalSubDeclaration;
|
|
SubOrFunctionLocation = ReadLocation();
|
|
}
|
|
else if (Peek().Type == TokenType.Function)
|
|
{
|
|
MethodType = TreeType.ExternalFunctionDeclaration;
|
|
SubOrFunctionLocation = ReadLocation();
|
|
}
|
|
else
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedSubOrFunction, Peek());
|
|
}
|
|
SimpleName Name = ParseSimpleName(allowKeyword: false);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Lib, TokenType.LeftParenthesis);
|
|
}
|
|
Location LibLocation = default(Location);
|
|
if (Peek().Type == TokenType.Lib)
|
|
{
|
|
LibLocation = ReadLocation();
|
|
if (Peek().Type == TokenType.StringLiteral)
|
|
{
|
|
StringLiteralToken Literal2 = (StringLiteralToken)Read();
|
|
LibLiteral = new StringLiteralExpression(Literal2.Literal, Literal2.Span);
|
|
}
|
|
else
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedStringLiteral, Peek());
|
|
ResyncAt(TokenType.Alias, TokenType.LeftParenthesis);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedLib, Peek());
|
|
}
|
|
Location AliasLocation = default(Location);
|
|
if (Peek().Type == TokenType.Alias)
|
|
{
|
|
AliasLocation = ReadLocation();
|
|
if (Peek().Type == TokenType.StringLiteral)
|
|
{
|
|
StringLiteralToken Literal = (StringLiteralToken)Read();
|
|
AliasLiteral = new StringLiteralExpression(Literal.Literal, Literal.Span);
|
|
}
|
|
else
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedStringLiteral, Peek());
|
|
ResyncAt(TokenType.LeftParenthesis);
|
|
}
|
|
}
|
|
ParameterCollection Parameters = ParseParameters();
|
|
switch (MethodType)
|
|
{
|
|
case TreeType.ExternalFunctionDeclaration:
|
|
{
|
|
Location AsLocation = default(Location);
|
|
if (Peek().Type == TokenType.As)
|
|
{
|
|
AsLocation = ReadLocation();
|
|
ReturnTypeAttributes = ParseAttributes();
|
|
ReturnType = ParseTypeName(allowArrayType: true);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
}
|
|
return new ExternalFunctionDeclaration(attributes, modifiers, DeclareLocation, CharsetLocation, Charset, SubOrFunctionLocation, Name, LibLocation, LibLiteral, AliasLocation, AliasLiteral, Parameters, AsLocation, ReturnTypeAttributes, ReturnType, SpanFrom(startLocation), ParseTrailingComments());
|
|
}
|
|
case TreeType.ExternalSubDeclaration:
|
|
return new ExternalSubDeclaration(attributes, modifiers, DeclareLocation, CharsetLocation, Charset, SubOrFunctionLocation, Name, LibLocation, LibLiteral, AliasLocation, AliasLiteral, Parameters, SpanFrom(startLocation), ParseTrailingComments());
|
|
default:
|
|
return Declaration.GetBadDeclaration(SpanFrom(startLocation), ParseTrailingComments());
|
|
}
|
|
}
|
|
|
|
private Declaration ParseMethodDeclaration(Location startLocation, AttributeBlockCollection attributes, ModifierCollection modifiers)
|
|
{
|
|
TypeName ReturnType = null;
|
|
AttributeBlockCollection ReturnTypeAttributes = null;
|
|
NameCollection ImplementsList = null;
|
|
NameCollection HandlesList = null;
|
|
bool AllowKeywordsForName = false;
|
|
ModifierTypes ValidModifiers = ModifierTypes.AccessModifiers | ModifierTypes.Shared | ModifierTypes.Shadows | ModifierTypes.Overloads | ModifierTypes.Overrides | ModifierTypes.NotOverridable | ModifierTypes.Overridable | ModifierTypes.MustOverride;
|
|
StatementCollection Statements = null;
|
|
Statement EndStatement = null;
|
|
EndBlockDeclaration EndDeclaration = null;
|
|
bool InInterface = CurrentBlockContextType() == TreeType.InterfaceDeclaration;
|
|
List<Comment> Comments = null;
|
|
TypeParameterCollection TypeParameters = null;
|
|
if (!AtBeginningOfLine)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.MethodMustBeFirstStatementOnLine, Peek());
|
|
}
|
|
Location SubOrFunctionLocation;
|
|
TreeType MethodType;
|
|
if (Peek().Type == TokenType.Sub)
|
|
{
|
|
SubOrFunctionLocation = ReadLocation();
|
|
if (Peek().Type == TokenType.New)
|
|
{
|
|
MethodType = TreeType.ConstructorDeclaration;
|
|
AllowKeywordsForName = true;
|
|
ValidModifiers = ModifierTypes.AccessModifiers | ModifierTypes.Shared;
|
|
}
|
|
else
|
|
{
|
|
MethodType = TreeType.SubDeclaration;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SubOrFunctionLocation = ReadLocation();
|
|
MethodType = TreeType.FunctionDeclaration;
|
|
}
|
|
if (InInterface)
|
|
{
|
|
ValidModifiers = ModifierTypes.Shadows | ModifierTypes.Overloads;
|
|
}
|
|
ValidateModifierList(modifiers, ValidModifiers);
|
|
SimpleName Name = ParseSimpleName(AllowKeywordsForName);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.LeftParenthesis, TokenType.As);
|
|
}
|
|
TypeParameters = ParseTypeParameters();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.LeftParenthesis, TokenType.As);
|
|
}
|
|
if (MethodType == TreeType.ConstructorDeclaration && TypeParameters != null && TypeParameters.Count > 0)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ConstructorsCantBeGeneric, TypeParameters.Span);
|
|
}
|
|
ParameterCollection Parameters = ParseParameters();
|
|
Location AsLocation = default(Location);
|
|
if (MethodType == TreeType.FunctionDeclaration && Peek().Type == TokenType.As)
|
|
{
|
|
AsLocation = ReadLocation();
|
|
ReturnTypeAttributes = ParseAttributes();
|
|
ReturnType = ParseTypeName(allowArrayType: true);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Implements, TokenType.Handles);
|
|
}
|
|
}
|
|
if (InInterface)
|
|
{
|
|
Comments = ParseTrailingComments();
|
|
}
|
|
else
|
|
{
|
|
if (Peek().Type == TokenType.Implements)
|
|
{
|
|
ImplementsList = ParseNameList();
|
|
}
|
|
else if (Peek().Type == TokenType.Handles)
|
|
{
|
|
HandlesList = ParseNameList(allowLeadingMeOrMyBase: true);
|
|
}
|
|
if (modifiers == null || (modifiers.ModifierTypes & ModifierTypes.MustOverride) == 0)
|
|
{
|
|
Statements = ParseStatementBlock(SpanFrom(startLocation), MethodType, ref Comments, ref EndStatement);
|
|
}
|
|
else
|
|
{
|
|
Comments = ParseTrailingComments();
|
|
}
|
|
if (EndStatement != null)
|
|
{
|
|
EndDeclaration = new EndBlockDeclaration((EndBlockStatement)EndStatement);
|
|
}
|
|
}
|
|
return MethodType switch
|
|
{
|
|
TreeType.SubDeclaration => new SubDeclaration(attributes, modifiers, SubOrFunctionLocation, Name, TypeParameters, Parameters, ImplementsList, HandlesList, Statements, EndDeclaration, SpanFrom(startLocation), Comments),
|
|
TreeType.FunctionDeclaration => new FunctionDeclaration(attributes, modifiers, SubOrFunctionLocation, Name, TypeParameters, Parameters, AsLocation, ReturnTypeAttributes, ReturnType, ImplementsList, HandlesList, Statements, EndDeclaration, SpanFrom(startLocation), Comments),
|
|
_ => new ConstructorDeclaration(attributes, modifiers, SubOrFunctionLocation, Name, Parameters, Statements, EndDeclaration, SpanFrom(startLocation), Comments),
|
|
};
|
|
}
|
|
|
|
private Declaration ParseOperatorDeclaration(Location startLocation, AttributeBlockCollection attributes, ModifierCollection modifiers)
|
|
{
|
|
Token OperatorToken = null;
|
|
TypeName ReturnType = null;
|
|
AttributeBlockCollection ReturnTypeAttributes = null;
|
|
ModifierTypes ValidModifiers = ModifierTypes.Public | ModifierTypes.Shared | ModifierTypes.Shadows | ModifierTypes.Overloads | ModifierTypes.Widening | ModifierTypes.Narrowing;
|
|
StatementCollection Statements = null;
|
|
Statement EndStatement = null;
|
|
EndBlockDeclaration EndDeclaration = null;
|
|
List<Comment> Comments = null;
|
|
if (!AtBeginningOfLine)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.MethodMustBeFirstStatementOnLine, Peek());
|
|
}
|
|
Location KeywordLocation = ReadLocation();
|
|
ValidateModifierList(modifiers, ValidModifiers);
|
|
if (IsOverloadableOperator(Peek()))
|
|
{
|
|
OperatorToken = Read();
|
|
}
|
|
else
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.InvalidOperator, Peek());
|
|
ResyncAt(TokenType.LeftParenthesis, TokenType.As);
|
|
}
|
|
TypeParameterCollection TypeParameters = ParseTypeParameters();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.LeftParenthesis, TokenType.As);
|
|
}
|
|
if (TypeParameters != null && TypeParameters.Count > 0)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.OperatorsCantBeGeneric, TypeParameters.Span);
|
|
}
|
|
ParameterCollection Parameters = ParseParameters();
|
|
Location AsLocation = default(Location);
|
|
if (Peek().Type == TokenType.As)
|
|
{
|
|
AsLocation = ReadLocation();
|
|
ReturnTypeAttributes = ParseAttributes();
|
|
ReturnType = ParseTypeName(allowArrayType: true);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
}
|
|
Statements = ParseStatementBlock(SpanFrom(startLocation), TreeType.OperatorDeclaration, ref Comments, ref EndStatement);
|
|
Comments = ParseTrailingComments();
|
|
if (EndStatement != null)
|
|
{
|
|
EndDeclaration = new EndBlockDeclaration((EndBlockStatement)EndStatement);
|
|
}
|
|
return new OperatorDeclaration(attributes, modifiers, KeywordLocation, OperatorToken, Parameters, AsLocation, ReturnTypeAttributes, ReturnType, Statements, EndDeclaration, SpanFrom(startLocation), Comments);
|
|
}
|
|
|
|
private Declaration ParseAccessorDeclaration(Location startLocation, AttributeBlockCollection attributes, ModifierCollection modifiers)
|
|
{
|
|
ParameterCollection Parameters = null;
|
|
Statement EndStatement = null;
|
|
EndBlockDeclaration EndDeclaration = null;
|
|
List<Comment> Comments = null;
|
|
ModifierTypes ValidModifiers = ModifierTypes.None;
|
|
if (Scanner.Version > LanguageVersion.VisualBasic71)
|
|
{
|
|
ValidModifiers |= ModifierTypes.AccessModifiers;
|
|
}
|
|
if (!AtBeginningOfLine)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.MethodMustBeFirstStatementOnLine, Peek());
|
|
}
|
|
ValidateModifierList(modifiers, ValidModifiers);
|
|
TreeType AccessorType = ((Peek().Type != TokenType.Get) ? TreeType.SetAccessorDeclaration : TreeType.GetAccessorDeclaration);
|
|
Location GetOrSetLocation = ReadLocation();
|
|
if (AccessorType == TreeType.SetAccessorDeclaration)
|
|
{
|
|
Parameters = ParseParameters();
|
|
}
|
|
StatementCollection Statements = ParseStatementBlock(SpanFrom(startLocation), AccessorType, ref Comments, ref EndStatement);
|
|
if (EndStatement != null)
|
|
{
|
|
EndDeclaration = new EndBlockDeclaration((EndBlockStatement)EndStatement);
|
|
}
|
|
if (AccessorType == TreeType.GetAccessorDeclaration)
|
|
{
|
|
return new GetAccessorDeclaration(attributes, modifiers, GetOrSetLocation, Statements, EndDeclaration, SpanFrom(startLocation), Comments);
|
|
}
|
|
return new SetAccessorDeclaration(attributes, modifiers, GetOrSetLocation, Parameters, Statements, EndDeclaration, SpanFrom(startLocation), Comments);
|
|
}
|
|
|
|
private Declaration ParseCustomEventDeclaration(Location startLocation, AttributeBlockCollection attributes, ModifierCollection modifiers)
|
|
{
|
|
NameCollection ImplementsList = null;
|
|
DeclarationCollection Accessors = null;
|
|
EndBlockDeclaration EndBlockDeclaration = null;
|
|
List<Comment> Comments = null;
|
|
ValidateModifierList(modifiers, ModifierTypes.AccessModifiers | ModifierTypes.Shared | ModifierTypes.Shadows);
|
|
Location CustomLocation = ReadLocation();
|
|
Debug.Assert(Peek().Type == TokenType.Event);
|
|
Location EventLocation = ReadLocation();
|
|
SimpleName Name = ParseSimpleName(allowKeyword: false);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.As);
|
|
}
|
|
Location AsLocation = VerifyExpectedToken(TokenType.As);
|
|
TypeName EventType = ParseTypeName(allowArrayType: true);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Implements);
|
|
}
|
|
if (Peek().Type == TokenType.Implements)
|
|
{
|
|
ImplementsList = ParseNameList();
|
|
}
|
|
Accessors = ParseDeclarationBlock(SpanFrom(startLocation), TreeType.CustomEventDeclaration, ref Comments, ref EndBlockDeclaration);
|
|
return new CustomEventDeclaration(attributes, modifiers, CustomLocation, EventLocation, Name, AsLocation, EventType, ImplementsList, Accessors, EndBlockDeclaration, SpanFrom(startLocation), Comments);
|
|
}
|
|
|
|
private Declaration ParseEventAccessorDeclaration(Location startLocation, AttributeBlockCollection attributes, ModifierCollection modifiers)
|
|
{
|
|
ParameterCollection Parameters = null;
|
|
Statement EndStatement = null;
|
|
EndBlockDeclaration EndDeclaration = null;
|
|
List<Comment> Comments = null;
|
|
if (!AtBeginningOfLine)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.MethodMustBeFirstStatementOnLine, Peek());
|
|
}
|
|
ValidateModifierList(modifiers, ModifierTypes.None);
|
|
TreeType AccessorType = ((Peek().Type == TokenType.AddHandler) ? TreeType.AddHandlerAccessorDeclaration : ((Peek().Type != TokenType.RemoveHandler) ? TreeType.RaiseEventAccessorDeclaration : TreeType.RemoveHandlerAccessorDeclaration));
|
|
Location AccessorTypeLocation = ReadLocation();
|
|
Parameters = ParseParameters();
|
|
StatementCollection Statements = ParseStatementBlock(SpanFrom(startLocation), AccessorType, ref Comments, ref EndStatement);
|
|
if (EndStatement != null)
|
|
{
|
|
EndDeclaration = new EndBlockDeclaration((EndBlockStatement)EndStatement);
|
|
}
|
|
return AccessorType switch
|
|
{
|
|
TreeType.AddHandlerAccessorDeclaration => new AddHandlerAccessorDeclaration(attributes, AccessorTypeLocation, Parameters, Statements, EndDeclaration, SpanFrom(startLocation), Comments),
|
|
TreeType.RemoveHandlerAccessorDeclaration => new RemoveHandlerAccessorDeclaration(attributes, AccessorTypeLocation, Parameters, Statements, EndDeclaration, SpanFrom(startLocation), Comments),
|
|
_ => new RaiseEventAccessorDeclaration(attributes, AccessorTypeLocation, Parameters, Statements, EndDeclaration, SpanFrom(startLocation), Comments),
|
|
};
|
|
}
|
|
|
|
private Declaration ParseEventDeclaration(Location startLocation, AttributeBlockCollection attributes, ModifierCollection modifiers)
|
|
{
|
|
TypeName EventType = null;
|
|
ParameterCollection Parameters = null;
|
|
NameCollection ImplementsList = null;
|
|
ModifierTypes ValidModifiers = ((CurrentBlockContextType() != TreeType.InterfaceDeclaration) ? (ModifierTypes.AccessModifiers | ModifierTypes.Shared | ModifierTypes.Shadows) : ModifierTypes.Shadows);
|
|
ValidateModifierList(modifiers, ValidModifiers);
|
|
Location EventLocation = ReadLocation();
|
|
SimpleName Name = ParseSimpleName(allowKeyword: false);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.As, TokenType.LeftParenthesis, TokenType.Implements);
|
|
}
|
|
Location AsLocation = default(Location);
|
|
if (Peek().Type == TokenType.As)
|
|
{
|
|
AsLocation = ReadLocation();
|
|
EventType = ParseTypeName(allowArrayType: false);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Implements);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Parameters = ParseParameters();
|
|
if (Peek().Type == TokenType.As)
|
|
{
|
|
Token ErrorStart = Peek();
|
|
ResyncAt(TokenType.Implements);
|
|
ReportSyntaxError(SyntaxErrorType.EventsCantBeFunctions, ErrorStart, Peek());
|
|
}
|
|
}
|
|
if (Peek().Type == TokenType.Implements)
|
|
{
|
|
ImplementsList = ParseNameList();
|
|
}
|
|
return new EventDeclaration(attributes, modifiers, EventLocation, Name, Parameters, AsLocation, null, EventType, ImplementsList, SpanFrom(startLocation), ParseTrailingComments());
|
|
}
|
|
|
|
private Declaration ParseVariableListDeclaration(Location startLocation, AttributeBlockCollection attributes, ModifierCollection modifiers)
|
|
{
|
|
ModifierTypes ValidModifiers = ((modifiers == null || (modifiers.ModifierTypes & ModifierTypes.Const) == 0) ? (ModifierTypes.AccessModifiers | ModifierTypes.Shared | ModifierTypes.Shadows | ModifierTypes.ReadOnly | ModifierTypes.Dim | ModifierTypes.WithEvents) : (ModifierTypes.AccessModifiers | ModifierTypes.Shadows | ModifierTypes.Const));
|
|
ValidateModifierList(modifiers, ValidModifiers);
|
|
if (modifiers == null)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedModifier, Peek());
|
|
}
|
|
return new VariableListDeclaration(attributes, modifiers, ParseVariableDeclarators(), SpanFrom(startLocation), ParseTrailingComments());
|
|
}
|
|
|
|
private Declaration ParseEndDeclaration()
|
|
{
|
|
Token Start = Read();
|
|
BlockType EndType = GetBlockType(Peek().Type);
|
|
switch (EndType)
|
|
{
|
|
case BlockType.Sub:
|
|
if (!AtBeginningOfLine)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.EndSubNotAtLineStart, SpanFrom(Start));
|
|
}
|
|
break;
|
|
case BlockType.Function:
|
|
if (!AtBeginningOfLine)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.EndFunctionNotAtLineStart, SpanFrom(Start));
|
|
}
|
|
break;
|
|
case BlockType.Operator:
|
|
if (!AtBeginningOfLine)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.EndOperatorNotAtLineStart, SpanFrom(Start));
|
|
}
|
|
break;
|
|
case BlockType.Get:
|
|
if (!AtBeginningOfLine)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.EndGetNotAtLineStart, SpanFrom(Start));
|
|
}
|
|
break;
|
|
case BlockType.Set:
|
|
if (!AtBeginningOfLine)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.EndSetNotAtLineStart, SpanFrom(Start));
|
|
}
|
|
break;
|
|
case BlockType.AddHandler:
|
|
if (!AtBeginningOfLine)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.EndAddHandlerNotAtLineStart, SpanFrom(Start));
|
|
}
|
|
break;
|
|
case BlockType.RemoveHandler:
|
|
if (!AtBeginningOfLine)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.EndRemoveHandlerNotAtLineStart, SpanFrom(Start));
|
|
}
|
|
break;
|
|
case BlockType.RaiseEvent:
|
|
if (!AtBeginningOfLine)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.EndRaiseEventNotAtLineStart, SpanFrom(Start));
|
|
}
|
|
break;
|
|
case BlockType.None:
|
|
ReportSyntaxError(SyntaxErrorType.UnrecognizedEnd, Peek());
|
|
return Declaration.GetBadDeclaration(SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
return new EndBlockDeclaration(EndType, ReadLocation(), SpanFrom(Start), ParseTrailingComments());
|
|
}
|
|
|
|
private Declaration ParseTypeDeclaration(Location startLocation, AttributeBlockCollection attributes, ModifierCollection modifiers, TreeType blockType)
|
|
{
|
|
EndBlockDeclaration EndBlockDeclaration = null;
|
|
List<Comment> Comments = null;
|
|
TypeParameterCollection TypeParameters = null;
|
|
ModifierTypes ValidModifiers;
|
|
if (blockType == TreeType.ModuleDeclaration)
|
|
{
|
|
ValidModifiers = ModifierTypes.AccessModifiers;
|
|
}
|
|
else
|
|
{
|
|
ValidModifiers = ModifierTypes.AccessModifiers | ModifierTypes.Shadows;
|
|
if (blockType == TreeType.ClassDeclaration)
|
|
{
|
|
ValidModifiers = ValidModifiers | ModifierTypes.MustInherit | ModifierTypes.NotInheritable;
|
|
}
|
|
if (blockType == TreeType.ClassDeclaration || blockType == TreeType.StructureDeclaration)
|
|
{
|
|
ValidModifiers |= ModifierTypes.Partial;
|
|
}
|
|
}
|
|
ValidateModifierList(modifiers, ValidModifiers);
|
|
Location KeywordLocation = ReadLocation();
|
|
SimpleName Name = ParseSimpleName(allowKeyword: false);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
TypeParameters = ParseTypeParameters();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
if (blockType == TreeType.ModuleDeclaration && TypeParameters != null && TypeParameters.Count > 0)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ModulesCantBeGeneric, TypeParameters.Span);
|
|
}
|
|
DeclarationCollection Members = ParseDeclarationBlock(SpanFrom(startLocation), blockType, ref Comments, ref EndBlockDeclaration);
|
|
switch (blockType)
|
|
{
|
|
case TreeType.ClassDeclaration:
|
|
return new ClassDeclaration(attributes, modifiers, KeywordLocation, Name, TypeParameters, Members, EndBlockDeclaration, SpanFrom(startLocation), Comments);
|
|
case TreeType.ModuleDeclaration:
|
|
return new ModuleDeclaration(attributes, modifiers, KeywordLocation, Name, Members, EndBlockDeclaration, SpanFrom(startLocation), Comments);
|
|
case TreeType.InterfaceDeclaration:
|
|
return new InterfaceDeclaration(attributes, modifiers, KeywordLocation, Name, TypeParameters, Members, EndBlockDeclaration, SpanFrom(startLocation), Comments);
|
|
case TreeType.StructureDeclaration:
|
|
return new StructureDeclaration(attributes, modifiers, KeywordLocation, Name, TypeParameters, Members, EndBlockDeclaration, SpanFrom(startLocation), Comments);
|
|
default:
|
|
Debug.Assert(condition: false, "unexpected!");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private Declaration ParseEnumDeclaration(Location startLocation, AttributeBlockCollection attributes, ModifierCollection modifiers)
|
|
{
|
|
TypeName Type = null;
|
|
EndBlockDeclaration EndBlockDeclaration = null;
|
|
List<Comment> Comments = null;
|
|
ValidateModifierList(modifiers, ModifierTypes.AccessModifiers | ModifierTypes.Shadows);
|
|
Location KeywordLocation = ReadLocation();
|
|
SimpleName Name = ParseSimpleName(allowKeyword: false);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.As);
|
|
}
|
|
Location AsLocation = default(Location);
|
|
if (Peek().Type == TokenType.As)
|
|
{
|
|
AsLocation = ReadLocation();
|
|
Type = ParseTypeName(allowArrayType: false);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
}
|
|
DeclarationCollection Members = ParseDeclarationBlock(SpanFrom(startLocation), TreeType.EnumDeclaration, ref Comments, ref EndBlockDeclaration);
|
|
if (Members == null || Members.Count == 0)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.EmptyEnum, Name.Span);
|
|
}
|
|
return new EnumDeclaration(attributes, modifiers, KeywordLocation, Name, AsLocation, Type, Members, EndBlockDeclaration, SpanFrom(startLocation), Comments);
|
|
}
|
|
|
|
private Declaration ParseDelegateDeclaration(Location startLocation, AttributeBlockCollection attributes, ModifierCollection modifiers)
|
|
{
|
|
TreeType MethodType = TreeType.SyntaxError;
|
|
TypeName ReturnType = null;
|
|
AttributeBlockCollection ReturnTypeAttributes = null;
|
|
TypeParameterCollection TypeParameters = null;
|
|
ValidateModifierList(modifiers, ModifierTypes.AccessModifiers | ModifierTypes.Shared | ModifierTypes.Shadows);
|
|
Location DelegateLocation = ReadLocation();
|
|
Location SubOrFunctionLocation = default(Location);
|
|
if (Peek().Type == TokenType.Sub)
|
|
{
|
|
SubOrFunctionLocation = ReadLocation();
|
|
MethodType = TreeType.SubDeclaration;
|
|
}
|
|
else if (Peek().Type == TokenType.Function)
|
|
{
|
|
SubOrFunctionLocation = ReadLocation();
|
|
MethodType = TreeType.FunctionDeclaration;
|
|
}
|
|
else
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedSubOrFunction, Peek());
|
|
MethodType = TreeType.SubDeclaration;
|
|
}
|
|
SimpleName Name = ParseSimpleName(allowKeyword: false);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.LeftParenthesis, TokenType.As);
|
|
}
|
|
TypeParameters = ParseTypeParameters();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.LeftParenthesis, TokenType.As);
|
|
}
|
|
ParameterCollection Parameters = ParseParameters();
|
|
Location AsLocation = default(Location);
|
|
if (MethodType == TreeType.FunctionDeclaration && Peek().Type == TokenType.As)
|
|
{
|
|
AsLocation = ReadLocation();
|
|
ReturnTypeAttributes = ParseAttributes();
|
|
ReturnType = ParseTypeName(allowArrayType: true);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
}
|
|
if (MethodType == TreeType.SubDeclaration)
|
|
{
|
|
return new DelegateSubDeclaration(attributes, modifiers, DelegateLocation, SubOrFunctionLocation, Name, TypeParameters, Parameters, SpanFrom(startLocation), ParseTrailingComments());
|
|
}
|
|
return new DelegateFunctionDeclaration(attributes, modifiers, DelegateLocation, SubOrFunctionLocation, Name, TypeParameters, Parameters, AsLocation, ReturnTypeAttributes, ReturnType, SpanFrom(startLocation), ParseTrailingComments());
|
|
}
|
|
|
|
private Declaration ParseTypeListDeclaration(Location startLocation, AttributeBlockCollection attributes, ModifierCollection modifiers, TreeType listType)
|
|
{
|
|
List<Location> CommaLocations = new List<Location>();
|
|
List<TypeName> Types = new List<TypeName>();
|
|
Read();
|
|
if (attributes != null)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.SpecifiersInvalidOnTypeListDeclaration, attributes.Span);
|
|
}
|
|
if (modifiers != null)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.SpecifiersInvalidOnTypeListDeclaration, modifiers.Span);
|
|
}
|
|
Token ListStart = Peek();
|
|
do
|
|
{
|
|
if (Types.Count > 0)
|
|
{
|
|
CommaLocations.Add(ReadLocation());
|
|
}
|
|
Types.Add(ParseTypeName(allowArrayType: false));
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Comma);
|
|
}
|
|
}
|
|
while (Peek().Type == TokenType.Comma);
|
|
if (listType == TreeType.InheritsDeclaration)
|
|
{
|
|
return new InheritsDeclaration(new TypeNameCollection(Types, CommaLocations, SpanFrom(ListStart)), SpanFrom(startLocation), ParseTrailingComments());
|
|
}
|
|
return new ImplementsDeclaration(new TypeNameCollection(Types, CommaLocations, SpanFrom(ListStart)), SpanFrom(startLocation), ParseTrailingComments());
|
|
}
|
|
|
|
private Declaration ParseNamespaceDeclaration(Location startLocation, AttributeBlockCollection attributes, ModifierCollection modifiers)
|
|
{
|
|
EndBlockDeclaration EndBlockDeclaration = null;
|
|
List<Comment> Comments = null;
|
|
if (attributes != null)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.SpecifiersInvalidOnNamespaceDeclaration, attributes.Span);
|
|
}
|
|
if (modifiers != null)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.SpecifiersInvalidOnNamespaceDeclaration, modifiers.Span);
|
|
}
|
|
Location KeywordLocation = ReadLocation();
|
|
Name Name = ParseName(AllowGlobal: false);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
DeclarationCollection Members = ParseDeclarationBlock(SpanFrom(startLocation), TreeType.NamespaceDeclaration, ref Comments, ref EndBlockDeclaration);
|
|
return new NamespaceDeclaration(attributes, modifiers, KeywordLocation, Name, Members, EndBlockDeclaration, SpanFrom(startLocation), Comments);
|
|
}
|
|
|
|
private Declaration ParseImportsDeclaration(Location startLocation, AttributeBlockCollection attributes, ModifierCollection modifiers)
|
|
{
|
|
List<Import> ImportMembers = new List<Import>();
|
|
List<Location> CommaLocations = new List<Location>();
|
|
if (attributes != null)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.SpecifiersInvalidOnImportsDeclaration, attributes.Span);
|
|
}
|
|
if (modifiers != null)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.SpecifiersInvalidOnImportsDeclaration, modifiers.Span);
|
|
}
|
|
Read();
|
|
Token ListStart = Peek();
|
|
do
|
|
{
|
|
if (ImportMembers.Count > 0)
|
|
{
|
|
CommaLocations.Add(ReadLocation());
|
|
}
|
|
if (PeekAheadFor(TokenType.Equals, TokenType.Comma, TokenType.Period) == TokenType.Equals)
|
|
{
|
|
Token ImportStart2 = Peek();
|
|
SimpleName Name = ParseSimpleName(allowKeyword: false);
|
|
Location EqualsLocation = ReadLocation();
|
|
TypeName AliasedTypeName = ParseNamedTypeName(allowGlobal: false);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
ImportMembers.Add(new AliasImport(Name, EqualsLocation, AliasedTypeName, SpanFrom(ImportStart2)));
|
|
}
|
|
else
|
|
{
|
|
Token ImportStart = Peek();
|
|
TypeName TypeName = ParseNamedTypeName(allowGlobal: false);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
ImportMembers.Add(new NameImport(TypeName, SpanFrom(ImportStart)));
|
|
}
|
|
}
|
|
while (Peek().Type == TokenType.Comma);
|
|
return new ImportsDeclaration(new ImportCollection(ImportMembers, CommaLocations, SpanFrom(ListStart)), SpanFrom(startLocation), ParseTrailingComments());
|
|
}
|
|
|
|
private Declaration ParseOptionDeclaration(Location startLocation, AttributeBlockCollection attributes, ModifierCollection modifiers)
|
|
{
|
|
Read();
|
|
if (attributes != null)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.SpecifiersInvalidOnOptionDeclaration, attributes.Span);
|
|
}
|
|
if (modifiers != null)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.SpecifiersInvalidOnOptionDeclaration, modifiers.Span);
|
|
}
|
|
Location OptionTypeLocation = default(Location);
|
|
Location OptionArgumentLocation = default(Location);
|
|
OptionType OptionType;
|
|
if (Peek().AsUnreservedKeyword() == TokenType.Explicit)
|
|
{
|
|
OptionTypeLocation = ReadLocation();
|
|
if (Peek().AsUnreservedKeyword() == TokenType.Off)
|
|
{
|
|
OptionArgumentLocation = ReadLocation();
|
|
OptionType = OptionType.ExplicitOff;
|
|
}
|
|
else if (Peek().Type == TokenType.On)
|
|
{
|
|
OptionArgumentLocation = ReadLocation();
|
|
OptionType = OptionType.ExplicitOn;
|
|
}
|
|
else if (Peek().Type == TokenType.Identifier)
|
|
{
|
|
OptionType = OptionType.SyntaxError;
|
|
ReportSyntaxError(SyntaxErrorType.InvalidOptionExplicitType, SpanFrom(startLocation));
|
|
}
|
|
else
|
|
{
|
|
OptionType = OptionType.Explicit;
|
|
}
|
|
}
|
|
else if (Peek().AsUnreservedKeyword() == TokenType.Strict)
|
|
{
|
|
OptionTypeLocation = ReadLocation();
|
|
if (Peek().AsUnreservedKeyword() == TokenType.Off)
|
|
{
|
|
OptionArgumentLocation = ReadLocation();
|
|
OptionType = OptionType.StrictOff;
|
|
}
|
|
else if (Peek().Type == TokenType.On)
|
|
{
|
|
OptionArgumentLocation = ReadLocation();
|
|
OptionType = OptionType.StrictOn;
|
|
}
|
|
else if (Peek().Type == TokenType.Identifier)
|
|
{
|
|
OptionType = OptionType.SyntaxError;
|
|
ReportSyntaxError(SyntaxErrorType.InvalidOptionStrictType, SpanFrom(startLocation));
|
|
}
|
|
else
|
|
{
|
|
OptionType = OptionType.Strict;
|
|
}
|
|
}
|
|
else if (Peek().AsUnreservedKeyword() == TokenType.Compare)
|
|
{
|
|
OptionTypeLocation = ReadLocation();
|
|
if (Peek().AsUnreservedKeyword() == TokenType.Binary)
|
|
{
|
|
OptionArgumentLocation = ReadLocation();
|
|
OptionType = OptionType.CompareBinary;
|
|
}
|
|
else if (Peek().AsUnreservedKeyword() == TokenType.Text)
|
|
{
|
|
OptionArgumentLocation = ReadLocation();
|
|
OptionType = OptionType.CompareText;
|
|
}
|
|
else
|
|
{
|
|
OptionType = OptionType.SyntaxError;
|
|
ReportSyntaxError(SyntaxErrorType.InvalidOptionCompareType, SpanFrom(startLocation));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
OptionType = OptionType.SyntaxError;
|
|
ReportSyntaxError(SyntaxErrorType.InvalidOptionType, SpanFrom(startLocation));
|
|
}
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
return new OptionDeclaration(OptionType, OptionTypeLocation, OptionArgumentLocation, SpanFrom(startLocation), ParseTrailingComments());
|
|
}
|
|
|
|
private Declaration ParseAttributeDeclaration()
|
|
{
|
|
AttributeBlockCollection Attributes = ParseAttributes(AttributeTypes.Module | AttributeTypes.Assembly);
|
|
return new AttributeDeclaration(Attributes, Attributes.Span, ParseTrailingComments());
|
|
}
|
|
|
|
private Declaration ParseDeclaration(ref Token terminator)
|
|
{
|
|
Declaration Declaration = null;
|
|
AttributeBlockCollection Attributes = null;
|
|
ModifierCollection Modifiers = null;
|
|
TokenType LookAhead = TokenType.None;
|
|
Token Start = Peek();
|
|
ErrorInConstruct = false;
|
|
Location StartLocation = Peek().Span.Start;
|
|
LookAhead = PeekAheadFor(TokenType.Assembly, TokenType.Module, TokenType.GreaterThan);
|
|
if (Peek().Type != TokenType.LessThan || (LookAhead != TokenType.Assembly && LookAhead != TokenType.Module))
|
|
{
|
|
Attributes = ParseAttributes();
|
|
Modifiers = ParseDeclarationModifierList();
|
|
}
|
|
switch (Peek().Type)
|
|
{
|
|
case TokenType.End:
|
|
if (Attributes == null && Modifiers == null)
|
|
{
|
|
Declaration = ParseEndDeclaration();
|
|
break;
|
|
}
|
|
goto case TokenType.Identifier;
|
|
case TokenType.Property:
|
|
Declaration = ParsePropertyDeclaration(StartLocation, Attributes, Modifiers);
|
|
break;
|
|
case TokenType.Declare:
|
|
Declaration = ParseExternalDeclaration(StartLocation, Attributes, Modifiers);
|
|
break;
|
|
case TokenType.Function:
|
|
case TokenType.Sub:
|
|
Declaration = ParseMethodDeclaration(StartLocation, Attributes, Modifiers);
|
|
break;
|
|
case TokenType.Get:
|
|
case TokenType.Set:
|
|
Declaration = ParseAccessorDeclaration(StartLocation, Attributes, Modifiers);
|
|
break;
|
|
case TokenType.AddHandler:
|
|
case TokenType.RaiseEvent:
|
|
case TokenType.RemoveHandler:
|
|
Declaration = ParseEventAccessorDeclaration(StartLocation, Attributes, Modifiers);
|
|
break;
|
|
case TokenType.Event:
|
|
Declaration = ParseEventDeclaration(StartLocation, Attributes, Modifiers);
|
|
break;
|
|
case TokenType.Operator:
|
|
Declaration = ParseOperatorDeclaration(StartLocation, Attributes, Modifiers);
|
|
break;
|
|
case TokenType.Delegate:
|
|
Declaration = ParseDelegateDeclaration(StartLocation, Attributes, Modifiers);
|
|
break;
|
|
case TokenType.Class:
|
|
Declaration = ParseTypeDeclaration(StartLocation, Attributes, Modifiers, TreeType.ClassDeclaration);
|
|
break;
|
|
case TokenType.Structure:
|
|
Declaration = ParseTypeDeclaration(StartLocation, Attributes, Modifiers, TreeType.StructureDeclaration);
|
|
break;
|
|
case TokenType.Module:
|
|
Declaration = ParseTypeDeclaration(StartLocation, Attributes, Modifiers, TreeType.ModuleDeclaration);
|
|
break;
|
|
case TokenType.Interface:
|
|
Declaration = ParseTypeDeclaration(StartLocation, Attributes, Modifiers, TreeType.InterfaceDeclaration);
|
|
break;
|
|
case TokenType.Enum:
|
|
Declaration = ParseEnumDeclaration(StartLocation, Attributes, Modifiers);
|
|
break;
|
|
case TokenType.Namespace:
|
|
Declaration = ParseNamespaceDeclaration(StartLocation, Attributes, Modifiers);
|
|
break;
|
|
case TokenType.Implements:
|
|
Declaration = ParseTypeListDeclaration(StartLocation, Attributes, Modifiers, TreeType.ImplementsDeclaration);
|
|
break;
|
|
case TokenType.Inherits:
|
|
Declaration = ParseTypeListDeclaration(StartLocation, Attributes, Modifiers, TreeType.InheritsDeclaration);
|
|
break;
|
|
case TokenType.Imports:
|
|
Declaration = ParseImportsDeclaration(StartLocation, Attributes, Modifiers);
|
|
break;
|
|
case TokenType.Option:
|
|
Declaration = ParseOptionDeclaration(StartLocation, Attributes, Modifiers);
|
|
break;
|
|
case TokenType.LessThan:
|
|
Declaration = ParseAttributeDeclaration();
|
|
break;
|
|
case TokenType.Identifier:
|
|
Declaration = ((Peek().AsUnreservedKeyword() != TokenType.Custom || PeekAheadOne().Type != TokenType.Event) ? ParseVariableListDeclaration(StartLocation, Attributes, Modifiers) : ParseCustomEventDeclaration(StartLocation, Attributes, Modifiers));
|
|
break;
|
|
case TokenType.EndOfStream:
|
|
case TokenType.LineTerminator:
|
|
case TokenType.Colon:
|
|
if (Attributes != null || Modifiers != null)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedIdentifier, Peek());
|
|
}
|
|
break;
|
|
case TokenType.Comment:
|
|
{
|
|
List<Comment> Comments = new List<Comment>();
|
|
Token LastTerminator;
|
|
do
|
|
{
|
|
CommentToken CommentToken = (CommentToken)Scanner.Read();
|
|
Comments.Add(new Comment(CommentToken.Comment, CommentToken.IsREM, CommentToken.Span));
|
|
LastTerminator = Read();
|
|
}
|
|
while (Peek().Type == TokenType.Comment);
|
|
Backtrack(LastTerminator);
|
|
Declaration = new EmptyDeclaration(SpanFrom(Start), Comments);
|
|
break;
|
|
}
|
|
default:
|
|
ReportSyntaxError(SyntaxErrorType.SyntaxError, Peek());
|
|
break;
|
|
}
|
|
terminator = VerifyEndOfStatement();
|
|
return Declaration;
|
|
}
|
|
|
|
private Declaration ParseDeclarationInEnum(ref Token terminator)
|
|
{
|
|
Expression Expression = null;
|
|
Declaration Declaration = null;
|
|
Token Start = Peek();
|
|
if (Start.Type == TokenType.Comment)
|
|
{
|
|
List<Comment> Comments = new List<Comment>();
|
|
Token LastTerminator;
|
|
do
|
|
{
|
|
CommentToken CommentToken = (CommentToken)Scanner.Read();
|
|
Comments.Add(new Comment(CommentToken.Comment, CommentToken.IsREM, CommentToken.Span));
|
|
LastTerminator = Read();
|
|
}
|
|
while (Peek().Type == TokenType.Comment);
|
|
Backtrack(LastTerminator);
|
|
Declaration = new EmptyDeclaration(SpanFrom(Start), Comments);
|
|
}
|
|
else if (Start.Type != TokenType.LineTerminator && Start.Type != TokenType.Colon)
|
|
{
|
|
ErrorInConstruct = false;
|
|
Location StartLocation = Peek().Span.Start;
|
|
AttributeBlockCollection Attributes = ParseAttributes();
|
|
if (Peek().Type == TokenType.End && Attributes == null)
|
|
{
|
|
Declaration = ParseEndDeclaration();
|
|
}
|
|
else
|
|
{
|
|
SimpleName Name = ParseSimpleName(allowKeyword: false);
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Equals);
|
|
}
|
|
Location EqualsLocation = default(Location);
|
|
if (Peek().Type == TokenType.Equals)
|
|
{
|
|
EqualsLocation = ReadLocation();
|
|
Expression = ParseExpression();
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt();
|
|
}
|
|
}
|
|
Declaration = new EnumValueDeclaration(Attributes, Name, EqualsLocation, Expression, SpanFrom(StartLocation), ParseTrailingComments());
|
|
}
|
|
}
|
|
terminator = VerifyEndOfStatement();
|
|
return Declaration;
|
|
}
|
|
|
|
private DeclarationCollection ParseDeclarationBlock(Span blockStartSpan, TreeType blockType, ref List<Comment> Comments, ref EndBlockDeclaration endDeclaration)
|
|
{
|
|
List<Declaration> Declarations = new List<Declaration>();
|
|
List<Location> ColonLocations = new List<Location>();
|
|
bool BlockTerminated = false;
|
|
Comments = ParseTrailingComments();
|
|
Token Terminator = VerifyEndOfStatement();
|
|
if (Terminator.Type == TokenType.Colon)
|
|
{
|
|
ColonLocations.Add(Terminator.Span.Start);
|
|
}
|
|
Token Start = Peek();
|
|
Location DeclarationsEnd = Start.Span.Finish;
|
|
endDeclaration = null;
|
|
PushBlockContext(blockType);
|
|
while (Peek().Type != TokenType.EndOfStream)
|
|
{
|
|
Token PreviousTerminator = Terminator;
|
|
Declaration Declaration = ((blockType != TreeType.EnumDeclaration) ? ParseDeclaration(ref Terminator) : ParseDeclarationInEnum(ref Terminator));
|
|
if (Declaration != null)
|
|
{
|
|
if (Declaration.Type == TreeType.EndBlockDeclaration)
|
|
{
|
|
EndBlockDeclaration PotentialEndDeclaration = (EndBlockDeclaration)Declaration;
|
|
if (DeclarationEndsBlock(blockType, PotentialEndDeclaration))
|
|
{
|
|
endDeclaration = PotentialEndDeclaration;
|
|
Backtrack(Terminator);
|
|
BlockTerminated = true;
|
|
break;
|
|
}
|
|
bool DeclarationEndsOuterBlock = false;
|
|
foreach (TreeType BlockContext in BlockContextStack)
|
|
{
|
|
if (DeclarationEndsBlock(BlockContext, PotentialEndDeclaration))
|
|
{
|
|
DeclarationEndsOuterBlock = true;
|
|
break;
|
|
}
|
|
}
|
|
if (DeclarationEndsOuterBlock)
|
|
{
|
|
ReportMismatchedEndError(blockType, Declaration.Span);
|
|
Backtrack(PreviousTerminator);
|
|
BlockTerminated = true;
|
|
break;
|
|
}
|
|
ReportMissingBeginDeclarationError(PotentialEndDeclaration);
|
|
}
|
|
else
|
|
{
|
|
SyntaxErrorType ErrorType = ValidDeclaration(blockType, Declaration, Declarations);
|
|
if (ErrorType != 0)
|
|
{
|
|
ReportSyntaxError(ErrorType, Declaration.Span);
|
|
}
|
|
}
|
|
Declarations.Add(Declaration);
|
|
}
|
|
if (Terminator.Type == TokenType.Colon)
|
|
{
|
|
ColonLocations.Add(Terminator.Span.Start);
|
|
}
|
|
DeclarationsEnd = Terminator.Span.Finish;
|
|
}
|
|
if (!BlockTerminated)
|
|
{
|
|
ReportMismatchedEndError(blockType, blockStartSpan);
|
|
}
|
|
PopBlockContext();
|
|
if (Declarations.Count == 0 && ColonLocations.Count == 0)
|
|
{
|
|
return null;
|
|
}
|
|
return new DeclarationCollection(Declarations, ColonLocations, new Span(Start.Span.Start, DeclarationsEnd));
|
|
}
|
|
|
|
private Parameter ParseParameter()
|
|
{
|
|
Token Start = Peek();
|
|
TypeName Type = null;
|
|
Initializer Initializer = null;
|
|
AttributeBlockCollection Attributes = ParseAttributes();
|
|
ModifierCollection Modifiers = ParseParameterModifierList();
|
|
VariableName VariableName = ParseVariableName(allowExplicitArraySizes: false);
|
|
if (ErrorInConstruct && PeekAheadFor(TokenType.As, TokenType.Comma, TokenType.RightParenthesis) == TokenType.As)
|
|
{
|
|
ResyncAt(TokenType.As);
|
|
}
|
|
Location AsLocation = default(Location);
|
|
if (Peek().Type == TokenType.As)
|
|
{
|
|
AsLocation = ReadLocation();
|
|
Type = ParseTypeName(allowArrayType: true);
|
|
}
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Equals, TokenType.Comma, TokenType.RightParenthesis);
|
|
}
|
|
Location EqualsLocation = default(Location);
|
|
if (Peek().Type == TokenType.Equals)
|
|
{
|
|
EqualsLocation = ReadLocation();
|
|
Initializer = ParseInitializer();
|
|
}
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Comma, TokenType.RightParenthesis);
|
|
}
|
|
return new Parameter(Attributes, Modifiers, VariableName, AsLocation, Type, EqualsLocation, Initializer, SpanFrom(Start));
|
|
}
|
|
|
|
private bool ParametersContinue()
|
|
{
|
|
Token NextToken = Peek();
|
|
if (NextToken.Type == TokenType.Comma)
|
|
{
|
|
return true;
|
|
}
|
|
if (NextToken.Type == TokenType.RightParenthesis || MustEndStatement(NextToken))
|
|
{
|
|
return false;
|
|
}
|
|
ReportSyntaxError(SyntaxErrorType.ParameterSyntax, NextToken);
|
|
ResyncAt(TokenType.Comma, TokenType.RightParenthesis);
|
|
if (Peek().Type == TokenType.Comma)
|
|
{
|
|
ErrorInConstruct = false;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private ParameterCollection ParseParameters()
|
|
{
|
|
Token Start = Peek();
|
|
List<Parameter> Parameters = new List<Parameter>();
|
|
List<Location> CommaLocations = new List<Location>();
|
|
if (Start.Type != TokenType.LeftParenthesis)
|
|
{
|
|
return null;
|
|
}
|
|
Read();
|
|
if (Peek().Type != TokenType.RightParenthesis)
|
|
{
|
|
do
|
|
{
|
|
if (Parameters.Count > 0)
|
|
{
|
|
CommaLocations.Add(ReadLocation());
|
|
}
|
|
Parameters.Add(ParseParameter());
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Comma, TokenType.RightParenthesis);
|
|
}
|
|
}
|
|
while (ParametersContinue());
|
|
}
|
|
Location RightParenthesisLocation = default(Location);
|
|
if (Peek().Type == TokenType.RightParenthesis)
|
|
{
|
|
RightParenthesisLocation = ReadLocation();
|
|
}
|
|
else
|
|
{
|
|
Token CurrentToken = Peek();
|
|
ResyncAt(TokenType.LeftParenthesis, TokenType.RightParenthesis);
|
|
if (Peek().Type == TokenType.RightParenthesis)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.SyntaxError, Peek());
|
|
RightParenthesisLocation = ReadLocation();
|
|
}
|
|
else
|
|
{
|
|
Backtrack(CurrentToken);
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedRightParenthesis, Peek());
|
|
}
|
|
}
|
|
return new ParameterCollection(Parameters, CommaLocations, RightParenthesisLocation, SpanFrom(Start));
|
|
}
|
|
|
|
private TypeConstraintCollection ParseTypeConstraints()
|
|
{
|
|
Token Start = Peek();
|
|
List<Location> CommaLocations = new List<Location>();
|
|
List<TypeName> Types = new List<TypeName>();
|
|
Location RightBracketLocation = default(Location);
|
|
if (Peek().Type == TokenType.LeftCurlyBrace)
|
|
{
|
|
Read();
|
|
do
|
|
{
|
|
if (Types.Count > 0)
|
|
{
|
|
CommaLocations.Add(ReadLocation());
|
|
}
|
|
Types.Add(ParseTypeName(allowArrayType: true));
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Comma);
|
|
}
|
|
}
|
|
while (Peek().Type == TokenType.Comma);
|
|
RightBracketLocation = VerifyExpectedToken(TokenType.RightCurlyBrace);
|
|
}
|
|
else
|
|
{
|
|
Types.Add(ParseTypeName(allowArrayType: true));
|
|
}
|
|
return new TypeConstraintCollection(Types, CommaLocations, RightBracketLocation, SpanFrom(Start));
|
|
}
|
|
|
|
private TypeParameter ParseTypeParameter()
|
|
{
|
|
Token Start = Peek();
|
|
TypeConstraintCollection TypeConstraints = null;
|
|
SimpleName Name = ParseSimpleName(allowKeyword: false);
|
|
if (ErrorInConstruct && PeekAheadFor(TokenType.As, TokenType.Comma, TokenType.RightParenthesis) == TokenType.As)
|
|
{
|
|
ResyncAt(TokenType.As);
|
|
}
|
|
Location AsLocation = default(Location);
|
|
if (Peek().Type == TokenType.As)
|
|
{
|
|
AsLocation = ReadLocation();
|
|
TypeConstraints = ParseTypeConstraints();
|
|
}
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Equals, TokenType.Comma, TokenType.RightParenthesis);
|
|
}
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Comma, TokenType.RightParenthesis);
|
|
}
|
|
return new TypeParameter(Name, AsLocation, TypeConstraints, SpanFrom(Start));
|
|
}
|
|
|
|
private TypeParameterCollection ParseTypeParameters()
|
|
{
|
|
Token Start = Peek();
|
|
List<TypeParameter> TypeParameters = new List<TypeParameter>();
|
|
List<Location> CommaLocations = new List<Location>();
|
|
if (Start.Type != TokenType.LeftParenthesis || Scanner.Version < LanguageVersion.VisualBasic80)
|
|
{
|
|
return null;
|
|
}
|
|
Read();
|
|
if (Peek().Type != TokenType.Of || Scanner.Version < LanguageVersion.VisualBasic80)
|
|
{
|
|
Backtrack(Start);
|
|
return null;
|
|
}
|
|
Location OfLocation = VerifyExpectedToken(TokenType.Of);
|
|
do
|
|
{
|
|
if (TypeParameters.Count > 0)
|
|
{
|
|
CommaLocations.Add(ReadLocation());
|
|
}
|
|
TypeParameters.Add(ParseTypeParameter());
|
|
if (ErrorInConstruct)
|
|
{
|
|
ResyncAt(TokenType.Comma, TokenType.RightParenthesis);
|
|
}
|
|
}
|
|
while (ParametersContinue());
|
|
Location RightParenthesisLocation = VerifyExpectedToken(TokenType.RightParenthesis);
|
|
return new TypeParameterCollection(OfLocation, TypeParameters, CommaLocations, RightParenthesisLocation, SpanFrom(Start));
|
|
}
|
|
|
|
private File ParseFile()
|
|
{
|
|
List<Declaration> Declarations = new List<Declaration>();
|
|
List<Location> ColonLocations = new List<Location>();
|
|
Token Terminator = null;
|
|
Token Start = Peek();
|
|
while (Peek().Type != TokenType.EndOfStream)
|
|
{
|
|
Declaration Declaration = ParseDeclaration(ref Terminator);
|
|
if (Declaration != null)
|
|
{
|
|
SyntaxErrorType ErrorType = SyntaxErrorType.None;
|
|
ErrorType = ValidDeclaration(TreeType.File, Declaration, Declarations);
|
|
if (ErrorType != 0)
|
|
{
|
|
ReportSyntaxError(ErrorType, Declaration.Span);
|
|
}
|
|
Declarations.Add(Declaration);
|
|
}
|
|
if (Terminator.Type == TokenType.Colon)
|
|
{
|
|
ColonLocations.Add(Terminator.Span.Start);
|
|
}
|
|
}
|
|
if (Declarations.Count == 0 && ColonLocations.Count == 0)
|
|
{
|
|
return new File(null, SpanFrom(Start));
|
|
}
|
|
return new File(new DeclarationCollection(Declarations, ColonLocations, SpanFrom(Start)), SpanFrom(Start));
|
|
}
|
|
|
|
private ScriptBlock ParseScriptFile()
|
|
{
|
|
List<Statement> Statements = new List<Statement>();
|
|
List<Location> ColonLocations = new List<Location>();
|
|
bool BlockTerminated = false;
|
|
Token Start = Peek();
|
|
Location StatementsEnd = Start.Span.Finish;
|
|
Token Terminator = default(Token);
|
|
while (Peek().Type != TokenType.EndOfStream)
|
|
{
|
|
Token PreviousTerminator = Terminator;
|
|
Statement Statement = ParseStatementOrDeclaration(ref Terminator);
|
|
if (Statement != null)
|
|
{
|
|
Statements.Add(Statement);
|
|
}
|
|
if (Terminator.Type == TokenType.Colon)
|
|
{
|
|
ColonLocations.Add(Terminator.Span.Start);
|
|
StatementsEnd = Terminator.Span.Finish;
|
|
}
|
|
else
|
|
{
|
|
StatementsEnd = Terminator.Span.Finish;
|
|
}
|
|
}
|
|
if (Statements.Count == 0 && ColonLocations.Count == 0)
|
|
{
|
|
return new ScriptBlock(null, SpanFrom(Start));
|
|
}
|
|
return new ScriptBlock(new StatementCollection(Statements, ColonLocations, new Span(Start.Span.Start, StatementsEnd)), SpanFrom(Start));
|
|
}
|
|
|
|
private void ParseExternalSourceStatement(Token start)
|
|
{
|
|
Read();
|
|
if (CurrentExternalSourceContext != null)
|
|
{
|
|
ResyncAt();
|
|
ReportSyntaxError(SyntaxErrorType.NestedExternalSourceStatement, SpanFrom(start));
|
|
return;
|
|
}
|
|
VerifyExpectedToken(TokenType.LeftParenthesis);
|
|
if (Peek().Type != TokenType.StringLiteral)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedStringLiteral, Peek());
|
|
ResyncAt();
|
|
return;
|
|
}
|
|
string File = ((StringLiteralToken)Read()).Literal;
|
|
VerifyExpectedToken(TokenType.Comma);
|
|
if (Peek().Type != TokenType.IntegerLiteral)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedIntegerLiteral, Peek());
|
|
ResyncAt();
|
|
return;
|
|
}
|
|
long Line = ((IntegerLiteralToken)Read()).Literal;
|
|
VerifyExpectedToken(TokenType.RightParenthesis);
|
|
CurrentExternalSourceContext = new ExternalSourceContext();
|
|
ExternalSourceContext currentExternalSourceContext = CurrentExternalSourceContext;
|
|
currentExternalSourceContext.File = File;
|
|
currentExternalSourceContext.Line = Line;
|
|
currentExternalSourceContext.Start = Peek().Span.Start;
|
|
currentExternalSourceContext = null;
|
|
}
|
|
|
|
private void ParseExternalChecksumStatement()
|
|
{
|
|
Read();
|
|
VerifyExpectedToken(TokenType.LeftParenthesis);
|
|
if (Peek().Type != TokenType.StringLiteral)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedStringLiteral, Peek());
|
|
ResyncAt();
|
|
return;
|
|
}
|
|
string Filename = ((StringLiteralToken)Read()).Literal;
|
|
VerifyExpectedToken(TokenType.Comma);
|
|
if (Peek().Type != TokenType.StringLiteral)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedStringLiteral, Peek());
|
|
ResyncAt();
|
|
return;
|
|
}
|
|
string Guid = ((StringLiteralToken)Read()).Literal;
|
|
VerifyExpectedToken(TokenType.Comma);
|
|
if (Peek().Type != TokenType.StringLiteral)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedStringLiteral, Peek());
|
|
ResyncAt();
|
|
return;
|
|
}
|
|
string Checksum = ((StringLiteralToken)Read()).Literal;
|
|
VerifyExpectedToken(TokenType.RightParenthesis);
|
|
if (ExternalChecksums != null)
|
|
{
|
|
ExternalChecksums.Add(new ExternalChecksum(Filename, Guid, Checksum));
|
|
}
|
|
}
|
|
|
|
private void ParseRegionStatement(Token start, bool statementLevel)
|
|
{
|
|
if (statementLevel)
|
|
{
|
|
ResyncAt();
|
|
ReportSyntaxError(SyntaxErrorType.RegionInsideMethod, SpanFrom(start));
|
|
return;
|
|
}
|
|
Read();
|
|
if (Peek().Type != TokenType.StringLiteral)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedStringLiteral, Peek());
|
|
ResyncAt();
|
|
return;
|
|
}
|
|
string Description = ((StringLiteralToken)Read()).Literal;
|
|
RegionContext RegionContext = new RegionContext();
|
|
RegionContext.Description = Description;
|
|
RegionContext.Start = Peek().Span.Start;
|
|
RegionContextStack.Push(RegionContext);
|
|
}
|
|
|
|
private void ParseEndPreprocessingStatement(Token start, bool statementLevel)
|
|
{
|
|
Read();
|
|
if (Peek().AsUnreservedKeyword() == TokenType.ExternalSource)
|
|
{
|
|
Read();
|
|
if (CurrentExternalSourceContext == null)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.EndExternalSourceWithoutExternalSource, SpanFrom(start));
|
|
ResyncAt();
|
|
return;
|
|
}
|
|
if (ExternalLineMappings != null)
|
|
{
|
|
ExternalSourceContext currentExternalSourceContext = CurrentExternalSourceContext;
|
|
ExternalLineMappings.Add(new ExternalLineMapping(currentExternalSourceContext.Start, start.Span.Start, currentExternalSourceContext.File, currentExternalSourceContext.Line));
|
|
currentExternalSourceContext = null;
|
|
}
|
|
CurrentExternalSourceContext = null;
|
|
}
|
|
else if (Peek().AsUnreservedKeyword() == TokenType.Region)
|
|
{
|
|
Read();
|
|
if (statementLevel)
|
|
{
|
|
ResyncAt();
|
|
ReportSyntaxError(SyntaxErrorType.RegionInsideMethod, SpanFrom(start));
|
|
return;
|
|
}
|
|
if (RegionContextStack.Count == 0)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.EndRegionWithoutRegion, SpanFrom(start));
|
|
ResyncAt();
|
|
return;
|
|
}
|
|
RegionContext RegionContext = RegionContextStack.Pop();
|
|
if (SourceRegions != null)
|
|
{
|
|
SourceRegions.Add(new SourceRegion(RegionContext.Start, start.Span.Start, RegionContext.Description));
|
|
}
|
|
}
|
|
else if (Peek().Type == TokenType.If)
|
|
{
|
|
Read();
|
|
if (ConditionalCompilationContextStack.Count == 0)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.CCEndIfWithoutCCIf, SpanFrom(start));
|
|
}
|
|
else
|
|
{
|
|
ConditionalCompilationContextStack.Pop();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ResyncAt();
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedEndKind, Peek());
|
|
}
|
|
}
|
|
|
|
private static TypeCode TypeCodeOfCastExpression(IntrinsicType castType)
|
|
{
|
|
switch (castType)
|
|
{
|
|
case IntrinsicType.Boolean:
|
|
return TypeCode.Boolean;
|
|
case IntrinsicType.Byte:
|
|
return TypeCode.Byte;
|
|
case IntrinsicType.Char:
|
|
return TypeCode.Char;
|
|
case IntrinsicType.Date:
|
|
return TypeCode.DateTime;
|
|
case IntrinsicType.Decimal:
|
|
return TypeCode.Decimal;
|
|
case IntrinsicType.Double:
|
|
return TypeCode.Double;
|
|
case IntrinsicType.Integer:
|
|
return TypeCode.Int32;
|
|
case IntrinsicType.Long:
|
|
return TypeCode.Int64;
|
|
case IntrinsicType.Object:
|
|
return TypeCode.Object;
|
|
case IntrinsicType.Short:
|
|
return TypeCode.Int16;
|
|
case IntrinsicType.Single:
|
|
return TypeCode.Single;
|
|
case IntrinsicType.String:
|
|
return TypeCode.String;
|
|
default:
|
|
Debug.Assert(condition: false, "Unexpected!");
|
|
return TypeCode.Empty;
|
|
}
|
|
}
|
|
|
|
private static bool EitherIsTypeCode(TypeCode x, TypeCode y, TypeCode type)
|
|
{
|
|
return x == type || y == type;
|
|
}
|
|
|
|
private static bool IsEitherTypeCode(TypeCode x, TypeCode type1, TypeCode type2)
|
|
{
|
|
return x == type1 || x == type2;
|
|
}
|
|
|
|
private void StartParsing(Scanner scanner, IList<SyntaxError> errorTable, bool preprocess = false, IDictionary<string, object> conditionalCompilationConstants = null, IList<SourceRegion> sourceRegions = null, IList<ExternalLineMapping> externalLineMappings = null, IList<ExternalChecksum> externalChecksums = null)
|
|
{
|
|
Scanner = scanner;
|
|
ErrorTable = errorTable;
|
|
Preprocess = preprocess;
|
|
if (conditionalCompilationConstants == null)
|
|
{
|
|
ConditionalCompilationConstants = new Dictionary<string, object>();
|
|
}
|
|
else
|
|
{
|
|
ConditionalCompilationConstants = new Dictionary<string, object>(conditionalCompilationConstants);
|
|
}
|
|
ExternalLineMappings = externalLineMappings;
|
|
SourceRegions = sourceRegions;
|
|
ExternalChecksums = externalChecksums;
|
|
ErrorInConstruct = false;
|
|
AtBeginningOfLine = true;
|
|
BlockContextStack.Clear();
|
|
}
|
|
|
|
private void FinishParsing()
|
|
{
|
|
if (CurrentExternalSourceContext != null)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedEndExternalSource, Peek());
|
|
}
|
|
if (RegionContextStack.Count != 0)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedEndRegion, Peek());
|
|
}
|
|
if (ConditionalCompilationContextStack.Count != 0)
|
|
{
|
|
ReportSyntaxError(SyntaxErrorType.ExpectedCCEndIf, Peek());
|
|
}
|
|
StartParsing(null, null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parse an entire file.
|
|
/// </summary>
|
|
/// <param name="scanner">The scanner to use to fetch the tokens.</param>
|
|
/// <param name="errorTable">The list of errors produced during parsing.</param>
|
|
/// <returns>A file-level parse tree.</returns>
|
|
public File ParseFile(Scanner scanner, IList<SyntaxError> errorTable)
|
|
{
|
|
StartParsing(scanner, errorTable, preprocess: true);
|
|
File File = ParseFile();
|
|
FinishParsing();
|
|
return File;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parse an entire file.
|
|
/// </summary>
|
|
/// <param name="scanner">The scanner to use to fetch the tokens.</param>
|
|
/// <param name="errorTable">The list of errors produced during parsing.</param>
|
|
/// <param name="conditionalCompilationConstants">Pre-defined conditional compilation constants.</param>
|
|
/// <param name="sourceRegions">Source regions defined in the file.</param>
|
|
/// <param name="externalLineMappings">External line mappings defined in the file.</param>
|
|
/// <returns>A file-level parse tree.</returns>
|
|
public File ParseFile(Scanner scanner, IList<SyntaxError> errorTable, IDictionary<string, object> conditionalCompilationConstants, IList<SourceRegion> sourceRegions, IList<ExternalLineMapping> externalLineMappings, IList<ExternalChecksum> externalChecksums)
|
|
{
|
|
StartParsing(scanner, errorTable, preprocess: true, conditionalCompilationConstants, sourceRegions, externalLineMappings, externalChecksums);
|
|
File File = ParseFile();
|
|
FinishParsing();
|
|
return File;
|
|
}
|
|
|
|
public ScriptBlock ParseScriptFile(Scanner scanner, IList<SyntaxError> errorTable)
|
|
{
|
|
StartParsing(scanner, errorTable, preprocess: true);
|
|
ScriptBlock File = ParseScriptFile();
|
|
FinishParsing();
|
|
return File;
|
|
}
|
|
|
|
public ScriptBlock ParseScriptFile(Scanner scanner, IList<SyntaxError> errorTable, IDictionary<string, object> conditionalCompilationConstants, IList<SourceRegion> sourceRegions, IList<ExternalLineMapping> externalLineMappings, IList<ExternalChecksum> externalChecksums)
|
|
{
|
|
StartParsing(scanner, errorTable, preprocess: true, conditionalCompilationConstants, sourceRegions, externalLineMappings, externalChecksums);
|
|
ScriptBlock File = ParseScriptFile();
|
|
FinishParsing();
|
|
return File;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parse a declaration.
|
|
/// </summary>
|
|
/// <param name="scanner">The scanner to use to fetch the tokens.</param>
|
|
/// <param name="errorTable">The list of errors produced during parsing.</param>
|
|
/// <returns>A declaration-level parse tree.</returns>
|
|
public Declaration ParseDeclaration(Scanner scanner, IList<SyntaxError> errorTable)
|
|
{
|
|
StartParsing(scanner, errorTable);
|
|
Token terminator = null;
|
|
Declaration Declaration = ParseDeclaration(ref terminator);
|
|
FinishParsing();
|
|
return Declaration;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parse a statement.
|
|
/// </summary>
|
|
/// <param name="scanner">The scanner to use to fetch the tokens.</param>
|
|
/// <param name="errorTable">The list of errors produced during parsing.</param>
|
|
/// <returns>A statement-level parse tree.</returns>
|
|
public Statement ParseStatement(Scanner scanner, IList<SyntaxError> errorTable)
|
|
{
|
|
StartParsing(scanner, errorTable);
|
|
Token terminator = null;
|
|
Statement Statement = ParseStatement(ref terminator);
|
|
FinishParsing();
|
|
return Statement;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parse an expression.
|
|
/// </summary>
|
|
/// <param name="scanner">The scanner to use to fetch the tokens.</param>
|
|
/// <param name="errorTable">The list of errors produced during parsing.</param>
|
|
/// <returns>An expression-level parse tree.</returns>
|
|
public Expression ParseExpression(Scanner scanner, IList<SyntaxError> errorTable)
|
|
{
|
|
StartParsing(scanner, errorTable);
|
|
Expression Expression = ParseExpression();
|
|
FinishParsing();
|
|
return Expression;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parse a type name.
|
|
/// </summary>
|
|
/// <param name="scanner">The scanner to use to fetch the tokens.</param>
|
|
/// <param name="errorTable">The list of errors produced during parsing.</param>
|
|
/// <returns>A typename-level parse tree.</returns>
|
|
public TypeName ParseTypeName(Scanner scanner, IList<SyntaxError> errorTable)
|
|
{
|
|
StartParsing(scanner, errorTable);
|
|
TypeName TypeName = ParseTypeName(allowArrayType: true);
|
|
FinishParsing();
|
|
return TypeName;
|
|
}
|
|
}
|