diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..3729ff0
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,25 @@
+**/.classpath
+**/.dockerignore
+**/.env
+**/.git
+**/.gitignore
+**/.project
+**/.settings
+**/.toolstarget
+**/.vs
+**/.vscode
+**/*.*proj.user
+**/*.dbmdl
+**/*.jfm
+**/azds.yaml
+**/bin
+**/charts
+**/docker-compose*
+**/Dockerfile*
+**/node_modules
+**/npm-debug.log
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
+LICENSE
+README.md
\ No newline at end of file
diff --git a/.vs/aspclassic/DesignTimeBuild/.dtbcache.v2 b/.vs/aspclassic/DesignTimeBuild/.dtbcache.v2
new file mode 100644
index 0000000..bf01a1f
Binary files /dev/null and b/.vs/aspclassic/DesignTimeBuild/.dtbcache.v2 differ
diff --git a/.vs/aspclassic/v17/.futdcache.v1 b/.vs/aspclassic/v17/.futdcache.v1
new file mode 100644
index 0000000..42fba2e
Binary files /dev/null and b/.vs/aspclassic/v17/.futdcache.v1 differ
diff --git a/.vs/aspclassic/v17/.suo b/.vs/aspclassic/v17/.suo
new file mode 100644
index 0000000..a5cce45
Binary files /dev/null and b/.vs/aspclassic/v17/.suo differ
diff --git a/AspClassic.Parser/AddHandlerAccessorDeclaration.cs b/AspClassic.Parser/AddHandlerAccessorDeclaration.cs
new file mode 100644
index 0000000..649d45b
--- /dev/null
+++ b/AspClassic.Parser/AddHandlerAccessorDeclaration.cs
@@ -0,0 +1,67 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a AddHandler property accessor.
+///
+public sealed class AddHandlerAccessorDeclaration : ModifiedDeclaration
+{
+ private readonly Location _AddHandlerLocation;
+
+ private readonly ParameterCollection _Parameters;
+
+ private readonly StatementCollection _Statements;
+
+ private readonly EndBlockDeclaration _EndStatement;
+
+ ///
+ /// The location of the 'AddHandler'.
+ ///
+ public Location AddHandlerLocation => _AddHandlerLocation;
+
+ ///
+ /// The accessor's parameters.
+ ///
+ public ParameterCollection Parameters => _Parameters;
+
+ ///
+ /// The statements in the accessor.
+ ///
+ public StatementCollection Statements => _Statements;
+
+ ///
+ /// The End declaration for the accessor.
+ ///
+ public EndBlockDeclaration EndStatement => _EndStatement;
+
+ ///
+ /// Constructs a new parse tree for a property accessor.
+ ///
+ /// The attributes for the parse tree.
+ /// The location of the 'AddHandler'.
+ /// The parameters of the declaration.
+ /// The statements in the declaration.
+ /// The end block declaration, if any.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public AddHandlerAccessorDeclaration(AttributeBlockCollection attributes, Location addHandlerLocation, ParameterCollection parameters, StatementCollection statements, EndBlockDeclaration endStatement, Span span, IList comments)
+ : base(TreeType.AddHandlerAccessorDeclaration, attributes, null, span, comments)
+ {
+ SetParent(parameters);
+ SetParent(statements);
+ SetParent(endStatement);
+ _Parameters = parameters;
+ _AddHandlerLocation = addHandlerLocation;
+ _Statements = statements;
+ _EndStatement = endStatement;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, Parameters);
+ Tree.AddChild(childList, Statements);
+ Tree.AddChild(childList, EndStatement);
+ }
+}
diff --git a/AspClassic.Parser/AddHandlerStatement.cs b/AspClassic.Parser/AddHandlerStatement.cs
new file mode 100644
index 0000000..602679e
--- /dev/null
+++ b/AspClassic.Parser/AddHandlerStatement.cs
@@ -0,0 +1,22 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an AddHandler statement.
+///
+public sealed class AddHandlerStatement : HandlerStatement
+{
+ ///
+ /// Constructs a new parse tree for an AddHandler statement.
+ ///
+ /// The name of the event.
+ /// The location of the ','.
+ /// The delegate expression.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public AddHandlerStatement(Expression name, Location commaLocation, Expression delegateExpression, Span span, IList comments)
+ : base(TreeType.AddHandlerStatement, name, commaLocation, delegateExpression, span, comments)
+ {
+ }
+}
diff --git a/AspClassic.Parser/AddressOfExpression.cs b/AspClassic.Parser/AddressOfExpression.cs
new file mode 100644
index 0000000..c4550ca
--- /dev/null
+++ b/AspClassic.Parser/AddressOfExpression.cs
@@ -0,0 +1,17 @@
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an AddressOf expression.
+///
+public sealed class AddressOfExpression : UnaryExpression
+{
+ ///
+ /// Constructs a new AddressOf expression parse tree.
+ ///
+ /// The operand of AddressOf.
+ /// The location of the parse tree.
+ public AddressOfExpression(Expression operand, Span span)
+ : base(TreeType.AddressOfExpression, operand, span)
+ {
+ }
+}
diff --git a/AspClassic.Parser/AggregateInitializer.cs b/AspClassic.Parser/AggregateInitializer.cs
new file mode 100644
index 0000000..6401909
--- /dev/null
+++ b/AspClassic.Parser/AggregateInitializer.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an aggregate initializer.
+///
+public sealed class AggregateInitializer : Initializer
+{
+ private readonly InitializerCollection _Elements;
+
+ ///
+ /// The elements of the aggregate initializer.
+ ///
+ public InitializerCollection Elements => _Elements;
+
+ ///
+ /// Constructs a new aggregate initializer parse tree.
+ ///
+ /// The elements of the aggregate initializer.
+ /// The location of the parse tree.
+ public AggregateInitializer(InitializerCollection elements, Span span)
+ : base(TreeType.AggregateInitializer, span)
+ {
+ if (elements == null)
+ {
+ throw new ArgumentNullException("elements");
+ }
+ SetParent(elements);
+ _Elements = elements;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Elements);
+ }
+}
diff --git a/AspClassic.Parser/AliasImport.cs b/AspClassic.Parser/AliasImport.cs
new file mode 100644
index 0000000..f01c296
--- /dev/null
+++ b/AspClassic.Parser/AliasImport.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an Imports statement that aliases a type or namespace.
+///
+public sealed class AliasImport : Import
+{
+ private readonly SimpleName _Name;
+
+ private readonly Location _EqualsLocation;
+
+ private readonly TypeName _AliasedTypeName;
+
+ ///
+ /// The alias name.
+ ///
+ public SimpleName Name => _Name;
+
+ ///
+ /// The location of the '='.
+ ///
+ public Location EqualsLocation => _EqualsLocation;
+
+ ///
+ /// The name being aliased.
+ ///
+ public TypeName AliasedTypeName => _AliasedTypeName;
+
+ ///
+ /// Constructs a new aliased import parse tree.
+ ///
+ /// The name of the alias.
+ /// The location of the '='.
+ /// The name being aliased.
+ /// The location of the parse tree.
+ public AliasImport(SimpleName name, Location equalsLocation, TypeName aliasedTypeName, Span span)
+ : base(TreeType.AliasImport, span)
+ {
+ if (aliasedTypeName == null)
+ {
+ throw new ArgumentNullException("aliasedTypeName");
+ }
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+ SetParent(name);
+ SetParent(aliasedTypeName);
+ _Name = name;
+ _EqualsLocation = equalsLocation;
+ _AliasedTypeName = aliasedTypeName;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, AliasedTypeName);
+ }
+}
diff --git a/AspClassic.Parser/Argument.cs b/AspClassic.Parser/Argument.cs
new file mode 100644
index 0000000..529b6cd
--- /dev/null
+++ b/AspClassic.Parser/Argument.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an argument to a call or index.
+///
+public sealed class Argument : Tree
+{
+ private readonly SimpleName _Name;
+
+ private readonly Location _ColonEqualsLocation;
+
+ private readonly Expression _Expression;
+
+ ///
+ /// The name of the argument, if any.
+ ///
+ public SimpleName Name => _Name;
+
+ ///
+ /// The location of the ':=', if any.
+ ///
+ public Location ColonEqualsLocation => _ColonEqualsLocation;
+
+ ///
+ /// The argument, if any.
+ ///
+ public Expression Expression => _Expression;
+
+ ///
+ /// Constructs a new parse tree for an argument.
+ ///
+ /// The name of the argument, if any.
+ /// The location of the ':=', if any.
+ /// The expression, if any.
+ /// The location of the parse tree.
+ public Argument(SimpleName name, Location colonEqualsLocation, Expression expression, Span span)
+ : base(TreeType.Argument, span)
+ {
+ if (expression == null)
+ {
+ throw new ArgumentNullException("expression");
+ }
+ SetParent(name);
+ SetParent(expression);
+ _Name = name;
+ _ColonEqualsLocation = colonEqualsLocation;
+ _Expression = expression;
+ }
+
+ private Argument()
+ : base(TreeType.Argument, default(Span))
+ {
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Name);
+ Tree.AddChild(childList, Expression);
+ }
+}
diff --git a/AspClassic.Parser/ArgumentCollection.cs b/AspClassic.Parser/ArgumentCollection.cs
new file mode 100644
index 0000000..19832f3
--- /dev/null
+++ b/AspClassic.Parser/ArgumentCollection.cs
@@ -0,0 +1,29 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A read-only collection of arguments.
+///
+public sealed class ArgumentCollection : CommaDelimitedTreeCollection
+{
+ private readonly Location _RightParenthesisLocation;
+
+ ///
+ /// The location of the ')'.
+ ///
+ public Location RightParenthesisLocation => _RightParenthesisLocation;
+
+ ///
+ /// Constructs a new argument collection.
+ ///
+ /// The arguments in the collection.
+ /// The location of the commas in the collection.
+ /// The location of the ')'.
+ /// The location of the parse tree.
+ public ArgumentCollection(IList arguments, IList commaLocations, Location rightParenthesisLocation, Span span)
+ : base(TreeType.ArgumentCollection, arguments, commaLocations, span)
+ {
+ _RightParenthesisLocation = rightParenthesisLocation;
+ }
+}
diff --git a/AspClassic.Parser/ArrayTypeName.cs b/AspClassic.Parser/ArrayTypeName.cs
new file mode 100644
index 0000000..54c6a2c
--- /dev/null
+++ b/AspClassic.Parser/ArrayTypeName.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an array type name.
+///
+///
+/// This tree may contain size arguments as well.
+///
+public sealed class ArrayTypeName : TypeName
+{
+ private readonly TypeName _ElementTypeName;
+
+ private readonly int _Rank;
+
+ private readonly ArgumentCollection _Arguments;
+
+ ///
+ /// The type name for the element type of the array.
+ ///
+ public TypeName ElementTypeName => _ElementTypeName;
+
+ ///
+ /// The rank of the array type name.
+ ///
+ public int Rank => _Rank;
+
+ ///
+ /// The arguments of the array type name, if any.
+ ///
+ public ArgumentCollection Arguments => _Arguments;
+
+ ///
+ /// Constructs a new parse tree for an array type name.
+ ///
+ /// The type name for the array element type.
+ /// The rank of the array type name.
+ /// The arguments of the array type name, if any.
+ /// The location of the parse tree.
+ public ArrayTypeName(TypeName elementTypeName, int rank, ArgumentCollection arguments, Span span)
+ : base(TreeType.ArrayType, span)
+ {
+ if (arguments == null)
+ {
+ throw new ArgumentNullException("arguments");
+ }
+ SetParent(elementTypeName);
+ SetParent(arguments);
+ _ElementTypeName = elementTypeName;
+ _Rank = rank;
+ _Arguments = arguments;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, ElementTypeName);
+ Tree.AddChild(childList, Arguments);
+ }
+}
diff --git a/AspClassic.Parser/AspClassic.Parser.csproj b/AspClassic.Parser/AspClassic.Parser.csproj
new file mode 100644
index 0000000..132c02c
--- /dev/null
+++ b/AspClassic.Parser/AspClassic.Parser.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
diff --git a/AspClassic.Parser/AssignmentStatement.cs b/AspClassic.Parser/AssignmentStatement.cs
new file mode 100644
index 0000000..05e5fdf
--- /dev/null
+++ b/AspClassic.Parser/AssignmentStatement.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an assignment statement.
+///
+public sealed class AssignmentStatement : Statement
+{
+ private readonly Expression _TargetExpression;
+
+ private readonly Location _OperatorLocation;
+
+ private readonly Expression _SourceExpression;
+
+ private readonly bool _IsSetStatement;
+
+ ///
+ /// The target of the assignment.
+ ///
+ public Expression TargetExpression => _TargetExpression;
+
+ ///
+ /// The location of the operator.
+ ///
+ public Location OperatorLocation => _OperatorLocation;
+
+ ///
+ /// The source of the assignment.
+ ///
+ public Expression SourceExpression => _SourceExpression;
+
+ public bool IsSetStatement => _IsSetStatement;
+
+ ///
+ /// Constructs a new parse tree for an assignment statement.
+ ///
+ /// The target of the assignment.
+ /// The location of the operator.
+ /// The source of the assignment.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ /// Whether is is a set statement
+ public AssignmentStatement(Expression targetExpression, Location operatorLocation, Expression sourceExpression, Span span, IList comments, bool isSetStatement)
+ : base(TreeType.AssignmentStatement, span, comments)
+ {
+ if (targetExpression == null)
+ {
+ throw new ArgumentNullException("targetExpression");
+ }
+ if (sourceExpression == null)
+ {
+ throw new ArgumentNullException("sourceExpression");
+ }
+ SetParent(targetExpression);
+ SetParent(sourceExpression);
+ _TargetExpression = targetExpression;
+ _OperatorLocation = operatorLocation;
+ _SourceExpression = sourceExpression;
+ _IsSetStatement = isSetStatement;
+ }
+
+ ///
+ /// Constructs a new parse tree for an assignment statement.
+ ///
+ /// The target of the assignment.
+ /// The location of the operator.
+ /// The source of the assignment.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public AssignmentStatement(Expression targetExpression, Location operatorLocation, Expression sourceExpression, Span span, IList comments)
+ : this(targetExpression, operatorLocation, sourceExpression, span, comments, isSetStatement: false)
+ {
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, TargetExpression);
+ Tree.AddChild(childList, SourceExpression);
+ }
+}
diff --git a/AspClassic.Parser/Attribute.cs b/AspClassic.Parser/Attribute.cs
new file mode 100644
index 0000000..6137909
--- /dev/null
+++ b/AspClassic.Parser/Attribute.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an attribute usage.
+///
+public sealed class Attribute : Tree
+{
+ private readonly AttributeTypes _AttributeType;
+
+ private readonly Location _AttributeTypeLocation;
+
+ private readonly Location _ColonLocation;
+
+ private readonly Name _Name;
+
+ private readonly ArgumentCollection _Arguments;
+
+ ///
+ /// The target type of the attribute.
+ ///
+ public AttributeTypes AttributeType => _AttributeType;
+
+ ///
+ /// The location of the attribute type, if any.
+ ///
+ public Location AttributeTypeLocation => _AttributeTypeLocation;
+
+ ///
+ /// The location of the ':', if any.
+ ///
+ public Location ColonLocation => _ColonLocation;
+
+ ///
+ /// The name of the attribute being applied.
+ ///
+ public Name Name => _Name;
+
+ ///
+ /// The arguments to the attribute.
+ ///
+ public ArgumentCollection Arguments => _Arguments;
+
+ ///
+ /// Constructs a new attribute parse tree.
+ ///
+ /// The target type of the attribute.
+ /// The location of the attribute type.
+ /// The location of the ':'.
+ /// The name of the attribute being applied.
+ /// The arguments to the attribute.
+ /// The location of the parse tree.
+ public Attribute(AttributeTypes attributeType, Location attributeTypeLocation, Location colonLocation, Name name, ArgumentCollection arguments, Span span)
+ : base(TreeType.Attribute, span)
+ {
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+ SetParent(name);
+ SetParent(arguments);
+ _AttributeType = attributeType;
+ _AttributeTypeLocation = attributeTypeLocation;
+ _ColonLocation = colonLocation;
+ _Name = name;
+ _Arguments = arguments;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Name);
+ Tree.AddChild(childList, Arguments);
+ }
+}
diff --git a/AspClassic.Parser/AttributeBlockCollection.cs b/AspClassic.Parser/AttributeBlockCollection.cs
new file mode 100644
index 0000000..b9a16ec
--- /dev/null
+++ b/AspClassic.Parser/AttributeBlockCollection.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A read-only collection of attributes.
+///
+public sealed class AttributeBlockCollection : TreeCollection
+{
+ ///
+ /// Constructs a new collection of attribute blocks.
+ ///
+ /// The attribute blockss in the collection.
+ /// The location of the parse tree.
+ public AttributeBlockCollection(IList attributeBlocks, Span span)
+ : base(TreeType.AttributeBlockCollection, attributeBlocks, span)
+ {
+ if (attributeBlocks == null || attributeBlocks.Count == 0)
+ {
+ throw new ArgumentException("AttributeBlocksCollection cannot be empty.");
+ }
+ }
+}
diff --git a/AspClassic.Parser/AttributeCollection.cs b/AspClassic.Parser/AttributeCollection.cs
new file mode 100644
index 0000000..0c8fc73
--- /dev/null
+++ b/AspClassic.Parser/AttributeCollection.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A read-only collection of attributes.
+///
+public sealed class AttributeCollection : CommaDelimitedTreeCollection
+{
+ private readonly Location _RightBracketLocation;
+
+ ///
+ /// The location of the '}'.
+ ///
+ public Location RightBracketLocation => _RightBracketLocation;
+
+ ///
+ /// Constructs a new collection of attributes.
+ ///
+ /// The attributes in the collection.
+ /// The location of the commas in the list.
+ /// The location of the right bracket.
+ /// The location of the parse tree.
+ public AttributeCollection(IList attributes, IList commaLocations, Location rightBracketLocation, Span span)
+ : base(TreeType.AttributeCollection, attributes, commaLocations, span)
+ {
+ if (attributes == null || attributes.Count == 0)
+ {
+ throw new ArgumentException("AttributeCollection cannot be empty.");
+ }
+ _RightBracketLocation = rightBracketLocation;
+ }
+}
diff --git a/AspClassic.Parser/AttributeDeclaration.cs b/AspClassic.Parser/AttributeDeclaration.cs
new file mode 100644
index 0000000..e7025fe
--- /dev/null
+++ b/AspClassic.Parser/AttributeDeclaration.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an assembly-level or module-level attribute declaration.
+///
+public sealed class AttributeDeclaration : Declaration
+{
+ private readonly AttributeBlockCollection _Attributes;
+
+ ///
+ /// The attributes.
+ ///
+ public AttributeBlockCollection Attributes => _Attributes;
+
+ ///
+ /// Constructs a new parse tree for assembly-level or module-level attribute declarations.
+ ///
+ /// The attributes.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public AttributeDeclaration(AttributeBlockCollection attributes, Span span, IList comments)
+ : base(TreeType.AttributeDeclaration, span, comments)
+ {
+ if (attributes == null)
+ {
+ throw new ArgumentNullException("attributes");
+ }
+ SetParent(attributes);
+ _Attributes = attributes;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Attributes);
+ }
+}
diff --git a/AspClassic.Parser/AttributeTypes.cs b/AspClassic.Parser/AttributeTypes.cs
new file mode 100644
index 0000000..b74a065
--- /dev/null
+++ b/AspClassic.Parser/AttributeTypes.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace AspClassic.Parser;
+
+///
+/// The type of an attribute usage.
+///
+[Flags]
+public enum AttributeTypes
+{
+ /// Regular application.
+ Regular = 1,
+ /// Applied to the netmodule.
+ Module = 2,
+ /// Applied to the assembly.
+ Assembly = 4
+}
diff --git a/AspClassic.Parser/BinaryOperatorExpression.cs b/AspClassic.Parser/BinaryOperatorExpression.cs
new file mode 100644
index 0000000..813c7fc
--- /dev/null
+++ b/AspClassic.Parser/BinaryOperatorExpression.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a binary operator expression.
+///
+public sealed class BinaryOperatorExpression : Expression
+{
+ private readonly Expression _LeftOperand;
+
+ private readonly OperatorType _Operator;
+
+ private readonly Location _OperatorLocation;
+
+ private readonly Expression _RightOperand;
+
+ ///
+ /// The left operand expression.
+ ///
+ public Expression LeftOperand => _LeftOperand;
+
+ ///
+ /// The operator.
+ ///
+ public OperatorType Operator => _Operator;
+
+ ///
+ /// The location of the operator.
+ ///
+ public Location OperatorLocation => _OperatorLocation;
+
+ ///
+ /// The right operand expression.
+ ///
+ public Expression RightOperand => _RightOperand;
+
+ public override bool IsConstant => LeftOperand.IsConstant && RightOperand.IsConstant;
+
+ ///
+ /// Constructs a new parse tree for a binary operation.
+ ///
+ /// The left operand expression.
+ /// The operator.
+ /// The location of the operator.
+ /// The right operand expression.
+ /// The location of the parse tree.
+ public BinaryOperatorExpression(Expression leftOperand, OperatorType @operator, Location operatorLocation, Expression rightOperand, Span span)
+ : base(TreeType.BinaryOperatorExpression, span)
+ {
+ if (@operator < OperatorType.Plus || @operator > OperatorType.GreaterThanEquals)
+ {
+ throw new ArgumentOutOfRangeException("operator");
+ }
+ if (leftOperand == null)
+ {
+ throw new ArgumentNullException("leftOperand");
+ }
+ if (rightOperand == null)
+ {
+ throw new ArgumentNullException("rightOperand");
+ }
+ SetParent(leftOperand);
+ SetParent(rightOperand);
+ _LeftOperand = leftOperand;
+ _Operator = @operator;
+ _OperatorLocation = operatorLocation;
+ _RightOperand = rightOperand;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, LeftOperand);
+ Tree.AddChild(childList, RightOperand);
+ }
+}
diff --git a/AspClassic.Parser/BlockDeclaration.cs b/AspClassic.Parser/BlockDeclaration.cs
new file mode 100644
index 0000000..e81e34d
--- /dev/null
+++ b/AspClassic.Parser/BlockDeclaration.cs
@@ -0,0 +1,65 @@
+#define DEBUG
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a block declaration.
+///
+public abstract class BlockDeclaration : ModifiedDeclaration
+{
+ private readonly Location _KeywordLocation;
+
+ private readonly SimpleName _Name;
+
+ private readonly DeclarationCollection _Declarations;
+
+ private readonly EndBlockDeclaration _EndDeclaration;
+
+ ///
+ /// The location of the keyword.
+ ///
+ public Location KeywordLocation => _KeywordLocation;
+
+ ///
+ /// The name of the declaration.
+ ///
+ public SimpleName Name => _Name;
+
+ ///
+ /// The declarations in the block.
+ ///
+ public DeclarationCollection Declarations => _Declarations;
+
+ ///
+ /// The End statement for the block.
+ ///
+ public EndBlockDeclaration EndDeclaration => _EndDeclaration;
+
+ protected BlockDeclaration(TreeType type, AttributeBlockCollection attributes, ModifierCollection modifiers, Location keywordLocation, SimpleName name, DeclarationCollection declarations, EndBlockDeclaration endDeclaration, Span span, IList comments)
+ : base(type, attributes, modifiers, span, comments)
+ {
+ Debug.Assert(type == TreeType.ClassDeclaration || type == TreeType.ModuleDeclaration || type == TreeType.InterfaceDeclaration || type == TreeType.StructureDeclaration || type == TreeType.EnumDeclaration);
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+ SetParent(name);
+ SetParent(declarations);
+ SetParent(endDeclaration);
+ _KeywordLocation = keywordLocation;
+ _Name = name;
+ _Declarations = declarations;
+ _EndDeclaration = endDeclaration;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, Name);
+ Tree.AddChild(childList, Declarations);
+ Tree.AddChild(childList, EndDeclaration);
+ }
+}
diff --git a/AspClassic.Parser/BlockStatement.cs b/AspClassic.Parser/BlockStatement.cs
new file mode 100644
index 0000000..efdfb72
--- /dev/null
+++ b/AspClassic.Parser/BlockStatement.cs
@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a block statement.
+///
+public abstract class BlockStatement : Statement
+{
+ private readonly StatementCollection _Statements;
+
+ ///
+ /// The statements in the block.
+ ///
+ public StatementCollection Statements => _Statements;
+
+ protected BlockStatement(TreeType type, StatementCollection statements, Span span, IList comments)
+ : base(type, span, comments)
+ {
+ _Statements = statements;
+ SetParent(statements);
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Statements);
+ }
+}
diff --git a/AspClassic.Parser/BlockType.cs b/AspClassic.Parser/BlockType.cs
new file mode 100644
index 0000000..13efa2f
--- /dev/null
+++ b/AspClassic.Parser/BlockType.cs
@@ -0,0 +1,34 @@
+namespace AspClassic.Parser;
+
+///
+/// The type a block declaration.
+///
+public enum BlockType
+{
+ None,
+ Do,
+ For,
+ While,
+ Select,
+ If,
+ Try,
+ SyncLock,
+ Using,
+ With,
+ Sub,
+ Function,
+ Operator,
+ Event,
+ AddHandler,
+ RemoveHandler,
+ RaiseEvent,
+ Get,
+ Set,
+ Property,
+ Class,
+ Structure,
+ Module,
+ Interface,
+ Enum,
+ Namespace
+}
diff --git a/AspClassic.Parser/BooleanLiteralExpression.cs b/AspClassic.Parser/BooleanLiteralExpression.cs
new file mode 100644
index 0000000..596b4bc
--- /dev/null
+++ b/AspClassic.Parser/BooleanLiteralExpression.cs
@@ -0,0 +1,27 @@
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a Boolean literal expression.
+///
+public sealed class BooleanLiteralExpression : LiteralExpression
+{
+ private readonly bool _Literal;
+
+ ///
+ /// The literal value.
+ ///
+ public bool Literal => _Literal;
+
+ public override object Value => _Literal;
+
+ ///
+ /// Constructs a new parse tree for a Boolean literal expression.
+ ///
+ /// The literal value.
+ /// The location of the parse tree.
+ public BooleanLiteralExpression(bool literal, Span span)
+ : base(TreeType.BooleanLiteralExpression, span)
+ {
+ _Literal = literal;
+ }
+}
diff --git a/AspClassic.Parser/CTypeExpression.cs b/AspClassic.Parser/CTypeExpression.cs
new file mode 100644
index 0000000..f7247f1
--- /dev/null
+++ b/AspClassic.Parser/CTypeExpression.cs
@@ -0,0 +1,21 @@
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a CType expression.
+///
+public sealed class CTypeExpression : CastTypeExpression
+{
+ ///
+ /// Constructs a new parse tree for a CType expression.
+ ///
+ /// The location of the '('.
+ /// The expression to be converted.
+ /// The location of the ','.
+ /// The target type of the conversion.
+ /// The location of the ')'.
+ /// The location of the parse tree.
+ public CTypeExpression(Location leftParenthesisLocation, Expression operand, Location commaLocation, TypeName target, Location rightParenthesisLocation, Span span)
+ : base(TreeType.CTypeExpression, leftParenthesisLocation, operand, commaLocation, target, rightParenthesisLocation, span)
+ {
+ }
+}
diff --git a/AspClassic.Parser/CallOrIndexExpression.cs b/AspClassic.Parser/CallOrIndexExpression.cs
new file mode 100644
index 0000000..95131d3
--- /dev/null
+++ b/AspClassic.Parser/CallOrIndexExpression.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a call or index expression.
+///
+public sealed class CallOrIndexExpression : Expression
+{
+ private readonly Expression _TargetExpression;
+
+ private readonly ArgumentCollection _Arguments;
+
+ ///
+ /// The target of the call or index.
+ ///
+ public Expression TargetExpression => _TargetExpression;
+
+ ///
+ /// The arguments to the call or index.
+ ///
+ public ArgumentCollection Arguments => _Arguments;
+
+ ///
+ /// Constructs a new parse tree for a call or index expression.
+ ///
+ /// The target of the call or index.
+ /// The arguments to the call or index.
+ /// The location of the parse tree.
+ public CallOrIndexExpression(Expression targetExpression, ArgumentCollection arguments, Span span)
+ : base(TreeType.CallOrIndexExpression, span)
+ {
+ if (targetExpression == null)
+ {
+ throw new ArgumentNullException("targetExpression");
+ }
+ SetParent(targetExpression);
+ SetParent(arguments);
+ _TargetExpression = targetExpression;
+ _Arguments = arguments;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, TargetExpression);
+ Tree.AddChild(childList, Arguments);
+ }
+}
diff --git a/AspClassic.Parser/CallStatement.cs b/AspClassic.Parser/CallStatement.cs
new file mode 100644
index 0000000..855d68b
--- /dev/null
+++ b/AspClassic.Parser/CallStatement.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a method call statement.
+///
+public sealed class CallStatement : Statement
+{
+ private readonly Location _CallLocation;
+
+ private readonly Expression _TargetExpression;
+
+ private readonly ArgumentCollection _Arguments;
+
+ ///
+ /// The location of the 'Call', if any.
+ ///
+ public Location CallLocation => _CallLocation;
+
+ ///
+ /// The target of the call.
+ ///
+ public Expression TargetExpression => _TargetExpression;
+
+ ///
+ /// The arguments to the call.
+ ///
+ public ArgumentCollection Arguments => _Arguments;
+
+ ///
+ /// Constructs a new parse tree for a method call statement.
+ ///
+ /// The location of the 'Call', if any.
+ /// The target of the call.
+ /// The arguments to the call.
+ /// The location of the parse tree.
+ /// The comments of the parse tree.
+ public CallStatement(Location callLocation, Expression targetExpression, ArgumentCollection arguments, Span span, IList comments)
+ : base(TreeType.CallStatement, span, comments)
+ {
+ if (targetExpression == null)
+ {
+ throw new ArgumentNullException("targetExpression");
+ }
+ SetParent(targetExpression);
+ SetParent(arguments);
+ _CallLocation = callLocation;
+ _TargetExpression = targetExpression;
+ _Arguments = arguments;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, TargetExpression);
+ Tree.AddChild(childList, Arguments);
+ }
+}
diff --git a/AspClassic.Parser/CaseBlockStatement.cs b/AspClassic.Parser/CaseBlockStatement.cs
new file mode 100644
index 0000000..4616a20
--- /dev/null
+++ b/AspClassic.Parser/CaseBlockStatement.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for the block of a Case statement.
+///
+public sealed class CaseBlockStatement : BlockStatement
+{
+ private readonly CaseStatement _CaseStatement;
+
+ ///
+ /// The Case statement that started the block.
+ ///
+ public CaseStatement CaseStatement => _CaseStatement;
+
+ ///
+ /// Constructs a new parse tree for the block of a Case statement.
+ ///
+ /// The Case statement that started the block.
+ /// The statements in the block.
+ /// The location of the parse tree.
+ /// The comments of the tree.
+ public CaseBlockStatement(CaseStatement caseStatement, StatementCollection statements, Span span, IList comments)
+ : base(TreeType.CaseBlockStatement, statements, span, comments)
+ {
+ if (caseStatement == null)
+ {
+ throw new ArgumentNullException("caseStatement");
+ }
+ SetParent(caseStatement);
+ _CaseStatement = caseStatement;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, CaseStatement);
+ base.GetChildTrees(childList);
+ }
+}
diff --git a/AspClassic.Parser/CaseClause.cs b/AspClassic.Parser/CaseClause.cs
new file mode 100644
index 0000000..d0eeeb9
--- /dev/null
+++ b/AspClassic.Parser/CaseClause.cs
@@ -0,0 +1,16 @@
+#define DEBUG
+using System.Diagnostics;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a case clause in a Select statement.
+///
+public abstract class CaseClause : Tree
+{
+ protected CaseClause(TreeType type, Span span)
+ : base(type, span)
+ {
+ Debug.Assert(type == TreeType.ComparisonCaseClause || type == TreeType.RangeCaseClause);
+ }
+}
diff --git a/AspClassic.Parser/CaseClauseCollection.cs b/AspClassic.Parser/CaseClauseCollection.cs
new file mode 100644
index 0000000..4a760cb
--- /dev/null
+++ b/AspClassic.Parser/CaseClauseCollection.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A collection of case clauses.
+///
+public sealed class CaseClauseCollection : CommaDelimitedTreeCollection
+{
+ ///
+ /// Constructs a new collection of case clauses.
+ ///
+ /// The case clauses in the collection.
+ /// The locations of the commas in the list.
+ /// The location of the parse tree.
+ public CaseClauseCollection(IList caseClauses, IList commaLocations, Span span)
+ : base(TreeType.CaseClauseCollection, caseClauses, commaLocations, span)
+ {
+ if (caseClauses == null || caseClauses.Count == 0)
+ {
+ throw new ArgumentException("CaseClauseCollection cannot be empty.");
+ }
+ }
+}
diff --git a/AspClassic.Parser/CaseElseBlockStatement.cs b/AspClassic.Parser/CaseElseBlockStatement.cs
new file mode 100644
index 0000000..07b9a51
--- /dev/null
+++ b/AspClassic.Parser/CaseElseBlockStatement.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for the block of a Case Else statement.
+///
+public sealed class CaseElseBlockStatement : BlockStatement
+{
+ private readonly CaseElseStatement _CaseElseStatement;
+
+ ///
+ /// The Case Else statement that started the block.
+ ///
+ public CaseElseStatement CaseElseStatement => _CaseElseStatement;
+
+ ///
+ /// Constructs a new parse tree for the block of a Case Else statement.
+ ///
+ /// The Case Else statement that started the block.
+ /// The statements in the block.
+ /// The location of the parse tree.
+ /// The comments of the tree.
+ public CaseElseBlockStatement(CaseElseStatement caseElseStatement, StatementCollection statements, Span span, IList comments)
+ : base(TreeType.CaseElseBlockStatement, statements, span, comments)
+ {
+ if (caseElseStatement == null)
+ {
+ throw new ArgumentNullException("caseElseStatement");
+ }
+ SetParent(caseElseStatement);
+ _CaseElseStatement = caseElseStatement;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, CaseElseStatement);
+ base.GetChildTrees(childList);
+ }
+}
diff --git a/AspClassic.Parser/CaseElseStatement.cs b/AspClassic.Parser/CaseElseStatement.cs
new file mode 100644
index 0000000..01a9ba1
--- /dev/null
+++ b/AspClassic.Parser/CaseElseStatement.cs
@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a Case Else statement.
+///
+public sealed class CaseElseStatement : Statement
+{
+ private readonly Location _ElseLocation;
+
+ ///
+ /// The location of the 'Else'.
+ ///
+ public Location ElseLocation => _ElseLocation;
+
+ ///
+ /// Constructs a new parse tree for a Case Else statement.
+ ///
+ /// The location of the 'Else'.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public CaseElseStatement(Location elseLocation, Span span, IList comments)
+ : base(TreeType.CaseElseStatement, span, comments)
+ {
+ _ElseLocation = elseLocation;
+ }
+}
diff --git a/AspClassic.Parser/CaseStatement.cs b/AspClassic.Parser/CaseStatement.cs
new file mode 100644
index 0000000..9d8e4a1
--- /dev/null
+++ b/AspClassic.Parser/CaseStatement.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a Case statement.
+///
+public sealed class CaseStatement : Statement
+{
+ private readonly CaseClauseCollection _CaseClauses;
+
+ ///
+ /// The clauses in the Case statement.
+ ///
+ public CaseClauseCollection CaseClauses => _CaseClauses;
+
+ ///
+ /// Constructs a new parse tree for a Case statement.
+ ///
+ /// The clauses in the Case statement.
+ /// The location of the parse tree.
+ /// The comments on the parse tree.
+ public CaseStatement(CaseClauseCollection caseClauses, Span span, IList comments)
+ : base(TreeType.CaseStatement, span, comments)
+ {
+ if (caseClauses == null)
+ {
+ throw new ArgumentNullException("caseClauses");
+ }
+ SetParent(caseClauses);
+ _CaseClauses = caseClauses;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, CaseClauses);
+ }
+}
diff --git a/AspClassic.Parser/CastTypeExpression.cs b/AspClassic.Parser/CastTypeExpression.cs
new file mode 100644
index 0000000..af84246
--- /dev/null
+++ b/AspClassic.Parser/CastTypeExpression.cs
@@ -0,0 +1,61 @@
+#define DEBUG
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a CType or DirectCast expression.
+///
+public abstract class CastTypeExpression : UnaryExpression
+{
+ private readonly Location _LeftParenthesisLocation;
+
+ private readonly Location _CommaLocation;
+
+ private readonly TypeName _Target;
+
+ private readonly Location _RightParenthesisLocation;
+
+ ///
+ /// The location of the '('.
+ ///
+ public Location LeftParenthesisLocation => _LeftParenthesisLocation;
+
+ ///
+ /// The location of the ','.
+ ///
+ public Location CommaLocation => _CommaLocation;
+
+ ///
+ /// The target type for the operand.
+ ///
+ public TypeName Target => _Target;
+
+ ///
+ /// The location of the ')'.
+ ///
+ public Location RightParenthesisLocation => _RightParenthesisLocation;
+
+ protected CastTypeExpression(TreeType type, Location leftParenthesisLocation, Expression operand, Location commaLocation, TypeName target, Location rightParenthesisLocation, Span span)
+ : base(type, operand, span)
+ {
+ Debug.Assert(type == TreeType.CTypeExpression || type == TreeType.DirectCastExpression || type == TreeType.TryCastExpression);
+ if (target == null)
+ {
+ throw new ArgumentNullException("target");
+ }
+ SetParent(target);
+ _Target = target;
+ _LeftParenthesisLocation = leftParenthesisLocation;
+ _CommaLocation = commaLocation;
+ _RightParenthesisLocation = rightParenthesisLocation;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, Target);
+ }
+}
diff --git a/AspClassic.Parser/CatchBlockStatement.cs b/AspClassic.Parser/CatchBlockStatement.cs
new file mode 100644
index 0000000..7f35e44
--- /dev/null
+++ b/AspClassic.Parser/CatchBlockStatement.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a Catch block statement.
+///
+public sealed class CatchBlockStatement : BlockStatement
+{
+ private readonly CatchStatement _CatchStatement;
+
+ ///
+ /// The Catch statement.
+ ///
+ public CatchStatement CatchStatement => _CatchStatement;
+
+ ///
+ /// Constructs a new parse tree for a Catch block statement.
+ ///
+ /// The Catch statement.
+ /// The statements in the block.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public CatchBlockStatement(CatchStatement catchStatement, StatementCollection statements, Span span, IList comments)
+ : base(TreeType.CatchBlockStatement, statements, span, comments)
+ {
+ if (catchStatement == null)
+ {
+ throw new ArgumentNullException("catchStatement");
+ }
+ SetParent(catchStatement);
+ _CatchStatement = catchStatement;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, CatchStatement);
+ base.GetChildTrees(childList);
+ }
+}
diff --git a/AspClassic.Parser/CatchStatement.cs b/AspClassic.Parser/CatchStatement.cs
new file mode 100644
index 0000000..6bd0358
--- /dev/null
+++ b/AspClassic.Parser/CatchStatement.cs
@@ -0,0 +1,74 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a Catch statement.
+///
+public sealed class CatchStatement : Statement
+{
+ private readonly SimpleName _Name;
+
+ private readonly Location _AsLocation;
+
+ private readonly TypeName _ExceptionType;
+
+ private readonly Location _WhenLocation;
+
+ private readonly Expression _FilterExpression;
+
+ ///
+ /// The name of the catch variable, if any.
+ ///
+ public SimpleName Name => _Name;
+
+ ///
+ /// The location of the 'As', if any.
+ ///
+ public Location AsLocation => _AsLocation;
+
+ ///
+ /// The type of the catch variable, if any.
+ ///
+ public TypeName ExceptionType => _ExceptionType;
+
+ ///
+ /// The location of the 'When', if any.
+ ///
+ public Location WhenLocation => _WhenLocation;
+
+ ///
+ /// The filter expression, if any.
+ ///
+ public Expression FilterExpression => _FilterExpression;
+
+ ///
+ /// Constructs a new parse tree for a Catch statement.
+ ///
+ /// The name of the catch variable, if any.
+ /// The location of the 'As', if any.
+ /// The type of the catch variable, if any.
+ /// The location of the 'When', if any.
+ /// The filter expression, if any.
+ /// The location of the parse tree, if any.
+ /// The comments for the parse tree, if any.
+ public CatchStatement(SimpleName name, Location asLocation, TypeName exceptionType, Location whenLocation, Expression filterExpression, Span span, IList comments)
+ : base(TreeType.CatchStatement, span, comments)
+ {
+ SetParent(name);
+ SetParent(exceptionType);
+ SetParent(filterExpression);
+ _Name = name;
+ _AsLocation = asLocation;
+ _ExceptionType = exceptionType;
+ _WhenLocation = whenLocation;
+ _FilterExpression = filterExpression;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Name);
+ Tree.AddChild(childList, ExceptionType);
+ Tree.AddChild(childList, FilterExpression);
+ }
+}
diff --git a/AspClassic.Parser/CharacterLiteralExpression.cs b/AspClassic.Parser/CharacterLiteralExpression.cs
new file mode 100644
index 0000000..ddacf1f
--- /dev/null
+++ b/AspClassic.Parser/CharacterLiteralExpression.cs
@@ -0,0 +1,27 @@
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a character literal expression.
+///
+public sealed class CharacterLiteralExpression : LiteralExpression
+{
+ private readonly char _Literal;
+
+ ///
+ /// The literal value.
+ ///
+ public char Literal => _Literal;
+
+ public override object Value => _Literal;
+
+ ///
+ /// Constructs a new parse tree for a character literal expression.
+ ///
+ /// The literal value.
+ /// The location of the parse tree.
+ public CharacterLiteralExpression(char literal, Span span)
+ : base(TreeType.CharacterLiteralExpression, span)
+ {
+ _Literal = literal;
+ }
+}
diff --git a/AspClassic.Parser/CharacterLiteralToken.cs b/AspClassic.Parser/CharacterLiteralToken.cs
new file mode 100644
index 0000000..fa1b823
--- /dev/null
+++ b/AspClassic.Parser/CharacterLiteralToken.cs
@@ -0,0 +1,25 @@
+namespace AspClassic.Parser;
+
+///
+/// A character literal.
+///
+public sealed class CharacterLiteralToken : Token
+{
+ private readonly char _Literal;
+
+ ///
+ /// The literal value.
+ ///
+ public char Literal => _Literal;
+
+ ///
+ /// Constructs a new character literal token.
+ ///
+ /// The literal value.
+ /// The location of the literal.
+ public CharacterLiteralToken(char literal, Span span)
+ : base(TokenType.CharacterLiteral, span)
+ {
+ _Literal = literal;
+ }
+}
diff --git a/AspClassic.Parser/Charset.cs b/AspClassic.Parser/Charset.cs
new file mode 100644
index 0000000..156aad8
--- /dev/null
+++ b/AspClassic.Parser/Charset.cs
@@ -0,0 +1,11 @@
+namespace AspClassic.Parser;
+
+///
+/// The character set of a Declare statement.
+///
+public enum Charset
+{
+ Ansi,
+ Unicode,
+ Auto
+}
diff --git a/AspClassic.Parser/ClassDeclaration.cs b/AspClassic.Parser/ClassDeclaration.cs
new file mode 100644
index 0000000..5b222e7
--- /dev/null
+++ b/AspClassic.Parser/ClassDeclaration.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a Class declaration.
+///
+public sealed class ClassDeclaration : GenericBlockDeclaration
+{
+ ///
+ /// Constructs a new parse tree for a Class declaration.
+ ///
+ /// The attributes for the parse tree.
+ /// The modifiers for the parse tree.
+ /// The location of the keyword.
+ /// The name of the declaration.
+ /// The type parameters of the type, if any.
+ /// The declarations in the block.
+ /// The end block declaration, if any.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public ClassDeclaration(AttributeBlockCollection attributes, ModifierCollection modifiers, Location keywordLocation, SimpleName name, TypeParameterCollection typeParameters, DeclarationCollection declarations, EndBlockDeclaration endStatement, Span span, IList comments)
+ : base(TreeType.ClassDeclaration, attributes, modifiers, keywordLocation, name, typeParameters, declarations, endStatement, span, comments)
+ {
+ }
+}
diff --git a/AspClassic.Parser/ColonDelimitedTreeCollection.cs b/AspClassic.Parser/ColonDelimitedTreeCollection.cs
new file mode 100644
index 0000000..4308549
--- /dev/null
+++ b/AspClassic.Parser/ColonDelimitedTreeCollection.cs
@@ -0,0 +1,29 @@
+#define DEBUG
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+
+namespace AspClassic.Parser;
+
+///
+/// A collection of trees that are colon delimited.
+///
+public abstract class ColonDelimitedTreeCollection : TreeCollection where T : Tree
+{
+ private readonly ReadOnlyCollection _ColonLocations;
+
+ ///
+ /// The locations of the colons in the collection.
+ ///
+ public ReadOnlyCollection ColonLocations => _ColonLocations;
+
+ protected ColonDelimitedTreeCollection(TreeType type, IList trees, IList colonLocations, Span span)
+ : base(type, trees, span)
+ {
+ Debug.Assert(type == TreeType.StatementCollection || type == TreeType.DeclarationCollection);
+ if (colonLocations != null && colonLocations.Count > 0)
+ {
+ _ColonLocations = new ReadOnlyCollection(colonLocations);
+ }
+ }
+}
diff --git a/AspClassic.Parser/CommaDelimitedTreeCollection.cs b/AspClassic.Parser/CommaDelimitedTreeCollection.cs
new file mode 100644
index 0000000..322c096
--- /dev/null
+++ b/AspClassic.Parser/CommaDelimitedTreeCollection.cs
@@ -0,0 +1,29 @@
+#define DEBUG
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+
+namespace AspClassic.Parser;
+
+///
+/// A collection of trees that are delimited by commas.
+///
+public abstract class CommaDelimitedTreeCollection : TreeCollection where T : Tree
+{
+ private readonly ReadOnlyCollection _CommaLocations;
+
+ ///
+ /// The location of the commas in the list.
+ ///
+ public ReadOnlyCollection CommaLocations => _CommaLocations;
+
+ protected CommaDelimitedTreeCollection(TreeType type, IList trees, IList commaLocations, Span span)
+ : base(type, trees, span)
+ {
+ Debug.Assert(type >= TreeType.ArgumentCollection && type <= TreeType.ImportCollection);
+ if (commaLocations != null && commaLocations.Count > 0)
+ {
+ _CommaLocations = new ReadOnlyCollection(commaLocations);
+ }
+ }
+}
diff --git a/AspClassic.Parser/Comment.cs b/AspClassic.Parser/Comment.cs
new file mode 100644
index 0000000..cabc52d
--- /dev/null
+++ b/AspClassic.Parser/Comment.cs
@@ -0,0 +1,40 @@
+using System;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a comment.
+///
+public sealed class Comment : Tree
+{
+ private readonly string _Comment;
+
+ private readonly bool _IsREM;
+
+ ///
+ /// The text of the comment.
+ ///
+ public string VComment => _Comment;
+
+ ///
+ /// Whether the comment is a REM comment.
+ ///
+ public bool IsREM => _IsREM;
+
+ ///
+ /// Constructs a new comment parse tree.
+ ///
+ /// The text of the comment.
+ /// Whether the comment is a REM comment.
+ /// The location of the parse tree.
+ public Comment(string comment, bool isREM, Span span)
+ : base(TreeType.Comment, span)
+ {
+ if (comment == null)
+ {
+ throw new ArgumentNullException("comment");
+ }
+ _Comment = comment;
+ _IsREM = isREM;
+ }
+}
diff --git a/AspClassic.Parser/CommentToken.cs b/AspClassic.Parser/CommentToken.cs
new file mode 100644
index 0000000..393cf00
--- /dev/null
+++ b/AspClassic.Parser/CommentToken.cs
@@ -0,0 +1,40 @@
+using System;
+
+namespace AspClassic.Parser;
+
+///
+/// A comment token.
+///
+public sealed class CommentToken : Token
+{
+ private readonly bool _IsREM;
+
+ private readonly string _Comment;
+
+ ///
+ /// Whether the comment was preceded by REM.
+ ///
+ public bool IsREM => _IsREM;
+
+ ///
+ /// The text of the comment.
+ ///
+ public string Comment => _Comment;
+
+ ///
+ /// Constructs a new comment token.
+ ///
+ /// The comment value.
+ /// Whether the comment was preceded by REM.
+ /// The location of the comment.
+ public CommentToken(string comment, bool isREM, Span span)
+ : base(TokenType.Comment, span)
+ {
+ if (comment == null)
+ {
+ throw new ArgumentNullException("comment");
+ }
+ _IsREM = isREM;
+ _Comment = comment;
+ }
+}
diff --git a/AspClassic.Parser/ComparisonCaseClause.cs b/AspClassic.Parser/ComparisonCaseClause.cs
new file mode 100644
index 0000000..b58424b
--- /dev/null
+++ b/AspClassic.Parser/ComparisonCaseClause.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a case clause that compares values.
+///
+public sealed class ComparisonCaseClause : CaseClause
+{
+ private readonly Location _IsLocation;
+
+ private readonly OperatorType _ComparisonOperator;
+
+ private readonly Location _OperatorLocation;
+
+ private readonly Expression _Operand;
+
+ ///
+ /// The location of the 'Is', if any.
+ ///
+ public Location IsLocation => _IsLocation;
+
+ ///
+ /// The comparison operator used in the case clause.
+ ///
+ public OperatorType ComparisonOperator => _ComparisonOperator;
+
+ ///
+ /// The location of the comparison operator.
+ ///
+ public Location OperatorLocation => _OperatorLocation;
+
+ ///
+ /// The operand of the case clause.
+ ///
+ public Expression Operand => _Operand;
+
+ ///
+ /// Constructs a new parse tree for a comparison case clause.
+ ///
+ /// The location of the 'Is', if any.
+ /// The comparison operator used.
+ /// The location of the comparison operator.
+ /// The operand of the comparison.
+ /// The location of the parse tree.
+ public ComparisonCaseClause(Location isLocation, OperatorType comparisonOperator, Location operatorLocation, Expression operand, Span span)
+ : base(TreeType.ComparisonCaseClause, span)
+ {
+ if (operand == null)
+ {
+ throw new ArgumentNullException("operand");
+ }
+ if (comparisonOperator < OperatorType.Equals || comparisonOperator > OperatorType.GreaterThanEquals)
+ {
+ throw new ArgumentOutOfRangeException("comparisonOperator");
+ }
+ SetParent(operand);
+ _IsLocation = isLocation;
+ _ComparisonOperator = comparisonOperator;
+ _OperatorLocation = operatorLocation;
+ _Operand = operand;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Operand);
+ }
+}
diff --git a/AspClassic.Parser/CompoundAssignmentStatement.cs b/AspClassic.Parser/CompoundAssignmentStatement.cs
new file mode 100644
index 0000000..6b5884a
--- /dev/null
+++ b/AspClassic.Parser/CompoundAssignmentStatement.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a compound assignment statement.
+///
+public sealed class CompoundAssignmentStatement : Statement
+{
+ private readonly Expression _TargetExpression;
+
+ private readonly OperatorType _CompoundOperator;
+
+ private readonly Location _OperatorLocation;
+
+ private readonly Expression _SourceExpression;
+
+ ///
+ /// The target of the assignment.
+ ///
+ public Expression TargetExpression => _TargetExpression;
+
+ ///
+ /// The compound operator.
+ ///
+ public OperatorType CompoundOperator => _CompoundOperator;
+
+ ///
+ /// The location of the operator.
+ ///
+ public Location OperatorLocation => _OperatorLocation;
+
+ ///
+ /// The source of the assignment.
+ ///
+ public Expression SourceExpression => _SourceExpression;
+
+ ///
+ /// Constructs a new parse tree for a compound assignment statement.
+ ///
+ /// The compound operator.
+ /// The target of the assignment.
+ /// The location of the operator.
+ /// The source of the assignment.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public CompoundAssignmentStatement(OperatorType compoundOperator, Expression targetExpression, Location operatorLocation, Expression sourceExpression, Span span, IList comments)
+ : base(TreeType.CompoundAssignmentStatement, span, comments)
+ {
+ if (compoundOperator < OperatorType.Plus || compoundOperator > OperatorType.Power)
+ {
+ throw new ArgumentOutOfRangeException("compoundOperator");
+ }
+ if (targetExpression == null)
+ {
+ throw new ArgumentNullException("targetExpression");
+ }
+ if (sourceExpression == null)
+ {
+ throw new ArgumentNullException("sourceExpression");
+ }
+ SetParent(targetExpression);
+ SetParent(sourceExpression);
+ _CompoundOperator = compoundOperator;
+ _TargetExpression = targetExpression;
+ _OperatorLocation = operatorLocation;
+ _SourceExpression = sourceExpression;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, TargetExpression);
+ Tree.AddChild(childList, SourceExpression);
+ }
+}
diff --git a/AspClassic.Parser/ConstructedTypeName.cs b/AspClassic.Parser/ConstructedTypeName.cs
new file mode 100644
index 0000000..20f1f08
--- /dev/null
+++ b/AspClassic.Parser/ConstructedTypeName.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a constructed generic type name.
+///
+public sealed class ConstructedTypeName : NamedTypeName
+{
+ private readonly TypeArgumentCollection _TypeArguments;
+
+ ///
+ /// The type arguments.
+ ///
+ public TypeArgumentCollection TypeArguments => _TypeArguments;
+
+ ///
+ /// Constructs a new parse tree for a generic constructed type name.
+ ///
+ /// The generic type being constructed.
+ /// The type arguments.
+ /// The location of the parse tree.
+ public ConstructedTypeName(Name name, TypeArgumentCollection typeArguments, Span span)
+ : base(TreeType.ConstructedType, name, span)
+ {
+ if (typeArguments == null)
+ {
+ throw new ArgumentNullException("typeArguments");
+ }
+ SetParent(typeArguments);
+ _TypeArguments = typeArguments;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, TypeArguments);
+ }
+}
diff --git a/AspClassic.Parser/ConstructorDeclaration.cs b/AspClassic.Parser/ConstructorDeclaration.cs
new file mode 100644
index 0000000..4b3565b
--- /dev/null
+++ b/AspClassic.Parser/ConstructorDeclaration.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a constructor declaration.
+///
+public sealed class ConstructorDeclaration : MethodDeclaration
+{
+ ///
+ /// Creates a new parse tree for a constructor declaration.
+ ///
+ /// The attributes for the parse tree.
+ /// The modifiers for the parse tree.
+ /// The location of the keyword.
+ /// The name of the declaration.
+ /// The parameters of the declaration.
+ /// The statements in the declaration.
+ /// The end block declaration, if any.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public ConstructorDeclaration(AttributeBlockCollection attributes, ModifierCollection modifiers, Location keywordLocation, SimpleName name, ParameterCollection parameters, StatementCollection statements, EndBlockDeclaration endDeclaration, Span span, IList comments)
+ : base(TreeType.ConstructorDeclaration, attributes, modifiers, keywordLocation, name, null, parameters, default(Location), null, null, null, null, statements, endDeclaration, span, comments)
+ {
+ }
+}
diff --git a/AspClassic.Parser/ContinueStatement.cs b/AspClassic.Parser/ContinueStatement.cs
new file mode 100644
index 0000000..d3d714d
--- /dev/null
+++ b/AspClassic.Parser/ContinueStatement.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an Continue statement.
+///
+public sealed class ContinueStatement : Statement
+{
+ private readonly BlockType _ContinueType;
+
+ private readonly Location _ContinueArgumentLocation;
+
+ ///
+ /// The type of tree this statement continues.
+ ///
+ public BlockType ContinueType => _ContinueType;
+
+ ///
+ /// The location of the Continue statement type.
+ ///
+ public Location ContinueArgumentLocation => _ContinueArgumentLocation;
+
+ ///
+ /// Constructs a parse tree for an Continue statement.
+ ///
+ /// The type of tree this statement continues.
+ /// The location of the Continue statement type.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public ContinueStatement(BlockType continueType, Location continueArgumentLocation, Span span, IList comments)
+ : base(TreeType.ContinueStatement, span, comments)
+ {
+ if ((uint)continueType > 3u)
+ {
+ throw new ArgumentOutOfRangeException("continueType");
+ }
+ _ContinueType = continueType;
+ _ContinueArgumentLocation = continueArgumentLocation;
+ }
+}
diff --git a/AspClassic.Parser/CustomEventDeclaration.cs b/AspClassic.Parser/CustomEventDeclaration.cs
new file mode 100644
index 0000000..a5c6321
--- /dev/null
+++ b/AspClassic.Parser/CustomEventDeclaration.cs
@@ -0,0 +1,72 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a custom event declaration.
+///
+public sealed class CustomEventDeclaration : SignatureDeclaration
+{
+ private readonly Location _CustomLocation;
+
+ private readonly NameCollection _ImplementsList;
+
+ private readonly DeclarationCollection _Accessors;
+
+ private readonly EndBlockDeclaration _EndDeclaration;
+
+ ///
+ /// The location of the 'Custom' keyword.
+ ///
+ public Location CustomLocation => _CustomLocation;
+
+ ///
+ /// The list of implemented members.
+ ///
+ public NameCollection ImplementsList => _ImplementsList;
+
+ ///
+ /// The event accessors.
+ ///
+ public DeclarationCollection Accessors => _Accessors;
+
+ ///
+ /// The End Event declaration, if any.
+ ///
+ public EndBlockDeclaration EndDeclaration => _EndDeclaration;
+
+ ///
+ /// Constructs a new parse tree for a custom property declaration.
+ ///
+ /// The attributes on the declaration.
+ /// The modifiers on the declaration.
+ /// The location of the 'Custom' keyword.
+ /// The location of the keyword.
+ /// The name of the custom event.
+ /// The location of the 'As', if any.
+ /// The result type, if any.
+ /// The implements list.
+ /// The custom event accessors.
+ /// The End Event declaration, if any.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public CustomEventDeclaration(AttributeBlockCollection attributes, ModifierCollection modifiers, Location customLocation, Location keywordLocation, SimpleName name, Location asLocation, TypeName resultType, NameCollection implementsList, DeclarationCollection accessors, EndBlockDeclaration endDeclaration, Span span, IList comments)
+ : base(TreeType.CustomEventDeclaration, attributes, modifiers, keywordLocation, name, null, null, asLocation, null, resultType, span, comments)
+ {
+ SetParent(accessors);
+ SetParent(endDeclaration);
+ SetParent(implementsList);
+ _CustomLocation = customLocation;
+ _ImplementsList = implementsList;
+ _Accessors = accessors;
+ _EndDeclaration = endDeclaration;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, ImplementsList);
+ Tree.AddChild(childList, Accessors);
+ Tree.AddChild(childList, EndDeclaration);
+ }
+}
diff --git a/AspClassic.Parser/DateLiteralExpression.cs b/AspClassic.Parser/DateLiteralExpression.cs
new file mode 100644
index 0000000..562c06a
--- /dev/null
+++ b/AspClassic.Parser/DateLiteralExpression.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a date literal expression.
+///
+public sealed class DateLiteralExpression : LiteralExpression
+{
+ private readonly DateTime _Literal;
+
+ ///
+ /// The literal value.
+ ///
+ public DateTime Literal => _Literal;
+
+ public override object Value => _Literal;
+
+ ///
+ /// Constructs a new parse tree for a date literal.
+ ///
+ /// The literal value.
+ /// The location of the parse tree.
+ public DateLiteralExpression(DateTime literal, Span span)
+ : base(TreeType.DateLiteralExpression, span)
+ {
+ _Literal = literal;
+ }
+}
diff --git a/AspClassic.Parser/DateLiteralToken.cs b/AspClassic.Parser/DateLiteralToken.cs
new file mode 100644
index 0000000..2b5ad9c
--- /dev/null
+++ b/AspClassic.Parser/DateLiteralToken.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace AspClassic.Parser;
+
+///
+/// A date/time literal.
+///
+public sealed class DateLiteralToken : Token
+{
+ private readonly DateTime _Literal;
+
+ ///
+ /// The literal value.
+ ///
+ public DateTime Literal => _Literal;
+
+ ///
+ /// Constructs a new date literal instance.
+ ///
+ /// The literal value.
+ /// The location of the literal.
+ public DateLiteralToken(DateTime literal, Span span)
+ : base(TokenType.DateLiteral, span)
+ {
+ _Literal = literal;
+ }
+}
diff --git a/AspClassic.Parser/DecimalLiteralExpression.cs b/AspClassic.Parser/DecimalLiteralExpression.cs
new file mode 100644
index 0000000..8c17340
--- /dev/null
+++ b/AspClassic.Parser/DecimalLiteralExpression.cs
@@ -0,0 +1,42 @@
+using System;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a decimal literal expression.
+///
+public sealed class DecimalLiteralExpression : LiteralExpression
+{
+ private readonly decimal _Literal;
+
+ private readonly TypeCharacter _TypeCharacter;
+
+ ///
+ /// The literal value.
+ ///
+ public decimal Literal => _Literal;
+
+ public override object Value => _Literal;
+
+ ///
+ /// The type character on the literal value.
+ ///
+ public TypeCharacter TypeCharacter => _TypeCharacter;
+
+ ///
+ /// Constructs a new parse tree for a floating point literal.
+ ///
+ /// The literal value.
+ /// The type character on the literal value.
+ /// The location of the parse tree.
+ public DecimalLiteralExpression(decimal literal, TypeCharacter typeCharacter, Span span)
+ : base(TreeType.DecimalLiteralExpression, span)
+ {
+ if (typeCharacter != 0 && typeCharacter != TypeCharacter.DecimalChar && typeCharacter != TypeCharacter.DecimalSymbol)
+ {
+ throw new ArgumentOutOfRangeException("typeCharacter");
+ }
+ _Literal = literal;
+ _TypeCharacter = typeCharacter;
+ }
+}
diff --git a/AspClassic.Parser/DecimalLiteralToken.cs b/AspClassic.Parser/DecimalLiteralToken.cs
new file mode 100644
index 0000000..401db85
--- /dev/null
+++ b/AspClassic.Parser/DecimalLiteralToken.cs
@@ -0,0 +1,40 @@
+using System;
+
+namespace AspClassic.Parser;
+
+///
+/// A decimal literal token.
+///
+public sealed class DecimalLiteralToken : Token
+{
+ private readonly decimal _Literal;
+
+ private readonly TypeCharacter _TypeCharacter;
+
+ ///
+ /// The literal value.
+ ///
+ public decimal Literal => _Literal;
+
+ ///
+ /// The type character of the literal.
+ ///
+ public TypeCharacter TypeCharacter => _TypeCharacter;
+
+ ///
+ /// Constructs a new decimal literal token.
+ ///
+ /// The literal value.
+ /// The literal's type character.
+ /// The location of the literal.
+ public DecimalLiteralToken(decimal literal, TypeCharacter typeCharacter, Span span)
+ : base(TokenType.DecimalLiteral, span)
+ {
+ if (typeCharacter != 0 && typeCharacter != TypeCharacter.DecimalChar && typeCharacter != TypeCharacter.DecimalSymbol)
+ {
+ throw new ArgumentOutOfRangeException("typeCharacter");
+ }
+ _Literal = literal;
+ _TypeCharacter = typeCharacter;
+ }
+}
diff --git a/AspClassic.Parser/Declaration.cs b/AspClassic.Parser/Declaration.cs
new file mode 100644
index 0000000..bf28ebb
--- /dev/null
+++ b/AspClassic.Parser/Declaration.cs
@@ -0,0 +1,35 @@
+#define DEBUG
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a declaration.
+///
+public class Declaration : Statement
+{
+ public override bool IsBad => base.Type == TreeType.SyntaxError;
+
+ ///
+ /// Creates a bad declaration.
+ ///
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ /// A bad declaration.
+ public static Declaration GetBadDeclaration(Span span, IList comments)
+ {
+ return new Declaration(span, comments);
+ }
+
+ protected Declaration(TreeType type, Span span, IList comments)
+ : base(type, span, comments)
+ {
+ Debug.Assert(type >= TreeType.EmptyDeclaration && type <= TreeType.DelegateFunctionDeclaration);
+ }
+
+ private Declaration(Span span, IList comments)
+ : base(TreeType.SyntaxError, span, comments)
+ {
+ }
+}
diff --git a/AspClassic.Parser/DeclarationCollection.cs b/AspClassic.Parser/DeclarationCollection.cs
new file mode 100644
index 0000000..9f80968
--- /dev/null
+++ b/AspClassic.Parser/DeclarationCollection.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A read-only collection of declarations.
+///
+public sealed class DeclarationCollection : ColonDelimitedTreeCollection
+{
+ ///
+ /// Constructs a new collection of declarations.
+ ///
+ /// The declarations in the collection.
+ /// The locations of the colons in the collection.
+ /// The location of the parse tree.
+ public DeclarationCollection(IList declarations, IList colonLocations, Span span)
+ : base(TreeType.DeclarationCollection, declarations, colonLocations, span)
+ {
+ if ((declarations == null || declarations.Count == 0) && (colonLocations == null || colonLocations.Count == 0))
+ {
+ throw new ArgumentException("DeclarationCollection cannot be empty.");
+ }
+ }
+}
diff --git a/AspClassic.Parser/DelegateDeclaration.cs b/AspClassic.Parser/DelegateDeclaration.cs
new file mode 100644
index 0000000..0220713
--- /dev/null
+++ b/AspClassic.Parser/DelegateDeclaration.cs
@@ -0,0 +1,30 @@
+#define DEBUG
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a delegate declaration.
+///
+public abstract class DelegateDeclaration : SignatureDeclaration
+{
+ private readonly Location _SubOrFunctionLocation;
+
+ ///
+ /// The location of 'Sub' or 'Function'.
+ ///
+ public Location SubOrFunctionLocation => _SubOrFunctionLocation;
+
+ protected DelegateDeclaration(TreeType type, AttributeBlockCollection attributes, ModifierCollection modifiers, Location keywordLocation, Location subOrFunctionLocation, SimpleName name, TypeParameterCollection typeParameters, ParameterCollection parameters, Location asLocation, AttributeBlockCollection resultTypeAttributes, TypeName resultType, Span span, IList comments)
+ : base(type, attributes, modifiers, keywordLocation, name, typeParameters, parameters, asLocation, resultTypeAttributes, resultType, span, comments)
+ {
+ Debug.Assert(type == TreeType.DelegateSubDeclaration || type == TreeType.DelegateFunctionDeclaration);
+ _SubOrFunctionLocation = subOrFunctionLocation;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ base.GetChildTrees(childList);
+ }
+}
diff --git a/AspClassic.Parser/DelegateFunctionDeclaration.cs b/AspClassic.Parser/DelegateFunctionDeclaration.cs
new file mode 100644
index 0000000..7a429f0
--- /dev/null
+++ b/AspClassic.Parser/DelegateFunctionDeclaration.cs
@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a delegate Function declaration.
+///
+public sealed class DelegateFunctionDeclaration : DelegateDeclaration
+{
+ ///
+ /// Constructs a new parse tree for a delegate declaration.
+ ///
+ /// The attributes for the parse tree.
+ /// The modifiers for the parse tree.
+ /// The location of the keyword.
+ /// The location of the 'Function'.
+ /// The name of the declaration.
+ /// The type parameters of the declaration, if any.
+ /// The parameters of the declaration.
+ /// The location of the 'As', if any.
+ /// The attributes on the result type, if any.
+ /// The result type, if any.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public DelegateFunctionDeclaration(AttributeBlockCollection attributes, ModifierCollection modifiers, Location keywordLocation, Location functionLocation, SimpleName name, TypeParameterCollection typeParameters, ParameterCollection parameters, Location asLocation, AttributeBlockCollection resultTypeAttributes, TypeName resultType, Span span, IList comments)
+ : base(TreeType.DelegateFunctionDeclaration, attributes, modifiers, keywordLocation, functionLocation, name, typeParameters, parameters, asLocation, resultTypeAttributes, resultType, span, comments)
+ {
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ base.GetChildTrees(childList);
+ }
+}
diff --git a/AspClassic.Parser/DelegateSubDeclaration.cs b/AspClassic.Parser/DelegateSubDeclaration.cs
new file mode 100644
index 0000000..231e137
--- /dev/null
+++ b/AspClassic.Parser/DelegateSubDeclaration.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a delegate Sub declaration.
+///
+public sealed class DelegateSubDeclaration : DelegateDeclaration
+{
+ ///
+ /// Constructs a new parse tree for a delegate Sub declaration.
+ ///
+ /// The attributes for the parse tree.
+ /// The modifiers for the parse tree.
+ /// The location of the keyword.
+ /// The location of the 'Sub'.
+ /// The name of the declaration.
+ /// The type parameters of the declaration, if any.
+ /// The parameters of the declaration.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public DelegateSubDeclaration(AttributeBlockCollection attributes, ModifierCollection modifiers, Location keywordLocation, Location subLocation, SimpleName name, TypeParameterCollection typeParameters, ParameterCollection parameters, Span span, IList comments)
+ : base(TreeType.DelegateSubDeclaration, attributes, modifiers, keywordLocation, subLocation, name, typeParameters, parameters, default(Location), null, null, span, comments)
+ {
+ }
+}
diff --git a/AspClassic.Parser/DictionaryLookupExpression.cs b/AspClassic.Parser/DictionaryLookupExpression.cs
new file mode 100644
index 0000000..637bc30
--- /dev/null
+++ b/AspClassic.Parser/DictionaryLookupExpression.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a dictionary lookup expression.
+///
+public sealed class DictionaryLookupExpression : Expression
+{
+ private readonly Expression _Qualifier;
+
+ private readonly Location _BangLocation;
+
+ private readonly SimpleName _Name;
+
+ ///
+ /// The dictionary expression.
+ ///
+ public Expression Qualifier => _Qualifier;
+
+ ///
+ /// The location of the '!'.
+ ///
+ public Location BangLocation => _BangLocation;
+
+ ///
+ /// The name to look up.
+ ///
+ public SimpleName Name => _Name;
+
+ ///
+ /// Constructs a new parse tree for a dictionary lookup expression.
+ ///
+ /// The dictionary expression.
+ /// The location of the '!'.
+ /// The name to look up..
+ /// The location of the parse tree.
+ public DictionaryLookupExpression(Expression qualifier, Location bangLocation, SimpleName name, Span span)
+ : base(TreeType.DictionaryLookupExpression, span)
+ {
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+ SetParent(qualifier);
+ SetParent(name);
+ _Qualifier = qualifier;
+ _BangLocation = bangLocation;
+ _Name = name;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Qualifier);
+ Tree.AddChild(childList, Name);
+ }
+}
diff --git a/AspClassic.Parser/DirectCastExpression.cs b/AspClassic.Parser/DirectCastExpression.cs
new file mode 100644
index 0000000..3c13198
--- /dev/null
+++ b/AspClassic.Parser/DirectCastExpression.cs
@@ -0,0 +1,21 @@
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a DirectCast expression.
+///
+public sealed class DirectCastExpression : CastTypeExpression
+{
+ ///
+ /// Constructs a new parse tree for a DirectCast expression.
+ ///
+ /// The location of the '('.
+ /// The expression to be converted.
+ /// The location of the ','.
+ /// The target type of the conversion.
+ /// The location of the ')'.
+ /// The location of the parse tree.
+ public DirectCastExpression(Location leftParenthesisLocation, Expression operand, Location commaLocation, TypeName target, Location rightParenthesisLocation, Span span)
+ : base(TreeType.DirectCastExpression, leftParenthesisLocation, operand, commaLocation, target, rightParenthesisLocation, span)
+ {
+ }
+}
diff --git a/AspClassic.Parser/DoBlockStatement.cs b/AspClassic.Parser/DoBlockStatement.cs
new file mode 100644
index 0000000..28dca31
--- /dev/null
+++ b/AspClassic.Parser/DoBlockStatement.cs
@@ -0,0 +1,65 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a Do statement.
+///
+public sealed class DoBlockStatement : BlockStatement
+{
+ private readonly bool _IsWhile;
+
+ private readonly Location _WhileOrUntilLocation;
+
+ private readonly Expression _Expression;
+
+ private readonly LoopStatement _EndStatement;
+
+ ///
+ /// Whether the Do is followed by a While or Until, if any.
+ ///
+ public bool IsWhile => _IsWhile;
+
+ ///
+ /// The location of the While or Until, if any.
+ ///
+ public Location WhileOrUntilLocation => _WhileOrUntilLocation;
+
+ ///
+ /// The While or Until expression, if any.
+ ///
+ public Expression Expression => _Expression;
+
+ ///
+ /// The ending Loop statement.
+ ///
+ public LoopStatement EndStatement => _EndStatement;
+
+ ///
+ /// Constructs a new parse tree for a Do statement.
+ ///
+ /// The While or Until expression, if any.
+ /// Whether the Do is followed by a While or Until, if any.
+ /// The location of the While or Until, if any.
+ /// The statements in the block.
+ /// The ending Loop statement.
+ /// The location of the parse tree.
+ /// The comments on the parse tree.
+ public DoBlockStatement(Expression expression, bool isWhile, Location whileOrUntilLocation, StatementCollection statements, LoopStatement endStatement, Span span, IList comments)
+ : base(TreeType.DoBlockStatement, statements, span, comments)
+ {
+ SetParent(expression);
+ SetParent(endStatement);
+ _Expression = expression;
+ _IsWhile = isWhile;
+ _WhileOrUntilLocation = whileOrUntilLocation;
+ _EndStatement = endStatement;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Expression);
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, EndStatement);
+ }
+}
diff --git a/AspClassic.Parser/ElseBlockStatement.cs b/AspClassic.Parser/ElseBlockStatement.cs
new file mode 100644
index 0000000..cc041d2
--- /dev/null
+++ b/AspClassic.Parser/ElseBlockStatement.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an Else block statement.
+///
+public sealed class ElseBlockStatement : BlockStatement
+{
+ private readonly ElseStatement _ElseStatement;
+
+ ///
+ /// The Else or Else If statement.
+ ///
+ public ElseStatement ElseStatement => _ElseStatement;
+
+ ///
+ /// Constructs a new parse tree for an Else block statement.
+ ///
+ /// The Else statement.
+ /// The statements in the block.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public ElseBlockStatement(ElseStatement elseStatement, StatementCollection statements, Span span, IList comments)
+ : base(TreeType.ElseBlockStatement, statements, span, comments)
+ {
+ if (elseStatement == null)
+ {
+ throw new ArgumentNullException("elseStatement");
+ }
+ SetParent(elseStatement);
+ _ElseStatement = elseStatement;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, ElseStatement);
+ base.GetChildTrees(childList);
+ }
+}
diff --git a/AspClassic.Parser/ElseIfBlockStatement.cs b/AspClassic.Parser/ElseIfBlockStatement.cs
new file mode 100644
index 0000000..fd7d9ab
--- /dev/null
+++ b/AspClassic.Parser/ElseIfBlockStatement.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an Else If block statement.
+///
+public sealed class ElseIfBlockStatement : BlockStatement
+{
+ private readonly ElseIfStatement _ElseIfStatement;
+
+ ///
+ /// The Else If statement.
+ ///
+ public ElseIfStatement ElseIfStatement => _ElseIfStatement;
+
+ ///
+ /// Constructs a new parse tree for an Else If block statement.
+ ///
+ /// The Else If statement.
+ /// The statements in the block.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public ElseIfBlockStatement(ElseIfStatement elseIfStatement, StatementCollection statements, Span span, IList comments)
+ : base(TreeType.ElseIfBlockStatement, statements, span, comments)
+ {
+ if (elseIfStatement == null)
+ {
+ throw new ArgumentNullException("elseIfStatement");
+ }
+ SetParent(elseIfStatement);
+ _ElseIfStatement = elseIfStatement;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, ElseIfStatement);
+ base.GetChildTrees(childList);
+ }
+}
diff --git a/AspClassic.Parser/ElseIfStatement.cs b/AspClassic.Parser/ElseIfStatement.cs
new file mode 100644
index 0000000..38a6f94
--- /dev/null
+++ b/AspClassic.Parser/ElseIfStatement.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an Else If statement.
+///
+public sealed class ElseIfStatement : Statement
+{
+ private readonly Expression _Expression;
+
+ private readonly Location _ThenLocation;
+
+ ///
+ /// The conditional expression.
+ ///
+ public Expression Expression => _Expression;
+
+ ///
+ /// The location of the 'Then', if any.
+ ///
+ public Location ThenLocation => _ThenLocation;
+
+ ///
+ /// Constructs a new parse tree for an Else If statement.
+ ///
+ /// The conditional expression.
+ /// The location of the 'Then', if any.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public ElseIfStatement(Expression expression, Location thenLocation, Span span, IList comments)
+ : base(TreeType.ElseIfStatement, span, comments)
+ {
+ if (expression == null)
+ {
+ throw new ArgumentNullException("expression");
+ }
+ SetParent(expression);
+ _Expression = expression;
+ _ThenLocation = thenLocation;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Expression);
+ }
+}
diff --git a/AspClassic.Parser/ElseStatement.cs b/AspClassic.Parser/ElseStatement.cs
new file mode 100644
index 0000000..a9f26a3
--- /dev/null
+++ b/AspClassic.Parser/ElseStatement.cs
@@ -0,0 +1,19 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an Else statement.
+///
+public sealed class ElseStatement : Statement
+{
+ ///
+ /// Constructs a new parse tree for an Else statement.
+ ///
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public ElseStatement(Span span, IList comments)
+ : base(TreeType.ElseStatement, span, comments)
+ {
+ }
+}
diff --git a/AspClassic.Parser/EmptyDeclaration.cs b/AspClassic.Parser/EmptyDeclaration.cs
new file mode 100644
index 0000000..e67e4c1
--- /dev/null
+++ b/AspClassic.Parser/EmptyDeclaration.cs
@@ -0,0 +1,19 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an empty declaration.
+///
+public sealed class EmptyDeclaration : Declaration
+{
+ ///
+ /// Constructs a new parse tree for an empty declaration.
+ ///
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public EmptyDeclaration(Span span, IList comments)
+ : base(TreeType.EmptyDeclaration, span, comments)
+ {
+ }
+}
diff --git a/AspClassic.Parser/EmptyStatement.cs b/AspClassic.Parser/EmptyStatement.cs
new file mode 100644
index 0000000..c0e10f0
--- /dev/null
+++ b/AspClassic.Parser/EmptyStatement.cs
@@ -0,0 +1,19 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an empty statement.
+///
+public sealed class EmptyStatement : Statement
+{
+ ///
+ /// Constructs a new parse tree for an empty statement.
+ ///
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public EmptyStatement(Span span, IList comments)
+ : base(TreeType.EmptyStatement, span, comments)
+ {
+ }
+}
diff --git a/AspClassic.Parser/EndBlockDeclaration.cs b/AspClassic.Parser/EndBlockDeclaration.cs
new file mode 100644
index 0000000..c8f63f4
--- /dev/null
+++ b/AspClassic.Parser/EndBlockDeclaration.cs
@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an End declaration.
+///
+public sealed class EndBlockDeclaration : Declaration
+{
+ private readonly BlockType _EndType;
+
+ private readonly Location _EndArgumentLocation;
+
+ ///
+ /// The type of block the declaration ends.
+ ///
+ public BlockType EndType => _EndType;
+
+ ///
+ /// The location of the end block argument.
+ ///
+ public Location EndArgumentLocation => _EndArgumentLocation;
+
+ ///
+ /// Creates a new parse tree for an End block declaration.
+ ///
+ /// The type of the block the statement ends.
+ /// The location of the end block argument.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public EndBlockDeclaration(BlockType endType, Location endArgumentLocation, Span span, IList comments)
+ : base(TreeType.EndBlockDeclaration, span, comments)
+ {
+ if (endType < BlockType.Sub && endType > BlockType.Namespace)
+ {
+ throw new ArgumentOutOfRangeException("endType");
+ }
+ _EndType = endType;
+ _EndArgumentLocation = endArgumentLocation;
+ }
+
+ internal EndBlockDeclaration(EndBlockStatement endBlockStatement)
+ : base(TreeType.EndBlockDeclaration, endBlockStatement.Span, endBlockStatement.Comments)
+ {
+ BlockType endType = endBlockStatement.EndType;
+ if ((uint)(endType - 10) <= 2u || (uint)(endType - 14) <= 4u)
+ {
+ _EndType = endBlockStatement.EndType;
+ _EndArgumentLocation = endBlockStatement.EndArgumentLocation;
+ return;
+ }
+ throw new ArgumentException("Invalid EndBlockStatement type.");
+ }
+}
diff --git a/AspClassic.Parser/EndBlockStatement.cs b/AspClassic.Parser/EndBlockStatement.cs
new file mode 100644
index 0000000..df53c58
--- /dev/null
+++ b/AspClassic.Parser/EndBlockStatement.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an End statement of a block.
+///
+public sealed class EndBlockStatement : Statement
+{
+ private readonly BlockType _EndType;
+
+ private readonly Location _EndArgumentLocation;
+
+ ///
+ /// The type of block the statement ends.
+ ///
+ public BlockType EndType => _EndType;
+
+ ///
+ /// The location of the end block argument.
+ ///
+ public Location EndArgumentLocation => _EndArgumentLocation;
+
+ ///
+ /// Creates a new parse tree for an End block statement.
+ ///
+ /// The type of the block the statement ends.
+ /// The location of the end block argument.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public EndBlockStatement(BlockType endType, Location endArgumentLocation, Span span, IList comments)
+ : base(TreeType.EndBlockStatement, span, comments)
+ {
+ if (endType < BlockType.While || endType > BlockType.Namespace)
+ {
+ throw new ArgumentOutOfRangeException("endType");
+ }
+ _EndType = endType;
+ _EndArgumentLocation = endArgumentLocation;
+ }
+}
diff --git a/AspClassic.Parser/EndOfStreamToken.cs b/AspClassic.Parser/EndOfStreamToken.cs
new file mode 100644
index 0000000..607a456
--- /dev/null
+++ b/AspClassic.Parser/EndOfStreamToken.cs
@@ -0,0 +1,16 @@
+namespace AspClassic.Parser;
+
+///
+/// A token representing the end of the file.
+///
+public sealed class EndOfStreamToken : Token
+{
+ ///
+ /// Creates a new end-of-stream token.
+ ///
+ /// The location of the end of the stream.
+ public EndOfStreamToken(Span span)
+ : base(TokenType.EndOfStream, span)
+ {
+ }
+}
diff --git a/AspClassic.Parser/EndStatement.cs b/AspClassic.Parser/EndStatement.cs
new file mode 100644
index 0000000..6a5d695
--- /dev/null
+++ b/AspClassic.Parser/EndStatement.cs
@@ -0,0 +1,19 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an End statement.
+///
+public sealed class EndStatement : Statement
+{
+ ///
+ /// Constructs a new parse tree for an End statement.
+ ///
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public EndStatement(Span span, IList comments)
+ : base(TreeType.EndStatement, span, comments)
+ {
+ }
+}
diff --git a/AspClassic.Parser/EnumDeclaration.cs b/AspClassic.Parser/EnumDeclaration.cs
new file mode 100644
index 0000000..dd57fdf
--- /dev/null
+++ b/AspClassic.Parser/EnumDeclaration.cs
@@ -0,0 +1,50 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an Enum declaration.
+///
+public sealed class EnumDeclaration : BlockDeclaration
+{
+ private readonly Location _AsLocation;
+
+ private readonly TypeName _ElementType;
+
+ ///
+ /// The location of the 'As', if any.
+ ///
+ public Location AsLocation => _AsLocation;
+
+ ///
+ /// The element type of the enumerated type, if any.
+ ///
+ public TypeName ElementType => _ElementType;
+
+ ///
+ /// Constructs a parse tree for an Enum declaration.
+ ///
+ /// The attributes for the parse tree.
+ /// The modifiers for the parse tree.
+ /// The location of the keyword.
+ /// The name of the declaration.
+ /// The location of the 'As', if any.
+ /// The element type of the enumerated type, if any.
+ /// The enumerated values.
+ /// The end block declaration, if any.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public EnumDeclaration(AttributeBlockCollection attributes, ModifierCollection modifiers, Location keywordLocation, SimpleName name, Location asLocation, TypeName elementType, DeclarationCollection declarations, EndBlockDeclaration endStatement, Span span, IList comments)
+ : base(TreeType.EnumDeclaration, attributes, modifiers, keywordLocation, name, declarations, endStatement, span, comments)
+ {
+ SetParent(elementType);
+ _AsLocation = asLocation;
+ _ElementType = elementType;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, ElementType);
+ }
+}
diff --git a/AspClassic.Parser/EnumValueDeclaration.cs b/AspClassic.Parser/EnumValueDeclaration.cs
new file mode 100644
index 0000000..8f74ead
--- /dev/null
+++ b/AspClassic.Parser/EnumValueDeclaration.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an enumerated value declaration.
+///
+public sealed class EnumValueDeclaration : ModifiedDeclaration
+{
+ private readonly Name _Name;
+
+ private readonly Location _EqualsLocation;
+
+ private readonly Expression _Expression;
+
+ ///
+ /// The name of the enumerated value.
+ ///
+ public Name Name => _Name;
+
+ ///
+ /// The location of the '=', if any.
+ ///
+ public Location EqualsLocation => _EqualsLocation;
+
+ ///
+ /// The enumerated value, if any.
+ ///
+ public Expression Expression => _Expression;
+
+ ///
+ /// Constructs a new parse tree for an enumerated value.
+ ///
+ /// The attributes on the declaration.
+ /// The name of the declaration.
+ /// The location of the '=', if any.
+ /// The enumerated value, if any.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public EnumValueDeclaration(AttributeBlockCollection attributes, Name name, Location equalsLocation, Expression expression, Span span, IList comments)
+ : base(TreeType.EnumValueDeclaration, attributes, null, span, comments)
+ {
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+ SetParent(name);
+ SetParent(expression);
+ _Name = name;
+ _EqualsLocation = equalsLocation;
+ _Expression = expression;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, Name);
+ Tree.AddChild(childList, Expression);
+ }
+}
diff --git a/AspClassic.Parser/EraseStatement.cs b/AspClassic.Parser/EraseStatement.cs
new file mode 100644
index 0000000..54b28d0
--- /dev/null
+++ b/AspClassic.Parser/EraseStatement.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an Erase statement.
+///
+public sealed class EraseStatement : Statement
+{
+ private readonly ExpressionCollection _Variables;
+
+ ///
+ /// The variables to erase.
+ ///
+ public ExpressionCollection Variables => _Variables;
+
+ ///
+ /// Constructs a new parse tree for an Erase statement.
+ ///
+ /// The variables to erase.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public EraseStatement(ExpressionCollection variables, Span span, IList comments)
+ : base(TreeType.EraseStatement, span, comments)
+ {
+ if (variables == null)
+ {
+ throw new ArgumentNullException("variables");
+ }
+ SetParent(variables);
+ _Variables = variables;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Variables);
+ }
+}
diff --git a/AspClassic.Parser/ErrorStatement.cs b/AspClassic.Parser/ErrorStatement.cs
new file mode 100644
index 0000000..e6a2b54
--- /dev/null
+++ b/AspClassic.Parser/ErrorStatement.cs
@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an Error statement.
+///
+public sealed class ErrorStatement : ExpressionStatement
+{
+ ///
+ /// Constructs a new parse tree for an Error statement.
+ ///
+ /// The expression.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public ErrorStatement(Expression expression, Span span, IList comments)
+ : base(TreeType.ErrorStatement, expression, span, comments)
+ {
+ }
+}
diff --git a/AspClassic.Parser/ErrorToken.cs b/AspClassic.Parser/ErrorToken.cs
new file mode 100644
index 0000000..1d28b09
--- /dev/null
+++ b/AspClassic.Parser/ErrorToken.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace AspClassic.Parser;
+
+///
+/// A lexical error.
+///
+public sealed class ErrorToken : Token
+{
+ private readonly SyntaxError _SyntaxError;
+
+ ///
+ /// The syntax error that represents the lexical error.
+ ///
+ public SyntaxError SyntaxError => _SyntaxError;
+
+ ///
+ /// Creates a new lexical error token.
+ ///
+ /// The type of the error.
+ /// The location of the error.
+ public ErrorToken(SyntaxErrorType errorType, Span span)
+ : base(TokenType.LexicalError, span)
+ {
+ if (errorType < SyntaxErrorType.InvalidEscapedIdentifier || errorType > SyntaxErrorType.InvalidDecimalLiteral)
+ {
+ throw new ArgumentOutOfRangeException("errorType");
+ }
+ _SyntaxError = new SyntaxError(errorType, span);
+ }
+}
diff --git a/AspClassic.Parser/ErrorXmlSerializer.cs b/AspClassic.Parser/ErrorXmlSerializer.cs
new file mode 100644
index 0000000..b09eb29
--- /dev/null
+++ b/AspClassic.Parser/ErrorXmlSerializer.cs
@@ -0,0 +1,39 @@
+using System.Collections.Generic;
+using System.Xml;
+using Microsoft.VisualBasic.CompilerServices;
+
+namespace AspClassic.Parser;
+
+public class ErrorXmlSerializer
+{
+ private readonly XmlWriter Writer;
+
+ public ErrorXmlSerializer(XmlWriter Writer)
+ {
+ this.Writer = Writer;
+ }
+
+ private void Serialize(Span Span)
+ {
+ Writer.WriteAttributeString("startLine", Conversions.ToString(Span.Start.Line));
+ Writer.WriteAttributeString("startCol", Conversions.ToString(Span.Start.Column));
+ Writer.WriteAttributeString("endLine", Conversions.ToString(Span.Finish.Line));
+ Writer.WriteAttributeString("endCol", Conversions.ToString(Span.Finish.Column));
+ }
+
+ public void Serialize(SyntaxError SyntaxError)
+ {
+ Writer.WriteStartElement(SyntaxError.Type.ToString());
+ Serialize(SyntaxError.Span);
+ Writer.WriteString(SyntaxError.ToString());
+ Writer.WriteEndElement();
+ }
+
+ public void Serialize(List SyntaxErrors)
+ {
+ foreach (SyntaxError SyntaxError in SyntaxErrors)
+ {
+ Serialize(SyntaxError);
+ }
+ }
+}
diff --git a/AspClassic.Parser/EventDeclaration.cs b/AspClassic.Parser/EventDeclaration.cs
new file mode 100644
index 0000000..0ac71b9
--- /dev/null
+++ b/AspClassic.Parser/EventDeclaration.cs
@@ -0,0 +1,43 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an event declaration.
+///
+public sealed class EventDeclaration : SignatureDeclaration
+{
+ private readonly NameCollection _ImplementsList;
+
+ ///
+ /// The list of implemented members.
+ ///
+ public NameCollection ImplementsList => _ImplementsList;
+
+ ///
+ /// Constructs a parse tree for an event declaration.
+ ///
+ /// The attributes for the parse tree.
+ /// The modifiers for the parse tree.
+ /// The location of the keyword.
+ /// The name of the declaration.
+ /// The parameters of the declaration.
+ /// The location of the 'As', if any.
+ /// The attributes on the result type, if any.
+ /// The result type, if any.
+ /// The list of implemented members.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public EventDeclaration(AttributeBlockCollection attributes, ModifierCollection modifiers, Location keywordLocation, SimpleName name, ParameterCollection parameters, Location asLocation, AttributeBlockCollection resultTypeAttributes, TypeName resultType, NameCollection implementsList, Span span, IList comments)
+ : base(TreeType.EventDeclaration, attributes, modifiers, keywordLocation, name, null, parameters, asLocation, resultTypeAttributes, resultType, span, comments)
+ {
+ SetParent(implementsList);
+ _ImplementsList = implementsList;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, ImplementsList);
+ }
+}
diff --git a/AspClassic.Parser/ExitStatement.cs b/AspClassic.Parser/ExitStatement.cs
new file mode 100644
index 0000000..838c573
--- /dev/null
+++ b/AspClassic.Parser/ExitStatement.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an Exit statement.
+///
+public sealed class ExitStatement : Statement
+{
+ private readonly BlockType _ExitType;
+
+ private readonly Location _ExitArgumentLocation;
+
+ ///
+ /// The type of tree this statement exits.
+ ///
+ public BlockType ExitType => _ExitType;
+
+ ///
+ /// The location of the exit statement type.
+ ///
+ public Location ExitArgumentLocation => _ExitArgumentLocation;
+
+ ///
+ /// Constructs a parse tree for an Exit statement.
+ ///
+ /// The type of tree this statement exits.
+ /// The location of the exit statement type.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public ExitStatement(BlockType exitType, Location exitArgumentLocation, Span span, IList comments)
+ : base(TreeType.ExitStatement, span, comments)
+ {
+ switch (exitType)
+ {
+ default:
+ throw new ArgumentOutOfRangeException("exitType");
+ case BlockType.None:
+ case BlockType.Do:
+ case BlockType.For:
+ case BlockType.While:
+ case BlockType.Select:
+ case BlockType.Try:
+ case BlockType.Sub:
+ case BlockType.Function:
+ case BlockType.Property:
+ _ExitType = exitType;
+ _ExitArgumentLocation = exitArgumentLocation;
+ break;
+ }
+ }
+}
diff --git a/AspClassic.Parser/Expression.cs b/AspClassic.Parser/Expression.cs
new file mode 100644
index 0000000..fdc79b0
--- /dev/null
+++ b/AspClassic.Parser/Expression.cs
@@ -0,0 +1,38 @@
+#define DEBUG
+using System.Diagnostics;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an expression.
+///
+public class Expression : Tree
+{
+ ///
+ /// Whether the expression is constant or not.
+ ///
+ public virtual bool IsConstant => false;
+
+ public override bool IsBad => base.Type == TreeType.SyntaxError;
+
+ ///
+ /// Creates a bad expression.
+ ///
+ /// The location of the parse tree.
+ /// A bad expression.
+ public static Expression GetBadExpression(Span span)
+ {
+ return new Expression(span);
+ }
+
+ protected Expression(TreeType type, Span span)
+ : base(type, span)
+ {
+ Debug.Assert(type >= TreeType.SimpleNameExpression && type <= TreeType.GetTypeExpression);
+ }
+
+ private Expression(Span span)
+ : base(TreeType.SyntaxError, span)
+ {
+ }
+}
diff --git a/AspClassic.Parser/ExpressionBlockStatement.cs b/AspClassic.Parser/ExpressionBlockStatement.cs
new file mode 100644
index 0000000..813a585
--- /dev/null
+++ b/AspClassic.Parser/ExpressionBlockStatement.cs
@@ -0,0 +1,42 @@
+#define DEBUG
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an expression block statement.
+///
+public abstract class ExpressionBlockStatement : BlockStatement
+{
+ private readonly Expression _Expression;
+
+ private readonly EndBlockStatement _EndStatement;
+
+ ///
+ /// The expression.
+ ///
+ public Expression Expression => _Expression;
+
+ ///
+ /// The End statement for the block, if any.
+ ///
+ public EndBlockStatement EndStatement => _EndStatement;
+
+ protected ExpressionBlockStatement(TreeType type, Expression expression, StatementCollection statements, EndBlockStatement endStatement, Span span, IList comments)
+ : base(type, statements, span, comments)
+ {
+ Debug.Assert(type == TreeType.WithBlockStatement || type == TreeType.SyncLockBlockStatement || type == TreeType.WhileBlockStatement || type == TreeType.UsingBlockStatement);
+ SetParent(expression);
+ SetParent(endStatement);
+ _Expression = expression;
+ _EndStatement = endStatement;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Expression);
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, EndStatement);
+ }
+}
diff --git a/AspClassic.Parser/ExpressionCollection.cs b/AspClassic.Parser/ExpressionCollection.cs
new file mode 100644
index 0000000..ee151f3
--- /dev/null
+++ b/AspClassic.Parser/ExpressionCollection.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A read-only collection of expressions.
+///
+public sealed class ExpressionCollection : CommaDelimitedTreeCollection
+{
+ ///
+ /// Constructs a new collection of expressions.
+ ///
+ /// The expressions in the collection.
+ /// The locations of the commas in the collection.
+ /// The location of the parse tree.
+ public ExpressionCollection(IList expressions, IList commaLocations, Span span)
+ : base(TreeType.ExpressionCollection, expressions, commaLocations, span)
+ {
+ if ((expressions == null || expressions.Count == 0) && (commaLocations == null || commaLocations.Count == 0))
+ {
+ throw new ArgumentException("ExpressionCollection cannot be empty.");
+ }
+ }
+}
diff --git a/AspClassic.Parser/ExpressionInitializer.cs b/AspClassic.Parser/ExpressionInitializer.cs
new file mode 100644
index 0000000..214732e
--- /dev/null
+++ b/AspClassic.Parser/ExpressionInitializer.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an expression initializer.
+///
+public sealed class ExpressionInitializer : Initializer
+{
+ private readonly Expression _Expression;
+
+ ///
+ /// The expression.
+ ///
+ public Expression Expression => _Expression;
+
+ ///
+ /// Constructs a new expression initializer parse tree.
+ ///
+ /// The expression.
+ /// The location of the parse tree.
+ public ExpressionInitializer(Expression expression, Span span)
+ : base(TreeType.ExpressionInitializer, span)
+ {
+ if (expression == null)
+ {
+ throw new ArgumentNullException("expression");
+ }
+ SetParent(expression);
+ _Expression = expression;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Expression);
+ }
+}
diff --git a/AspClassic.Parser/ExpressionStatement.cs b/AspClassic.Parser/ExpressionStatement.cs
new file mode 100644
index 0000000..5c8dea2
--- /dev/null
+++ b/AspClassic.Parser/ExpressionStatement.cs
@@ -0,0 +1,38 @@
+#define DEBUG
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an expression statement.
+///
+public abstract class ExpressionStatement : Statement
+{
+ private readonly Expression _Expression;
+
+ ///
+ /// The expression.
+ ///
+ public Expression Expression => _Expression;
+
+ ///
+ /// Constructs a new parse tree for an expression statement.
+ ///
+ /// The type of the parse tree.
+ /// The expression.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ protected ExpressionStatement(TreeType type, Expression expression, Span span, IList comments)
+ : base(type, span, comments)
+ {
+ Debug.Assert(type == TreeType.ReturnStatement || type == TreeType.ErrorStatement || type == TreeType.ThrowStatement);
+ SetParent(expression);
+ _Expression = expression;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Expression);
+ }
+}
diff --git a/AspClassic.Parser/ExternalChecksum.cs b/AspClassic.Parser/ExternalChecksum.cs
new file mode 100644
index 0000000..fd80196
--- /dev/null
+++ b/AspClassic.Parser/ExternalChecksum.cs
@@ -0,0 +1,41 @@
+namespace AspClassic.Parser;
+
+///
+/// An external checksum for a file.
+///
+public sealed class ExternalChecksum
+{
+ private readonly string _Filename;
+
+ private readonly string _Guid;
+
+ private readonly string _Checksum;
+
+ ///
+ /// The filename that the checksum is for.
+ ///
+ public string Filename => _Filename;
+
+ ///
+ /// The guid of the file.
+ ///
+ public string Guid => _Guid;
+
+ ///
+ /// The checksum for the file.
+ ///
+ public string Checksum => _Checksum;
+
+ ///
+ /// Constructs a new external checksum.
+ ///
+ /// The filename that the checksum is for.
+ /// The guid of the file.
+ /// The checksum for the file.
+ public ExternalChecksum(string filename, string guid, string checksum)
+ {
+ _Filename = filename;
+ _Guid = guid;
+ _Checksum = checksum;
+ }
+}
diff --git a/AspClassic.Parser/ExternalDeclaration.cs b/AspClassic.Parser/ExternalDeclaration.cs
new file mode 100644
index 0000000..33f7002
--- /dev/null
+++ b/AspClassic.Parser/ExternalDeclaration.cs
@@ -0,0 +1,79 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a Declare statement.
+///
+public abstract class ExternalDeclaration : SignatureDeclaration
+{
+ private readonly Location _CharsetLocation;
+
+ private readonly Charset _Charset;
+
+ private readonly Location _SubOrFunctionLocation;
+
+ private readonly Location _LibLocation;
+
+ private readonly StringLiteralExpression _LibLiteral;
+
+ private readonly Location _AliasLocation;
+
+ private readonly StringLiteralExpression _AliasLiteral;
+
+ ///
+ /// The location of 'Auto', 'Ansi' or 'Unicode', if any.
+ ///
+ public Location CharsetLocation => _CharsetLocation;
+
+ ///
+ /// The charset.
+ ///
+ public Charset Charset => _Charset;
+
+ ///
+ /// The location of 'Sub' or 'Function'.
+ ///
+ public Location SubOrFunctionLocation => _SubOrFunctionLocation;
+
+ ///
+ /// The location of 'Lib', if any.
+ ///
+ public Location LibLocation => _LibLocation;
+
+ ///
+ /// The library, if any.
+ ///
+ public StringLiteralExpression LibLiteral => _LibLiteral;
+
+ ///
+ /// The location of 'Alias', if any.
+ ///
+ public Location AliasLocation => _AliasLocation;
+
+ ///
+ /// The alias, if any.
+ ///
+ public StringLiteralExpression AliasLiteral => _AliasLiteral;
+
+ protected ExternalDeclaration(TreeType type, AttributeBlockCollection attributes, ModifierCollection modifiers, Location keywordLocation, Location charsetLocation, Charset charset, Location subOrFunctionLocation, SimpleName name, Location libLocation, StringLiteralExpression libLiteral, Location aliasLocation, StringLiteralExpression aliasLiteral, ParameterCollection parameters, Location asLocation, AttributeBlockCollection resultTypeAttributes, TypeName resultType, Span span, IList comments)
+ : base(type, attributes, modifiers, keywordLocation, name, null, parameters, asLocation, resultTypeAttributes, resultType, span, comments)
+ {
+ SetParent(libLiteral);
+ SetParent(aliasLiteral);
+ _CharsetLocation = charsetLocation;
+ _Charset = charset;
+ _SubOrFunctionLocation = subOrFunctionLocation;
+ _LibLocation = libLocation;
+ _LibLiteral = libLiteral;
+ _AliasLocation = aliasLocation;
+ _AliasLiteral = aliasLiteral;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, LibLiteral);
+ Tree.AddChild(childList, AliasLiteral);
+ }
+}
diff --git a/AspClassic.Parser/ExternalFunctionDeclaration.cs b/AspClassic.Parser/ExternalFunctionDeclaration.cs
new file mode 100644
index 0000000..94c6077
--- /dev/null
+++ b/AspClassic.Parser/ExternalFunctionDeclaration.cs
@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a Declare Function statement.
+///
+public sealed class ExternalFunctionDeclaration : ExternalDeclaration
+{
+ ///
+ /// Constructs a parse tree for a Declare Function statement.
+ ///
+ /// The attributes for the parse tree.
+ /// The modifiers for the parse tree.
+ /// The location of the keyword.
+ /// The location of the 'Ansi', 'Auto' or 'Unicode', if any.
+ /// The charset.
+ /// The location of 'Function'.
+ /// The name of the declaration.
+ /// The location of 'Lib', if any.
+ /// The library, if any.
+ /// The location of 'Alias', if any.
+ /// The alias, if any.
+ /// The parameters of the declaration.
+ /// The location of the 'As', if any.
+ /// The attributes on the result type, if any.
+ /// The result type, if any.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public ExternalFunctionDeclaration(AttributeBlockCollection attributes, ModifierCollection modifiers, Location keywordLocation, Location charsetLocation, Charset charset, Location functionLocation, SimpleName name, Location libLocation, StringLiteralExpression libLiteral, Location aliasLocation, StringLiteralExpression aliasLiteral, ParameterCollection parameters, Location asLocation, AttributeBlockCollection resultTypeAttributes, TypeName resultType, Span span, IList comments)
+ : base(TreeType.ExternalFunctionDeclaration, attributes, modifiers, keywordLocation, charsetLocation, charset, functionLocation, name, libLocation, libLiteral, aliasLocation, aliasLiteral, parameters, asLocation, resultTypeAttributes, resultType, span, comments)
+ {
+ }
+}
diff --git a/AspClassic.Parser/ExternalLineMapping.cs b/AspClassic.Parser/ExternalLineMapping.cs
new file mode 100644
index 0000000..9964646
--- /dev/null
+++ b/AspClassic.Parser/ExternalLineMapping.cs
@@ -0,0 +1,50 @@
+namespace AspClassic.Parser;
+
+///
+/// A line mapping from a source span to an external file and line.
+///
+public sealed class ExternalLineMapping
+{
+ private readonly Location _Start;
+
+ private readonly Location _Finish;
+
+ private readonly string _File;
+
+ private readonly long _Line;
+
+ ///
+ /// The start location of the mapping in the source.
+ ///
+ public Location Start => _Start;
+
+ ///
+ /// The end location of the mapping in the source.
+ ///
+ public Location Finish => _Finish;
+
+ ///
+ /// The external file the source maps to.
+ ///
+ public string File => _File;
+
+ ///
+ /// The external line number the source maps to.
+ ///
+ public long Line => _Line;
+
+ ///
+ /// Constructs a new external line mapping.
+ ///
+ /// The start location in the source.
+ /// The end location in the source.
+ /// The name of the external file.
+ /// The line number in the external file.
+ public ExternalLineMapping(Location start, Location finish, string file, long line)
+ {
+ _Start = start;
+ _Finish = finish;
+ _File = file;
+ _Line = line;
+ }
+}
diff --git a/AspClassic.Parser/ExternalSubDeclaration.cs b/AspClassic.Parser/ExternalSubDeclaration.cs
new file mode 100644
index 0000000..8ec4981
--- /dev/null
+++ b/AspClassic.Parser/ExternalSubDeclaration.cs
@@ -0,0 +1,31 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a Declare Sub statement.
+///
+public sealed class ExternalSubDeclaration : ExternalDeclaration
+{
+ ///
+ /// Constructs a parse tree for a Declare Sub statement.
+ ///
+ /// The attributes for the parse tree.
+ /// The modifiers for the parse tree.
+ /// The location of the keyword.
+ /// The location of the 'Ansi', 'Auto' or 'Unicode', if any.
+ /// The charset.
+ /// The location of 'Sub'.
+ /// The name of the declaration.
+ /// The location of 'Lib', if any.
+ /// The library, if any.
+ /// The location of 'Alias', if any.
+ /// The alias, if any.
+ /// The parameters of the declaration.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public ExternalSubDeclaration(AttributeBlockCollection attributes, ModifierCollection modifiers, Location keywordLocation, Location charsetLocation, Charset charset, Location subLocation, SimpleName name, Location libLocation, StringLiteralExpression libLiteral, Location aliasLocation, StringLiteralExpression aliasLiteral, ParameterCollection parameters, Span span, IList comments)
+ : base(TreeType.ExternalSubDeclaration, attributes, modifiers, keywordLocation, charsetLocation, charset, subLocation, name, libLocation, libLiteral, aliasLocation, aliasLiteral, parameters, default(Location), null, null, span, comments)
+ {
+ }
+}
diff --git a/AspClassic.Parser/File.cs b/AspClassic.Parser/File.cs
new file mode 100644
index 0000000..b8c93b3
--- /dev/null
+++ b/AspClassic.Parser/File.cs
@@ -0,0 +1,33 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an entire file.
+///
+public sealed class File : Tree
+{
+ private readonly DeclarationCollection _Declarations;
+
+ ///
+ /// The declarations in the file.
+ ///
+ public DeclarationCollection Declarations => _Declarations;
+
+ ///
+ /// Constructs a new file parse tree.
+ ///
+ /// The declarations in the file.
+ /// The location of the tree.
+ public File(DeclarationCollection declarations, Span span)
+ : base(TreeType.File, span)
+ {
+ SetParent(declarations);
+ _Declarations = declarations;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Declarations);
+ }
+}
diff --git a/AspClassic.Parser/FinallyBlockStatement.cs b/AspClassic.Parser/FinallyBlockStatement.cs
new file mode 100644
index 0000000..caac07f
--- /dev/null
+++ b/AspClassic.Parser/FinallyBlockStatement.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a Finally block statement.
+///
+public sealed class FinallyBlockStatement : BlockStatement
+{
+ private readonly FinallyStatement _FinallyStatement;
+
+ ///
+ /// The Finally statement.
+ ///
+ public FinallyStatement FinallyStatement => _FinallyStatement;
+
+ ///
+ /// Constructs a new parse tree for a Finally block statement.
+ ///
+ /// The Finally statement.
+ /// The statements in the block.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public FinallyBlockStatement(FinallyStatement finallyStatement, StatementCollection statements, Span span, IList comments)
+ : base(TreeType.FinallyBlockStatement, statements, span, comments)
+ {
+ if (finallyStatement == null)
+ {
+ throw new ArgumentNullException("finallyStatement");
+ }
+ SetParent(finallyStatement);
+ _FinallyStatement = finallyStatement;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, FinallyStatement);
+ base.GetChildTrees(childList);
+ }
+}
diff --git a/AspClassic.Parser/FinallyStatement.cs b/AspClassic.Parser/FinallyStatement.cs
new file mode 100644
index 0000000..fd8751e
--- /dev/null
+++ b/AspClassic.Parser/FinallyStatement.cs
@@ -0,0 +1,19 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a Finally statement.
+///
+public sealed class FinallyStatement : Statement
+{
+ ///
+ /// Constructs a new parse tree for a Finally statement.
+ ///
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public FinallyStatement(Span span, IList comments)
+ : base(TreeType.FinallyStatement, span, comments)
+ {
+ }
+}
diff --git a/AspClassic.Parser/FloatingPointLiteralExpression.cs b/AspClassic.Parser/FloatingPointLiteralExpression.cs
new file mode 100644
index 0000000..5ba4212
--- /dev/null
+++ b/AspClassic.Parser/FloatingPointLiteralExpression.cs
@@ -0,0 +1,42 @@
+using System;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a floating point literal.
+///
+public sealed class FloatingPointLiteralExpression : LiteralExpression
+{
+ private readonly double _Literal;
+
+ private readonly TypeCharacter _TypeCharacter;
+
+ ///
+ /// The literal value.
+ ///
+ public double Literal => _Literal;
+
+ public override object Value => _Literal;
+
+ ///
+ /// The type character on the literal value.
+ ///
+ public TypeCharacter TypeCharacter => _TypeCharacter;
+
+ ///
+ /// Constructs a new parse tree for a floating point literal.
+ ///
+ /// The literal value.
+ /// The type character on the literal.
+ /// The location of the parse tree.
+ public FloatingPointLiteralExpression(double literal, TypeCharacter typeCharacter, Span span)
+ : base(TreeType.FloatingPointLiteralExpression, span)
+ {
+ if (typeCharacter != 0 && typeCharacter != TypeCharacter.SingleSymbol && typeCharacter != TypeCharacter.SingleChar && typeCharacter != TypeCharacter.DoubleSymbol && typeCharacter != TypeCharacter.DoubleChar)
+ {
+ throw new ArgumentOutOfRangeException("typeCharacter");
+ }
+ _Literal = literal;
+ _TypeCharacter = typeCharacter;
+ }
+}
diff --git a/AspClassic.Parser/FloatingPointLiteralToken.cs b/AspClassic.Parser/FloatingPointLiteralToken.cs
new file mode 100644
index 0000000..dd515a4
--- /dev/null
+++ b/AspClassic.Parser/FloatingPointLiteralToken.cs
@@ -0,0 +1,40 @@
+using System;
+
+namespace AspClassic.Parser;
+
+///
+/// A floating point literal.
+///
+public sealed class FloatingPointLiteralToken : Token
+{
+ private readonly double _Literal;
+
+ private readonly TypeCharacter _TypeCharacter;
+
+ ///
+ /// The value of the literal.
+ ///
+ public double Literal => _Literal;
+
+ ///
+ /// The type character after the literal.
+ ///
+ public TypeCharacter TypeCharacter => _TypeCharacter;
+
+ ///
+ /// Constructs a new floating point literal token.
+ ///
+ /// The literal value.
+ /// The type character of the literal.
+ /// The location of the literal.
+ public FloatingPointLiteralToken(double literal, TypeCharacter typeCharacter, Span span)
+ : base(TokenType.FloatingPointLiteral, span)
+ {
+ if (typeCharacter != 0 && typeCharacter != TypeCharacter.SingleSymbol && typeCharacter != TypeCharacter.SingleChar && typeCharacter != TypeCharacter.DoubleSymbol && typeCharacter != TypeCharacter.DoubleChar)
+ {
+ throw new ArgumentOutOfRangeException("typeCharacter");
+ }
+ _Literal = literal;
+ _TypeCharacter = typeCharacter;
+ }
+}
diff --git a/AspClassic.Parser/ForBlockStatement.cs b/AspClassic.Parser/ForBlockStatement.cs
new file mode 100644
index 0000000..bcb5cd8
--- /dev/null
+++ b/AspClassic.Parser/ForBlockStatement.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a For statement.
+///
+public sealed class ForBlockStatement : BlockStatement
+{
+ private readonly Expression _ControlExpression;
+
+ private readonly VariableDeclarator _ControlVariableDeclarator;
+
+ private readonly Location _EqualsLocation;
+
+ private readonly Expression _LowerBoundExpression;
+
+ private readonly Location _ToLocation;
+
+ private readonly Expression _UpperBoundExpression;
+
+ private readonly Location _StepLocation;
+
+ private readonly Expression _StepExpression;
+
+ private readonly NextStatement _NextStatement;
+
+ ///
+ /// The control expression for the loop.
+ ///
+ public Expression ControlExpression => _ControlExpression;
+
+ ///
+ /// The control variable declarator, if any.
+ ///
+ public VariableDeclarator ControlVariableDeclarator => _ControlVariableDeclarator;
+
+ ///
+ /// The location of the '='.
+ ///
+ public Location EqualsLocation => _EqualsLocation;
+
+ ///
+ /// The lower bound of the loop.
+ ///
+ public Expression LowerBoundExpression => _LowerBoundExpression;
+
+ ///
+ /// The location of the 'To'.
+ ///
+ public Location ToLocation => _ToLocation;
+
+ ///
+ /// The upper bound of the loop.
+ ///
+ public Expression UpperBoundExpression => _UpperBoundExpression;
+
+ ///
+ /// The location of the 'Step', if any.
+ ///
+ public Location StepLocation => _StepLocation;
+
+ ///
+ /// The step of the loop, if any.
+ ///
+ public Expression StepExpression => _StepExpression;
+
+ ///
+ /// The Next statement, if any.
+ ///
+ public NextStatement NextStatement => _NextStatement;
+
+ ///
+ /// Constructs a new parse tree for a For statement.
+ ///
+ /// The control expression for the loop.
+ /// The control variable declarator, if any.
+ /// The location of the '='.
+ /// The lower bound of the loop.
+ /// The location of the 'To'.
+ /// The upper bound of the loop.
+ /// The location of the 'Step', if any.
+ /// The step of the loop, if any.
+ /// The statements in the For loop.
+ /// The Next statement, if any.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public ForBlockStatement(Expression controlExpression, VariableDeclarator controlVariableDeclarator, Location equalsLocation, Expression lowerBoundExpression, Location toLocation, Expression upperBoundExpression, Location stepLocation, Expression stepExpression, StatementCollection statements, NextStatement nextStatement, Span span, IList comments)
+ : base(TreeType.ForBlockStatement, statements, span, comments)
+ {
+ if (controlExpression == null)
+ {
+ throw new ArgumentNullException("controlExpression");
+ }
+ SetParent(controlExpression);
+ SetParent(controlVariableDeclarator);
+ SetParent(lowerBoundExpression);
+ SetParent(upperBoundExpression);
+ SetParent(stepExpression);
+ SetParent(nextStatement);
+ _ControlExpression = controlExpression;
+ _ControlVariableDeclarator = controlVariableDeclarator;
+ _EqualsLocation = equalsLocation;
+ _LowerBoundExpression = lowerBoundExpression;
+ _ToLocation = toLocation;
+ _UpperBoundExpression = upperBoundExpression;
+ _StepLocation = stepLocation;
+ _StepExpression = stepExpression;
+ _NextStatement = nextStatement;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, ControlExpression);
+ Tree.AddChild(childList, ControlVariableDeclarator);
+ Tree.AddChild(childList, LowerBoundExpression);
+ Tree.AddChild(childList, UpperBoundExpression);
+ Tree.AddChild(childList, StepExpression);
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, NextStatement);
+ }
+}
diff --git a/AspClassic.Parser/ForEachBlockStatement.cs b/AspClassic.Parser/ForEachBlockStatement.cs
new file mode 100644
index 0000000..3b009ad
--- /dev/null
+++ b/AspClassic.Parser/ForEachBlockStatement.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a For Each statement.
+///
+public sealed class ForEachBlockStatement : BlockStatement
+{
+ private readonly Location _EachLocation;
+
+ private readonly Expression _ControlExpression;
+
+ private readonly VariableDeclarator _ControlVariableDeclarator;
+
+ private readonly Location _InLocation;
+
+ private readonly Expression _CollectionExpression;
+
+ private readonly NextStatement _NextStatement;
+
+ ///
+ /// The location of the 'Each'.
+ ///
+ public Location EachLocation => _EachLocation;
+
+ ///
+ /// The control expression.
+ ///
+ public Expression ControlExpression => _ControlExpression;
+
+ ///
+ /// The control variable declarator, if any.
+ ///
+ public VariableDeclarator ControlVariableDeclarator => _ControlVariableDeclarator;
+
+ ///
+ /// The location of the 'In'.
+ ///
+ public Location InLocation => _InLocation;
+
+ ///
+ /// The collection expression.
+ ///
+ public Expression CollectionExpression => _CollectionExpression;
+
+ ///
+ /// The Next statement, if any.
+ ///
+ public NextStatement NextStatement => _NextStatement;
+
+ ///
+ /// Constructs a new parse tree for a For Each statement.
+ ///
+ /// The location of the 'Each'.
+ /// The control expression.
+ /// The control variable declarator, if any.
+ /// The location of the 'In'.
+ /// The collection expression.
+ /// The statements in the block.
+ /// The Next statement, if any.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public ForEachBlockStatement(Location eachLocation, Expression controlExpression, VariableDeclarator controlVariableDeclarator, Location inLocation, Expression collectionExpression, StatementCollection statements, NextStatement nextStatement, Span span, IList comments)
+ : base(TreeType.ForEachBlockStatement, statements, span, comments)
+ {
+ if (controlExpression == null)
+ {
+ throw new ArgumentNullException("controlExpression");
+ }
+ SetParent(controlExpression);
+ SetParent(controlVariableDeclarator);
+ SetParent(collectionExpression);
+ SetParent(nextStatement);
+ _EachLocation = eachLocation;
+ _ControlExpression = controlExpression;
+ _ControlVariableDeclarator = controlVariableDeclarator;
+ _InLocation = inLocation;
+ _CollectionExpression = collectionExpression;
+ _NextStatement = nextStatement;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, ControlExpression);
+ Tree.AddChild(childList, ControlVariableDeclarator);
+ Tree.AddChild(childList, CollectionExpression);
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, NextStatement);
+ }
+}
diff --git a/AspClassic.Parser/FunctionDeclaration.cs b/AspClassic.Parser/FunctionDeclaration.cs
new file mode 100644
index 0000000..10d608c
--- /dev/null
+++ b/AspClassic.Parser/FunctionDeclaration.cs
@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a Function declaration.
+///
+public sealed class FunctionDeclaration : MethodDeclaration
+{
+ ///
+ /// Creates a new parse tree for a Function declaration.
+ ///
+ /// The attributes for the parse tree.
+ /// The modifiers for the parse tree.
+ /// The location of the keyword.
+ /// The name of the declaration.
+ /// The type parameters on the declaration, if any.
+ /// The parameters of the declaration.
+ /// The location of the 'As', if any.
+ /// The attributes on the result type, if any.
+ /// The result type, if any.
+ /// The list of implemented members.
+ /// The list of handled events.
+ /// The statements in the declaration.
+ /// The end block declaration, if any.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public FunctionDeclaration(AttributeBlockCollection attributes, ModifierCollection modifiers, Location keywordLocation, SimpleName name, TypeParameterCollection typeParameters, ParameterCollection parameters, Location asLocation, AttributeBlockCollection resultTypeAttributes, TypeName resultType, NameCollection implementsList, NameCollection handlesList, StatementCollection statements, EndBlockDeclaration endDeclaration, Span span, IList comments)
+ : base(TreeType.FunctionDeclaration, attributes, modifiers, keywordLocation, name, typeParameters, parameters, asLocation, resultTypeAttributes, resultType, implementsList, handlesList, statements, endDeclaration, span, comments)
+ {
+ }
+}
diff --git a/AspClassic.Parser/GenericBlockDeclaration.cs b/AspClassic.Parser/GenericBlockDeclaration.cs
new file mode 100644
index 0000000..5e57961
--- /dev/null
+++ b/AspClassic.Parser/GenericBlockDeclaration.cs
@@ -0,0 +1,32 @@
+#define DEBUG
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a possibly generic block declaration.
+///
+public abstract class GenericBlockDeclaration : BlockDeclaration
+{
+ private readonly TypeParameterCollection _TypeParameters;
+
+ ///
+ /// The type parameters of the type, if any.
+ ///
+ public TypeParameterCollection TypeParameters => _TypeParameters;
+
+ protected GenericBlockDeclaration(TreeType type, AttributeBlockCollection attributes, ModifierCollection modifiers, Location keywordLocation, SimpleName name, TypeParameterCollection typeParameters, DeclarationCollection declarations, EndBlockDeclaration endStatement, Span span, IList comments)
+ : base(type, attributes, modifiers, keywordLocation, name, declarations, endStatement, span, comments)
+ {
+ Debug.Assert(type == TreeType.ClassDeclaration || type == TreeType.InterfaceDeclaration || type == TreeType.StructureDeclaration);
+ SetParent(typeParameters);
+ _TypeParameters = typeParameters;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, TypeParameters);
+ }
+}
diff --git a/AspClassic.Parser/GenericQualifiedExpression.cs b/AspClassic.Parser/GenericQualifiedExpression.cs
new file mode 100644
index 0000000..6b33d25
--- /dev/null
+++ b/AspClassic.Parser/GenericQualifiedExpression.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a qualified name expression.
+///
+public sealed class GenericQualifiedExpression : Expression
+{
+ private readonly Expression _Base;
+
+ private readonly TypeArgumentCollection _TypeArguments;
+
+ ///
+ /// The base expression.
+ ///
+ public Expression Base => _Base;
+
+ ///
+ /// The qualifying type arguments.
+ ///
+ public TypeArgumentCollection TypeArguments => _TypeArguments;
+
+ ///
+ /// Constructs a new parse tree for a generic qualified expression.
+ ///
+ /// The base expression.
+ /// The qualifying type arguments.
+ /// The location of the parse tree.
+ public GenericQualifiedExpression(Expression @base, TypeArgumentCollection typeArguments, Span span)
+ : base(TreeType.GenericQualifiedExpression, span)
+ {
+ if (@base == null)
+ {
+ throw new ArgumentNullException("base");
+ }
+ if (typeArguments == null)
+ {
+ throw new ArgumentNullException("typeArguments");
+ }
+ SetParent(@base);
+ SetParent(typeArguments);
+ _Base = @base;
+ _TypeArguments = typeArguments;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Base);
+ Tree.AddChild(childList, TypeArguments);
+ }
+}
diff --git a/AspClassic.Parser/GetAccessorDeclaration.cs b/AspClassic.Parser/GetAccessorDeclaration.cs
new file mode 100644
index 0000000..32000f7
--- /dev/null
+++ b/AspClassic.Parser/GetAccessorDeclaration.cs
@@ -0,0 +1,57 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a Get property accessor.
+///
+public sealed class GetAccessorDeclaration : ModifiedDeclaration
+{
+ private readonly Location _GetLocation;
+
+ private readonly StatementCollection _Statements;
+
+ private readonly EndBlockDeclaration _EndDeclaration;
+
+ ///
+ /// The location of the 'Get'.
+ ///
+ public Location GetLocation => _GetLocation;
+
+ ///
+ /// The statements in the accessor.
+ ///
+ public StatementCollection Statements => _Statements;
+
+ ///
+ /// The End declaration for the accessor.
+ ///
+ public EndBlockDeclaration EndDeclaration => _EndDeclaration;
+
+ ///
+ /// Constructs a new parse tree for a Get property accessor.
+ ///
+ /// The attributes for the parse tree.
+ /// The modifiers for the parse tree.
+ /// The location of the 'Get'.
+ /// The statements in the declaration.
+ /// The end block declaration, if any.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public GetAccessorDeclaration(AttributeBlockCollection attributes, ModifierCollection modifiers, Location getLocation, StatementCollection statements, EndBlockDeclaration endDeclaration, Span span, IList comments)
+ : base(TreeType.GetAccessorDeclaration, attributes, modifiers, span, comments)
+ {
+ SetParent(statements);
+ SetParent(endDeclaration);
+ _GetLocation = getLocation;
+ _Statements = statements;
+ _EndDeclaration = endDeclaration;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, Statements);
+ Tree.AddChild(childList, EndDeclaration);
+ }
+}
diff --git a/AspClassic.Parser/GetTypeExpression.cs b/AspClassic.Parser/GetTypeExpression.cs
new file mode 100644
index 0000000..005fe50
--- /dev/null
+++ b/AspClassic.Parser/GetTypeExpression.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a GetType expression.
+///
+public sealed class GetTypeExpression : Expression
+{
+ private readonly Location _LeftParenthesisLocation;
+
+ private readonly TypeName _Target;
+
+ private readonly Location _RightParenthesisLocation;
+
+ ///
+ /// The location of the '('.
+ ///
+ public Location LeftParenthesisLocation => _LeftParenthesisLocation;
+
+ ///
+ /// The target type of the GetType expression.
+ ///
+ public TypeName Target => _Target;
+
+ ///
+ /// The location of the ')'.
+ ///
+ public Location RightParenthesisLocation => _RightParenthesisLocation;
+
+ ///
+ /// Constructs a new parse tree for a GetType expression.
+ ///
+ /// The location of the '('.
+ /// The target type of the GetType expression.
+ /// The location of the ')'.
+ /// The location of the parse tree.
+ public GetTypeExpression(Location leftParenthesisLocation, TypeName target, Location rightParenthesisLocation, Span span)
+ : base(TreeType.GetTypeExpression, span)
+ {
+ if (target == null)
+ {
+ throw new ArgumentNullException("target");
+ }
+ SetParent(target);
+ _LeftParenthesisLocation = leftParenthesisLocation;
+ _Target = target;
+ _RightParenthesisLocation = rightParenthesisLocation;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Target);
+ }
+}
diff --git a/AspClassic.Parser/GlobalExpression.cs b/AspClassic.Parser/GlobalExpression.cs
new file mode 100644
index 0000000..6562ac4
--- /dev/null
+++ b/AspClassic.Parser/GlobalExpression.cs
@@ -0,0 +1,16 @@
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for Nothing.
+///
+public sealed class GlobalExpression : Expression
+{
+ ///
+ /// Constructs a new parse tree for Global.
+ ///
+ /// The location of the parse tree.
+ public GlobalExpression(Span span)
+ : base(TreeType.GlobalExpression, span)
+ {
+ }
+}
diff --git a/AspClassic.Parser/GotoStatement.cs b/AspClassic.Parser/GotoStatement.cs
new file mode 100644
index 0000000..12d2533
--- /dev/null
+++ b/AspClassic.Parser/GotoStatement.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a GoTo statement.
+///
+public sealed class GotoStatement : LabelReferenceStatement
+{
+ ///
+ /// Constructs a parse tree for a GoTo statement.
+ ///
+ /// The label to branch to, if any.
+ /// Whether the label is a line number.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public GotoStatement(SimpleName name, bool isLineNumber, Span span, IList comments)
+ : base(TreeType.GotoStatement, name, isLineNumber, span, comments)
+ {
+ }
+}
diff --git a/AspClassic.Parser/HandlerStatement.cs b/AspClassic.Parser/HandlerStatement.cs
new file mode 100644
index 0000000..c7ccc39
--- /dev/null
+++ b/AspClassic.Parser/HandlerStatement.cs
@@ -0,0 +1,58 @@
+#define DEBUG
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an AddHandler or RemoveHandler statement.
+///
+public abstract class HandlerStatement : Statement
+{
+ private readonly Expression _Name;
+
+ private readonly Location _CommaLocation;
+
+ private readonly Expression _DelegateExpression;
+
+ ///
+ /// The event name.
+ ///
+ public Expression Name => _Name;
+
+ ///
+ /// The location of the ','.
+ ///
+ public Location CommaLocation => _CommaLocation;
+
+ ///
+ /// The delegate expression.
+ ///
+ public Expression DelegateExpression => _DelegateExpression;
+
+ protected HandlerStatement(TreeType type, Expression name, Location commaLocation, Expression delegateExpression, Span span, IList comments)
+ : base(type, span, comments)
+ {
+ Debug.Assert(type == TreeType.AddHandlerStatement || type == TreeType.RemoveHandlerStatement);
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+ if (delegateExpression == null)
+ {
+ throw new ArgumentNullException("delegateExpression");
+ }
+ SetParent(name);
+ SetParent(delegateExpression);
+ _Name = name;
+ _CommaLocation = commaLocation;
+ _DelegateExpression = delegateExpression;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Name);
+ Tree.AddChild(childList, DelegateExpression);
+ }
+}
diff --git a/AspClassic.Parser/IdentifierToken.cs b/AspClassic.Parser/IdentifierToken.cs
new file mode 100644
index 0000000..41daa89
--- /dev/null
+++ b/AspClassic.Parser/IdentifierToken.cs
@@ -0,0 +1,283 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.VisualBasic.CompilerServices;
+
+namespace AspClassic.Parser;
+
+///
+/// An identifier.
+///
+public sealed class IdentifierToken : Token
+{
+ private struct Keyword
+ {
+ public readonly LanguageVersion Versions;
+
+ public readonly LanguageVersion ReservedVersions;
+
+ public readonly TokenType TokenType;
+
+ public Keyword(LanguageVersion Versions, LanguageVersion ReservedVersions, TokenType TokenType)
+ {
+ this = default(Keyword);
+ this.Versions = Versions;
+ this.ReservedVersions = ReservedVersions;
+ this.TokenType = TokenType;
+ }
+ }
+
+ private static Dictionary KeywordTable;
+
+ private readonly string _Identifier;
+
+ private readonly TokenType _UnreservedType;
+
+ private readonly bool _Escaped;
+
+ private readonly TypeCharacter _TypeCharacter;
+
+ ///
+ /// The identifier name.
+ ///
+ public string Identifier => _Identifier;
+
+ ///
+ /// Whether the identifier is escaped.
+ ///
+ public bool Escaped => _Escaped;
+
+ ///
+ /// The type character of the identifier.
+ ///
+ public TypeCharacter TypeCharacter => _TypeCharacter;
+
+ private static void AddKeyword(Dictionary table, string name, Keyword keyword)
+ {
+ table.Add(name, keyword);
+ table.Add(Scanner.MakeFullWidth(name), keyword);
+ }
+
+ internal static TokenType TokenTypeFromString(string s, LanguageVersion Version, bool IncludeUnreserved)
+ {
+ if (KeywordTable == null)
+ {
+ Dictionary Table = new Dictionary(StringComparer.InvariantCultureIgnoreCase);
+ AddKeyword(Table, "AddHandler", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.AddHandler));
+ AddKeyword(Table, "AddressOf", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.AddressOf));
+ AddKeyword(Table, "Alias", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Alias));
+ AddKeyword(Table, "And", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.And));
+ AddKeyword(Table, "AndAlso", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.AndAlso));
+ AddKeyword(Table, "Ansi", new Keyword(LanguageVersion.All, LanguageVersion.VisualBasic71, TokenType.Ansi));
+ AddKeyword(Table, "As", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.As));
+ AddKeyword(Table, "Assembly", new Keyword(LanguageVersion.All, LanguageVersion.VisualBasic71, TokenType.Assembly));
+ AddKeyword(Table, "Auto", new Keyword(LanguageVersion.All, LanguageVersion.VisualBasic71, TokenType.Auto));
+ AddKeyword(Table, "Binary", new Keyword(LanguageVersion.All, LanguageVersion.None, TokenType.Binary));
+ AddKeyword(Table, "Boolean", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Boolean));
+ AddKeyword(Table, "ByRef", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.ByRef));
+ AddKeyword(Table, "Byte", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Byte));
+ AddKeyword(Table, "ByVal", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.ByVal));
+ AddKeyword(Table, "Call", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Call));
+ AddKeyword(Table, "Case", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Case));
+ AddKeyword(Table, "Catch", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Catch));
+ AddKeyword(Table, "Char", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Char));
+ AddKeyword(Table, "Class", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Class));
+ AddKeyword(Table, "Compare", new Keyword(LanguageVersion.All, LanguageVersion.None, TokenType.Compare));
+ AddKeyword(Table, "Const", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Const));
+ AddKeyword(Table, "Continue", new Keyword(LanguageVersion.VisualBasic80, LanguageVersion.VisualBasic80, TokenType.Continue));
+ AddKeyword(Table, "Custom", new Keyword(LanguageVersion.VisualBasic80, LanguageVersion.None, TokenType.Custom));
+ AddKeyword(Table, "Date", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Date));
+ AddKeyword(Table, "Decimal", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Decimal));
+ AddKeyword(Table, "Declare", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Declare));
+ AddKeyword(Table, "Default", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Default));
+ AddKeyword(Table, "Delegate", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Delegate));
+ AddKeyword(Table, "Dim", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Dim));
+ AddKeyword(Table, "DirectCast", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.DirectCast));
+ AddKeyword(Table, "Do", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Do));
+ AddKeyword(Table, "Double", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Double));
+ AddKeyword(Table, "Each", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Each));
+ AddKeyword(Table, "Else", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Else));
+ AddKeyword(Table, "ElseIf", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.ElseIf));
+ AddKeyword(Table, "End", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.End));
+ AddKeyword(Table, "EndIf", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.EndIf));
+ AddKeyword(Table, "Enum", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Enum));
+ AddKeyword(Table, "Erase", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Erase));
+ AddKeyword(Table, "Error", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Error));
+ AddKeyword(Table, "Event", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Event));
+ AddKeyword(Table, "Exit", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Exit));
+ AddKeyword(Table, "Explicit", new Keyword(LanguageVersion.All, LanguageVersion.None, TokenType.Explicit));
+ AddKeyword(Table, "ExternalChecksum", new Keyword(LanguageVersion.VisualBasic80, LanguageVersion.None, TokenType.ExternalChecksum));
+ AddKeyword(Table, "ExternalSource", new Keyword(LanguageVersion.All, LanguageVersion.None, TokenType.ExternalSource));
+ AddKeyword(Table, "False", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.False));
+ AddKeyword(Table, "Finally", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Finally));
+ AddKeyword(Table, "For", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.For));
+ AddKeyword(Table, "Friend", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Friend));
+ AddKeyword(Table, "Function", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Function));
+ AddKeyword(Table, "Get", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Get));
+ AddKeyword(Table, "GetType", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.GetType));
+ AddKeyword(Table, "Global", new Keyword(LanguageVersion.VisualBasic80, LanguageVersion.VisualBasic80, TokenType.Global));
+ AddKeyword(Table, "GoSub", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.GoSub));
+ AddKeyword(Table, "GoTo", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.GoTo));
+ AddKeyword(Table, "Handles", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Handles));
+ AddKeyword(Table, "If", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.If));
+ AddKeyword(Table, "Implements", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Implements));
+ AddKeyword(Table, "Imports", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Imports));
+ AddKeyword(Table, "In", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.In));
+ AddKeyword(Table, "Inherits", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Inherits));
+ AddKeyword(Table, "Integer", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Integer));
+ AddKeyword(Table, "Interface", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Interface));
+ AddKeyword(Table, "Is", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Is));
+ AddKeyword(Table, "IsFalse", new Keyword(LanguageVersion.VisualBasic80, LanguageVersion.None, TokenType.IsFalse));
+ AddKeyword(Table, "IsNot", new Keyword(LanguageVersion.VisualBasic80, LanguageVersion.VisualBasic80, TokenType.IsNot));
+ AddKeyword(Table, "IsTrue", new Keyword(LanguageVersion.VisualBasic80, LanguageVersion.None, TokenType.IsTrue));
+ AddKeyword(Table, "Let", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Let));
+ AddKeyword(Table, "Lib", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Lib));
+ AddKeyword(Table, "Like", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Like));
+ AddKeyword(Table, "Long", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Long));
+ AddKeyword(Table, "Loop", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Loop));
+ AddKeyword(Table, "Me", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Me));
+ AddKeyword(Table, "Mid", new Keyword(LanguageVersion.All, LanguageVersion.None, TokenType.Mid));
+ AddKeyword(Table, "Mod", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Mod));
+ AddKeyword(Table, "Module", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Module));
+ AddKeyword(Table, "MustInherit", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.MustInherit));
+ AddKeyword(Table, "MustOverride", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.MustOverride));
+ AddKeyword(Table, "MyBase", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.MyBase));
+ AddKeyword(Table, "MyClass", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.MyClass));
+ AddKeyword(Table, "Namespace", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Namespace));
+ AddKeyword(Table, "Narrowing", new Keyword(LanguageVersion.VisualBasic80, LanguageVersion.VisualBasic80, TokenType.Narrowing));
+ AddKeyword(Table, "New", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.New));
+ AddKeyword(Table, "Next", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Next));
+ AddKeyword(Table, "Not", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Not));
+ AddKeyword(Table, "Nothing", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Nothing));
+ AddKeyword(Table, "NotInheritable", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.NotInheritable));
+ AddKeyword(Table, "NotOverridable", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.NotOverridable));
+ AddKeyword(Table, "Object", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Object));
+ AddKeyword(Table, "Of", new Keyword(LanguageVersion.VisualBasic80, LanguageVersion.VisualBasic80, TokenType.Of));
+ AddKeyword(Table, "Off", new Keyword(LanguageVersion.All, LanguageVersion.None, TokenType.Off));
+ AddKeyword(Table, "On", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.On));
+ AddKeyword(Table, "Operator", new Keyword(LanguageVersion.VisualBasic80, LanguageVersion.VisualBasic80, TokenType.Operator));
+ AddKeyword(Table, "Option", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Option));
+ AddKeyword(Table, "Optional", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Optional));
+ AddKeyword(Table, "Or", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Or));
+ AddKeyword(Table, "OrElse", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.OrElse));
+ AddKeyword(Table, "Overloads", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Overloads));
+ AddKeyword(Table, "Overridable", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Overridable));
+ AddKeyword(Table, "Overrides", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Overrides));
+ AddKeyword(Table, "ParamArray", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.ParamArray));
+ AddKeyword(Table, "Partial", new Keyword(LanguageVersion.VisualBasic80, LanguageVersion.VisualBasic80, TokenType.Partial));
+ AddKeyword(Table, "Preserve", new Keyword(LanguageVersion.All, LanguageVersion.VisualBasic71, TokenType.Preserve));
+ AddKeyword(Table, "Private", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Private));
+ AddKeyword(Table, "Property", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Property));
+ AddKeyword(Table, "Protected", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Protected));
+ AddKeyword(Table, "Public", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Public));
+ AddKeyword(Table, "RaiseEvent", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.RaiseEvent));
+ AddKeyword(Table, "ReadOnly", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.ReadOnly));
+ AddKeyword(Table, "ReDim", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.ReDim));
+ AddKeyword(Table, "Region", new Keyword(LanguageVersion.All, LanguageVersion.None, TokenType.Region));
+ AddKeyword(Table, "REM", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.REM));
+ AddKeyword(Table, "RemoveHandler", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.RemoveHandler));
+ AddKeyword(Table, "Resume", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Resume));
+ AddKeyword(Table, "Return", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Return));
+ AddKeyword(Table, "SByte", new Keyword(LanguageVersion.VisualBasic80, LanguageVersion.VisualBasic80, TokenType.SByte));
+ AddKeyword(Table, "Select", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Select));
+ AddKeyword(Table, "Set", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Set));
+ AddKeyword(Table, "Shadows", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Shadows));
+ AddKeyword(Table, "Shared", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Shared));
+ AddKeyword(Table, "Short", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Short));
+ AddKeyword(Table, "Single", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Single));
+ AddKeyword(Table, "Static", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Static));
+ AddKeyword(Table, "Step", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Step));
+ AddKeyword(Table, "Stop", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Stop));
+ AddKeyword(Table, "Strict", new Keyword(LanguageVersion.All, LanguageVersion.None, TokenType.Strict));
+ AddKeyword(Table, "String", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.String));
+ AddKeyword(Table, "Structure", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Structure));
+ AddKeyword(Table, "Sub", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Sub));
+ AddKeyword(Table, "SyncLock", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.SyncLock));
+ AddKeyword(Table, "Text", new Keyword(LanguageVersion.All, LanguageVersion.None, TokenType.Text));
+ AddKeyword(Table, "Then", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Then));
+ AddKeyword(Table, "Throw", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Throw));
+ AddKeyword(Table, "To", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.To));
+ AddKeyword(Table, "True", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.True));
+ AddKeyword(Table, "Try", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Try));
+ AddKeyword(Table, "TryCast", new Keyword(LanguageVersion.VisualBasic80, LanguageVersion.VisualBasic80, TokenType.TryCast));
+ AddKeyword(Table, "TypeOf", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.TypeOf));
+ AddKeyword(Table, "UInteger", new Keyword(LanguageVersion.VisualBasic80, LanguageVersion.VisualBasic80, TokenType.UInteger));
+ AddKeyword(Table, "ULong", new Keyword(LanguageVersion.VisualBasic80, LanguageVersion.VisualBasic80, TokenType.ULong));
+ AddKeyword(Table, "UShort", new Keyword(LanguageVersion.VisualBasic80, LanguageVersion.VisualBasic80, TokenType.UShort));
+ AddKeyword(Table, "Using", new Keyword(LanguageVersion.VisualBasic80, LanguageVersion.VisualBasic80, TokenType.Using));
+ AddKeyword(Table, "Unicode", new Keyword(LanguageVersion.All, LanguageVersion.VisualBasic71, TokenType.Unicode));
+ AddKeyword(Table, "Until", new Keyword(LanguageVersion.All, LanguageVersion.VisualBasic71, TokenType.Until));
+ AddKeyword(Table, "Variant", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Variant));
+ AddKeyword(Table, "Wend", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Wend));
+ AddKeyword(Table, "When", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.When));
+ AddKeyword(Table, "While", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.While));
+ AddKeyword(Table, "Widening", new Keyword(LanguageVersion.VisualBasic80, LanguageVersion.VisualBasic80, TokenType.Widening));
+ AddKeyword(Table, "With", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.With));
+ AddKeyword(Table, "WithEvents", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.WithEvents));
+ AddKeyword(Table, "WriteOnly", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.WriteOnly));
+ AddKeyword(Table, "Xor", new Keyword(LanguageVersion.All, LanguageVersion.All, TokenType.Xor));
+ KeywordTable = Table;
+ }
+ if (KeywordTable.ContainsKey(s))
+ {
+ Keyword Keyword = KeywordTable[s];
+ if ((Keyword.Versions & Version) == Version && (IncludeUnreserved || (Keyword.ReservedVersions & Version) == Version))
+ {
+ return Keyword.TokenType;
+ }
+ }
+ return TokenType.Identifier;
+ }
+
+ ///
+ /// Determines if a token type is a keyword.
+ ///
+ /// The token type to check.
+ /// True if the token type is a keyword, False otherwise.
+ public static bool IsKeyword(TokenType type)
+ {
+ return type >= TokenType.AddHandler && type <= TokenType.Xor;
+ }
+
+ public override TokenType AsUnreservedKeyword()
+ {
+ return _UnreservedType;
+ }
+
+ ///
+ /// Constructs a new identifier token.
+ ///
+ /// The token type of the identifier.
+ /// The unreserved token type of the identifier.
+ /// The text of the identifier
+ /// Whether the identifier is escaped.
+ /// The type character of the identifier.
+ /// The location of the identifier.
+ public IdentifierToken(TokenType type, TokenType unreservedType, string identifier, bool escaped, TypeCharacter typeCharacter, Span span)
+ : base(type, span)
+ {
+ if (type != TokenType.Identifier && !IsKeyword(type))
+ {
+ throw new ArgumentOutOfRangeException("type");
+ }
+ if (unreservedType != TokenType.Identifier && !IsKeyword(unreservedType))
+ {
+ throw new ArgumentOutOfRangeException("unreservedType");
+ }
+ if (identifier == null || Operators.CompareString(identifier, "", TextCompare: false) == 0)
+ {
+ throw new ArgumentException("Identifier cannot be empty.", "identifier");
+ }
+ if (typeCharacter != 0 && typeCharacter != TypeCharacter.DecimalSymbol && typeCharacter != TypeCharacter.DoubleSymbol && typeCharacter != TypeCharacter.IntegerSymbol && typeCharacter != TypeCharacter.LongSymbol && typeCharacter != TypeCharacter.SingleSymbol && typeCharacter != TypeCharacter.StringSymbol)
+ {
+ throw new ArgumentOutOfRangeException("typeCharacter");
+ }
+ if (typeCharacter != 0 && escaped)
+ {
+ throw new ArgumentException("Escaped identifiers cannot have type characters.");
+ }
+ _UnreservedType = unreservedType;
+ _Identifier = identifier;
+ _Escaped = escaped;
+ _TypeCharacter = typeCharacter;
+ }
+}
diff --git a/AspClassic.Parser/IfBlockStatement.cs b/AspClassic.Parser/IfBlockStatement.cs
new file mode 100644
index 0000000..7547b92
--- /dev/null
+++ b/AspClassic.Parser/IfBlockStatement.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an If block.
+///
+public sealed class IfBlockStatement : BlockStatement
+{
+ private readonly Expression _Expression;
+
+ private readonly Location _ThenLocation;
+
+ private readonly StatementCollection _ElseIfBlockStatements;
+
+ private readonly ElseBlockStatement _ElseBlockStatement;
+
+ private readonly EndBlockStatement _EndStatement;
+
+ ///
+ /// The conditional expression.
+ ///
+ public Expression Expression => _Expression;
+
+ ///
+ /// The location of the 'Then', if any.
+ ///
+ public Location ThenLocation => _ThenLocation;
+
+ ///
+ /// The Else If statements.
+ ///
+ public StatementCollection ElseIfBlockStatements => _ElseIfBlockStatements;
+
+ ///
+ /// The Else statement, if any.
+ ///
+ public ElseBlockStatement ElseBlockStatement => _ElseBlockStatement;
+
+ ///
+ /// The End If statement, if any.
+ ///
+ public EndBlockStatement EndStatement => _EndStatement;
+
+ ///
+ /// Constructs a new parse tree for a If statement.
+ ///
+ /// The conditional expression.
+ /// The location of the 'Then', if any.
+ /// The statements in the If block.
+ /// The Else If statements.
+ /// The Else statement, if any.
+ /// The End If statement, if any.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public IfBlockStatement(Expression expression, Location thenLocation, StatementCollection statements, StatementCollection elseIfBlockStatements, ElseBlockStatement elseBlockStatement, EndBlockStatement endStatement, Span span, IList comments)
+ : base(TreeType.IfBlockStatement, statements, span, comments)
+ {
+ if (expression == null)
+ {
+ throw new ArgumentNullException("expression");
+ }
+ SetParent(expression);
+ SetParent(elseIfBlockStatements);
+ SetParent(elseBlockStatement);
+ SetParent(endStatement);
+ _Expression = expression;
+ _ThenLocation = thenLocation;
+ _ElseIfBlockStatements = elseIfBlockStatements;
+ _ElseBlockStatement = elseBlockStatement;
+ _EndStatement = endStatement;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Expression);
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, ElseIfBlockStatements);
+ Tree.AddChild(childList, ElseBlockStatement);
+ Tree.AddChild(childList, EndStatement);
+ }
+}
diff --git a/AspClassic.Parser/ImplementsDeclaration.cs b/AspClassic.Parser/ImplementsDeclaration.cs
new file mode 100644
index 0000000..1f307d8
--- /dev/null
+++ b/AspClassic.Parser/ImplementsDeclaration.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an Implements declaration.
+///
+public sealed class ImplementsDeclaration : Declaration
+{
+ private readonly TypeNameCollection _ImplementedTypes;
+
+ ///
+ /// The list of types.
+ ///
+ public TypeNameCollection ImplementedTypes => _ImplementedTypes;
+
+ ///
+ /// Constructs a parse tree for an Implements declaration.
+ ///
+ /// The types inherited or implemented.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public ImplementsDeclaration(TypeNameCollection implementedTypes, Span span, IList comments)
+ : base(TreeType.ImplementsDeclaration, span, comments)
+ {
+ if (implementedTypes == null)
+ {
+ throw new ArgumentNullException("implementedTypes");
+ }
+ SetParent(implementedTypes);
+ _ImplementedTypes = implementedTypes;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, ImplementedTypes);
+ }
+}
diff --git a/AspClassic.Parser/Import.cs b/AspClassic.Parser/Import.cs
new file mode 100644
index 0000000..1215b4c
--- /dev/null
+++ b/AspClassic.Parser/Import.cs
@@ -0,0 +1,16 @@
+#define DEBUG
+using System.Diagnostics;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an Imports statement.
+///
+public abstract class Import : Tree
+{
+ protected Import(TreeType type, Span span)
+ : base(type, span)
+ {
+ Debug.Assert(type == TreeType.AliasImport || type == TreeType.NameImport);
+ }
+}
diff --git a/AspClassic.Parser/ImportCollection.cs b/AspClassic.Parser/ImportCollection.cs
new file mode 100644
index 0000000..09c7d53
--- /dev/null
+++ b/AspClassic.Parser/ImportCollection.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A read-only collection of imports.
+///
+public sealed class ImportCollection : CommaDelimitedTreeCollection
+{
+ ///
+ /// Constructs a collection of imports.
+ ///
+ /// The imports in the collection.
+ /// The location of the commas.
+ /// The location of the parse tree.
+ public ImportCollection(IList importMembers, IList commaLocations, Span span)
+ : base(TreeType.ImportCollection, importMembers, commaLocations, span)
+ {
+ if (importMembers == null || importMembers.Count == 0)
+ {
+ throw new ArgumentException("ImportCollection cannot be empty.");
+ }
+ }
+}
diff --git a/AspClassic.Parser/ImportsDeclaration.cs b/AspClassic.Parser/ImportsDeclaration.cs
new file mode 100644
index 0000000..9fa3917
--- /dev/null
+++ b/AspClassic.Parser/ImportsDeclaration.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an Imports declaration.
+///
+public sealed class ImportsDeclaration : Declaration
+{
+ private readonly ImportCollection _ImportMembers;
+
+ ///
+ /// The members imported.
+ ///
+ public ImportCollection ImportMembers => _ImportMembers;
+
+ ///
+ /// Constructs a parse tree for an Imports declaration.
+ ///
+ /// The members imported.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public ImportsDeclaration(ImportCollection importMembers, Span span, IList comments)
+ : base(TreeType.ImportsDeclaration, span, comments)
+ {
+ if (importMembers == null)
+ {
+ throw new ArgumentNullException("importMembers");
+ }
+ SetParent(importMembers);
+ _ImportMembers = importMembers;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, ImportMembers);
+ }
+}
diff --git a/AspClassic.Parser/InheritsDeclaration.cs b/AspClassic.Parser/InheritsDeclaration.cs
new file mode 100644
index 0000000..85cfa87
--- /dev/null
+++ b/AspClassic.Parser/InheritsDeclaration.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an Inherits declaration.
+///
+public sealed class InheritsDeclaration : Declaration
+{
+ private readonly TypeNameCollection _InheritedTypes;
+
+ ///
+ /// The list of types.
+ ///
+ public TypeNameCollection InheritedTypes => _InheritedTypes;
+
+ ///
+ /// Constructs a parse tree for an Inherits declaration.
+ ///
+ /// The types inherited or implemented.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public InheritsDeclaration(TypeNameCollection inheritedTypes, Span span, IList comments)
+ : base(TreeType.InheritsDeclaration, span, comments)
+ {
+ if (inheritedTypes == null)
+ {
+ throw new ArgumentNullException("inheritedTypes");
+ }
+ SetParent(inheritedTypes);
+ _InheritedTypes = inheritedTypes;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, InheritedTypes);
+ }
+}
diff --git a/AspClassic.Parser/Initializer.cs b/AspClassic.Parser/Initializer.cs
new file mode 100644
index 0000000..07c13f5
--- /dev/null
+++ b/AspClassic.Parser/Initializer.cs
@@ -0,0 +1,16 @@
+#define DEBUG
+using System.Diagnostics;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an initializer.
+///
+public abstract class Initializer : Tree
+{
+ protected Initializer(TreeType type, Span span)
+ : base(type, span)
+ {
+ Debug.Assert(type == TreeType.ExpressionInitializer || type == TreeType.AggregateInitializer);
+ }
+}
diff --git a/AspClassic.Parser/InitializerCollection.cs b/AspClassic.Parser/InitializerCollection.cs
new file mode 100644
index 0000000..d2f3fe9
--- /dev/null
+++ b/AspClassic.Parser/InitializerCollection.cs
@@ -0,0 +1,29 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A read-only collection of initializers.
+///
+public sealed class InitializerCollection : CommaDelimitedTreeCollection
+{
+ private readonly Location _RightCurlyBraceLocation;
+
+ ///
+ /// The location of the '}'.
+ ///
+ public Location RightCurlyBraceLocation => _RightCurlyBraceLocation;
+
+ ///
+ /// Constructs a new initializer collection.
+ ///
+ /// The initializers in the collection.
+ /// The locations of the commas in the collection.
+ /// The location of the '}'.
+ /// The location of the parse tree.
+ public InitializerCollection(IList initializers, IList commaLocations, Location rightCurlyBraceLocation, Span span)
+ : base(TreeType.InitializerCollection, initializers, commaLocations, span)
+ {
+ _RightCurlyBraceLocation = rightCurlyBraceLocation;
+ }
+}
diff --git a/AspClassic.Parser/InstanceExpression.cs b/AspClassic.Parser/InstanceExpression.cs
new file mode 100644
index 0000000..6c3e4f1
--- /dev/null
+++ b/AspClassic.Parser/InstanceExpression.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for Me, MyBase or MyClass.
+///
+public sealed class InstanceExpression : Expression
+{
+ private InstanceType _InstanceType;
+
+ ///
+ /// The type of the instance expression.
+ ///
+ public InstanceType InstanceType => _InstanceType;
+
+ ///
+ /// Constructs a new parse tree for My, MyBase or MyClass.
+ ///
+ /// The type of the instance expression.
+ /// The location of the parse tree.
+ public InstanceExpression(InstanceType instanceType, Span span)
+ : base(TreeType.InstanceExpression, span)
+ {
+ if (instanceType < InstanceType.Me || instanceType > InstanceType.MyBase)
+ {
+ throw new ArgumentOutOfRangeException("instanceType");
+ }
+ _InstanceType = instanceType;
+ }
+}
diff --git a/AspClassic.Parser/InstanceType.cs b/AspClassic.Parser/InstanceType.cs
new file mode 100644
index 0000000..3ed0131
--- /dev/null
+++ b/AspClassic.Parser/InstanceType.cs
@@ -0,0 +1,11 @@
+namespace AspClassic.Parser;
+
+///
+/// The type of an instance expression.
+///
+public enum InstanceType
+{
+ Me,
+ MyClass,
+ MyBase
+}
diff --git a/AspClassic.Parser/IntegerBase.cs b/AspClassic.Parser/IntegerBase.cs
new file mode 100644
index 0000000..d7247d4
--- /dev/null
+++ b/AspClassic.Parser/IntegerBase.cs
@@ -0,0 +1,14 @@
+namespace AspClassic.Parser;
+
+///
+/// The numeric base of an integer literal.
+///
+public enum IntegerBase
+{
+ /// Base 10.
+ Decimal,
+ /// Base 8.
+ Octal,
+ /// Base 16.
+ Hexadecimal
+}
diff --git a/AspClassic.Parser/IntegerLiteralExpression.cs b/AspClassic.Parser/IntegerLiteralExpression.cs
new file mode 100644
index 0000000..eb9f4cf
--- /dev/null
+++ b/AspClassic.Parser/IntegerLiteralExpression.cs
@@ -0,0 +1,55 @@
+using System;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an integer literal.
+///
+public sealed class IntegerLiteralExpression : LiteralExpression
+{
+ private readonly int _Literal;
+
+ private readonly TypeCharacter _TypeCharacter;
+
+ private readonly IntegerBase _IntegerBase;
+
+ ///
+ /// The literal value.
+ ///
+ public int Literal => _Literal;
+
+ public override object Value => _Literal;
+
+ ///
+ /// The type character on the literal.
+ ///
+ public TypeCharacter TypeCharacter => _TypeCharacter;
+
+ ///
+ /// The integer base of the literal.
+ ///
+ public IntegerBase IntegerBase => _IntegerBase;
+
+ ///
+ /// Constructs a new parse tree for an integer literal.
+ ///
+ /// The literal value.
+ /// The integer base of the literal.
+ /// The type character on the literal.
+ /// The location of the parse tree.
+ public IntegerLiteralExpression(int literal, IntegerBase integerBase, TypeCharacter typeCharacter, Span span)
+ : base(TreeType.IntegerLiteralExpression, span)
+ {
+ if (integerBase < IntegerBase.Decimal || integerBase > IntegerBase.Hexadecimal)
+ {
+ throw new ArgumentOutOfRangeException("integerBase");
+ }
+ if (typeCharacter != 0 && typeCharacter != TypeCharacter.IntegerSymbol && typeCharacter != TypeCharacter.IntegerChar && typeCharacter != TypeCharacter.ShortChar && typeCharacter != TypeCharacter.LongSymbol && typeCharacter != TypeCharacter.LongChar)
+ {
+ throw new ArgumentOutOfRangeException("typeCharacter");
+ }
+ _Literal = literal;
+ _IntegerBase = integerBase;
+ _TypeCharacter = typeCharacter;
+ }
+}
diff --git a/AspClassic.Parser/IntegerLiteralToken.cs b/AspClassic.Parser/IntegerLiteralToken.cs
new file mode 100644
index 0000000..cc1bb97
--- /dev/null
+++ b/AspClassic.Parser/IntegerLiteralToken.cs
@@ -0,0 +1,53 @@
+using System;
+
+namespace AspClassic.Parser;
+
+///
+/// An integer literal.
+///
+public sealed class IntegerLiteralToken : Token
+{
+ private readonly int _Literal;
+
+ private readonly TypeCharacter _TypeCharacter;
+
+ private readonly IntegerBase _IntegerBase;
+
+ ///
+ /// The value of the literal.
+ ///
+ public int Literal => _Literal;
+
+ ///
+ /// The type character of the literal.
+ ///
+ public TypeCharacter TypeCharacter => _TypeCharacter;
+
+ ///
+ /// The integer base of the literal.
+ ///
+ public IntegerBase IntegerBase => _IntegerBase;
+
+ ///
+ /// Constructs a new integer literal.
+ ///
+ /// The literal value.
+ /// The integer base of the literal.
+ /// The type character of the literal.
+ /// The location of the literal.
+ public IntegerLiteralToken(int literal, IntegerBase integerBase, TypeCharacter typeCharacter, Span span)
+ : base(TokenType.IntegerLiteral, span)
+ {
+ if (integerBase < IntegerBase.Decimal || integerBase > IntegerBase.Hexadecimal)
+ {
+ throw new ArgumentOutOfRangeException("integerBase");
+ }
+ if (typeCharacter != 0 && typeCharacter != TypeCharacter.IntegerSymbol && typeCharacter != TypeCharacter.IntegerChar && typeCharacter != TypeCharacter.ShortChar && typeCharacter != TypeCharacter.LongSymbol && typeCharacter != TypeCharacter.LongChar)
+ {
+ throw new ArgumentOutOfRangeException("typeCharacter");
+ }
+ _Literal = literal;
+ _IntegerBase = integerBase;
+ _TypeCharacter = typeCharacter;
+ }
+}
diff --git a/AspClassic.Parser/InterfaceDeclaration.cs b/AspClassic.Parser/InterfaceDeclaration.cs
new file mode 100644
index 0000000..601d7f8
--- /dev/null
+++ b/AspClassic.Parser/InterfaceDeclaration.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a Interface declaration.
+///
+public sealed class InterfaceDeclaration : GenericBlockDeclaration
+{
+ ///
+ /// Constructs a new parse tree for a Interface declaration.
+ ///
+ /// The attributes for the parse tree.
+ /// The modifiers for the parse tree.
+ /// The location of the keyword.
+ /// The name of the declaration.
+ /// The type parameters on the declaration, if any.
+ /// The declarations in the block.
+ /// The end block declaration, if any.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public InterfaceDeclaration(AttributeBlockCollection attributes, ModifierCollection modifiers, Location keywordLocation, SimpleName name, TypeParameterCollection typeParameters, DeclarationCollection declarations, EndBlockDeclaration endStatement, Span span, IList comments)
+ : base(TreeType.InterfaceDeclaration, attributes, modifiers, keywordLocation, name, typeParameters, declarations, endStatement, span, comments)
+ {
+ }
+}
diff --git a/AspClassic.Parser/IntrinsicCastExpression.cs b/AspClassic.Parser/IntrinsicCastExpression.cs
new file mode 100644
index 0000000..c7555ae
--- /dev/null
+++ b/AspClassic.Parser/IntrinsicCastExpression.cs
@@ -0,0 +1,54 @@
+using System;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an intrinsic conversion expression.
+///
+public sealed class IntrinsicCastExpression : UnaryExpression
+{
+ private readonly IntrinsicType _IntrinsicType;
+
+ private readonly Location _LeftParenthesisLocation;
+
+ private readonly Location _RightParenthesisLocation;
+
+ ///
+ /// The intrinsic type conversion.
+ ///
+ public IntrinsicType IntrinsicType => _IntrinsicType;
+
+ ///
+ /// The location of the '('.
+ ///
+ public Location LeftParenthesisLocation => _LeftParenthesisLocation;
+
+ ///
+ /// The location of the ')'.
+ ///
+ public Location RightParenthesisLocation => _RightParenthesisLocation;
+
+ ///
+ /// Constructs a new parse tree for an intrinsic conversion expression.
+ ///
+ /// The intrinsic type conversion.
+ /// The location of the '('.
+ /// The expression to convert.
+ /// The location of the ')'.
+ /// The location of the parse tree.
+ public IntrinsicCastExpression(IntrinsicType intrinsicType, Location leftParenthesisLocation, Expression operand, Location rightParenthesisLocation, Span span)
+ : base(TreeType.IntrinsicCastExpression, operand, span)
+ {
+ if (intrinsicType < IntrinsicType.Boolean || intrinsicType > IntrinsicType.Object)
+ {
+ throw new ArgumentOutOfRangeException("intrinsicType");
+ }
+ if (operand == null)
+ {
+ throw new ArgumentNullException("operand");
+ }
+ _IntrinsicType = intrinsicType;
+ _LeftParenthesisLocation = leftParenthesisLocation;
+ _RightParenthesisLocation = rightParenthesisLocation;
+ }
+}
diff --git a/AspClassic.Parser/IntrinsicType.cs b/AspClassic.Parser/IntrinsicType.cs
new file mode 100644
index 0000000..ff588e6
--- /dev/null
+++ b/AspClassic.Parser/IntrinsicType.cs
@@ -0,0 +1,24 @@
+namespace AspClassic.Parser;
+
+///
+/// The type of an intrinsic type name.
+///
+public enum IntrinsicType
+{
+ Boolean,
+ SByte,
+ Byte,
+ Short,
+ UShort,
+ Integer,
+ UInteger,
+ Long,
+ ULong,
+ Decimal,
+ Single,
+ Double,
+ Date,
+ Char,
+ String,
+ Object
+}
diff --git a/AspClassic.Parser/IntrinsicTypeName.cs b/AspClassic.Parser/IntrinsicTypeName.cs
new file mode 100644
index 0000000..b252655
--- /dev/null
+++ b/AspClassic.Parser/IntrinsicTypeName.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an intrinsic type name.
+///
+public sealed class IntrinsicTypeName : TypeName
+{
+ private IntrinsicType _IntrinsicType;
+
+ ///
+ /// The intrinsic type.
+ ///
+ public IntrinsicType IntrinsicType => _IntrinsicType;
+
+ ///
+ /// Constructs a new intrinsic type parse tree.
+ ///
+ /// The intrinsic type.
+ /// The location of the parse tree.
+ public IntrinsicTypeName(IntrinsicType intrinsicType, Span span)
+ : base(TreeType.IntrinsicType, span)
+ {
+ if (intrinsicType < IntrinsicType.Boolean || intrinsicType > IntrinsicType.Object)
+ {
+ throw new ArgumentOutOfRangeException("intrinsicType");
+ }
+ _IntrinsicType = intrinsicType;
+ }
+}
diff --git a/AspClassic.Parser/LabelReferenceStatement.cs b/AspClassic.Parser/LabelReferenceStatement.cs
new file mode 100644
index 0000000..193ac2a
--- /dev/null
+++ b/AspClassic.Parser/LabelReferenceStatement.cs
@@ -0,0 +1,39 @@
+#define DEBUG
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a statement that refers to a label.
+///
+public abstract class LabelReferenceStatement : Statement
+{
+ private readonly SimpleName _Name;
+
+ private readonly bool _IsLineNumber;
+
+ ///
+ /// The name of the label being referred to.
+ ///
+ public SimpleName Name => _Name;
+
+ ///
+ /// Whether the label is a line number.
+ ///
+ public bool IsLineNumber => _IsLineNumber;
+
+ protected LabelReferenceStatement(TreeType type, SimpleName name, bool isLineNumber, Span span, IList comments)
+ : base(type, span, comments)
+ {
+ Debug.Assert(type == TreeType.GotoStatement || type == TreeType.LabelStatement || type == TreeType.OnErrorStatement || type == TreeType.ResumeStatement);
+ SetParent(name);
+ _Name = name;
+ _IsLineNumber = isLineNumber;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Name);
+ }
+}
diff --git a/AspClassic.Parser/LabelStatement.cs b/AspClassic.Parser/LabelStatement.cs
new file mode 100644
index 0000000..0590a50
--- /dev/null
+++ b/AspClassic.Parser/LabelStatement.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a label declaration statement.
+///
+public sealed class LabelStatement : LabelReferenceStatement
+{
+ ///
+ /// Constructs a parse tree for a label declaration statement.
+ ///
+ /// The label to branch to, if any.
+ /// Whether the label is a line number.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public LabelStatement(SimpleName name, bool isLineNumber, Span span, IList comments)
+ : base(TreeType.LabelStatement, name, isLineNumber, span, comments)
+ {
+ }
+}
diff --git a/AspClassic.Parser/LanguageVersion.cs b/AspClassic.Parser/LanguageVersion.cs
new file mode 100644
index 0000000..e308f8f
--- /dev/null
+++ b/AspClassic.Parser/LanguageVersion.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace AspClassic.Parser;
+
+///
+/// The version of the language you want.
+///
+[Flags]
+public enum LanguageVersion
+{
+ None = 0,
+ /// Visual Basic 7.1
+ /// Shipped in Visual Basic 2003
+ VisualBasic71 = 1,
+ /// Visual Basic 8.0
+ /// Shipped in Visual Basic 2005
+ VisualBasic80 = 2,
+ All = 3
+}
diff --git a/AspClassic.Parser/LineIfStatement.cs b/AspClassic.Parser/LineIfStatement.cs
new file mode 100644
index 0000000..72ac4a9
--- /dev/null
+++ b/AspClassic.Parser/LineIfStatement.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a line If statement.
+///
+public sealed class LineIfStatement : Statement
+{
+ private readonly Expression _Expression;
+
+ private readonly Location _ThenLocation;
+
+ private readonly StatementCollection _IfStatements;
+
+ private readonly Location _ElseLocation;
+
+ private readonly StatementCollection _ElseStatements;
+
+ ///
+ /// The conditional expression.
+ ///
+ public Expression Expression => _Expression;
+
+ ///
+ /// The location of the 'Then'.
+ ///
+ public Location ThenLocation => _ThenLocation;
+
+ ///
+ /// The If statements.
+ ///
+ public StatementCollection IfStatements => _IfStatements;
+
+ ///
+ /// The location of the 'Else', if any.
+ ///
+ public Location ElseLocation => _ElseLocation;
+
+ ///
+ /// The Else statements.
+ ///
+ public StatementCollection ElseStatements => _ElseStatements;
+
+ ///
+ /// Constructs a new parse tree for a line If statement.
+ ///
+ /// The conditional expression.
+ /// The location of the 'Then'.
+ /// The If statements.
+ /// The location of the 'Else', if any.
+ /// The Else statements.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public LineIfStatement(Expression expression, Location thenLocation, StatementCollection ifStatements, Location elseLocation, StatementCollection elseStatements, Span span, IList comments)
+ : base(TreeType.LineIfBlockStatement, span, comments)
+ {
+ if (expression == null)
+ {
+ throw new ArgumentNullException("expression");
+ }
+ SetParent(expression);
+ SetParent(ifStatements);
+ SetParent(elseStatements);
+ _Expression = expression;
+ _ThenLocation = thenLocation;
+ _IfStatements = ifStatements;
+ _ElseLocation = elseLocation;
+ _ElseStatements = elseStatements;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Expression);
+ Tree.AddChild(childList, IfStatements);
+ Tree.AddChild(childList, ElseStatements);
+ }
+}
diff --git a/AspClassic.Parser/LineTerminatorToken.cs b/AspClassic.Parser/LineTerminatorToken.cs
new file mode 100644
index 0000000..4e5ddcf
--- /dev/null
+++ b/AspClassic.Parser/LineTerminatorToken.cs
@@ -0,0 +1,16 @@
+namespace AspClassic.Parser;
+
+///
+/// A line terminator.
+///
+public sealed class LineTerminatorToken : Token
+{
+ ///
+ /// Create a new line terminator token.
+ ///
+ /// The location of the line terminator.
+ public LineTerminatorToken(Span span)
+ : base(TokenType.LineTerminator, span)
+ {
+ }
+}
diff --git a/AspClassic.Parser/LiteralExpression.cs b/AspClassic.Parser/LiteralExpression.cs
new file mode 100644
index 0000000..5301623
--- /dev/null
+++ b/AspClassic.Parser/LiteralExpression.cs
@@ -0,0 +1,20 @@
+#define DEBUG
+using System.Diagnostics;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a literal expression.
+///
+public abstract class LiteralExpression : Expression
+{
+ public sealed override bool IsConstant => true;
+
+ public abstract object Value { get; }
+
+ protected LiteralExpression(TreeType type, Span span)
+ : base(type, span)
+ {
+ Debug.Assert(type >= TreeType.StringLiteralExpression && type <= TreeType.BooleanLiteralExpression);
+ }
+}
diff --git a/AspClassic.Parser/LocalDeclarationStatement.cs b/AspClassic.Parser/LocalDeclarationStatement.cs
new file mode 100644
index 0000000..1f23138
--- /dev/null
+++ b/AspClassic.Parser/LocalDeclarationStatement.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a local declaration statement.
+///
+public sealed class LocalDeclarationStatement : Statement
+{
+ private readonly ModifierCollection _Modifiers;
+
+ private readonly VariableDeclaratorCollection _VariableDeclarators;
+
+ ///
+ /// The statement modifiers.
+ ///
+ public ModifierCollection Modifiers => _Modifiers;
+
+ ///
+ /// The variable declarators.
+ ///
+ public VariableDeclaratorCollection VariableDeclarators => _VariableDeclarators;
+
+ ///
+ /// Constructs a new parse tree for a local declaration statement.
+ ///
+ /// The statement modifiers.
+ /// The variable declarators.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public LocalDeclarationStatement(ModifierCollection modifiers, VariableDeclaratorCollection variableDeclarators, Span span, IList comments)
+ : base(TreeType.LocalDeclarationStatement, span, comments)
+ {
+ if (modifiers == null)
+ {
+ throw new ArgumentNullException("modifers");
+ }
+ if (variableDeclarators == null)
+ {
+ throw new ArgumentNullException("variableDeclarators");
+ }
+ SetParent(modifiers);
+ SetParent(variableDeclarators);
+ _Modifiers = modifiers;
+ _VariableDeclarators = variableDeclarators;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Modifiers);
+ Tree.AddChild(childList, VariableDeclarators);
+ }
+}
diff --git a/AspClassic.Parser/Location.cs b/AspClassic.Parser/Location.cs
new file mode 100644
index 0000000..687df9a
--- /dev/null
+++ b/AspClassic.Parser/Location.cs
@@ -0,0 +1,153 @@
+using Microsoft.VisualBasic.CompilerServices;
+
+namespace AspClassic.Parser;
+
+///
+/// Stores source code line and column information.
+///
+public struct Location
+{
+ private readonly int _Index;
+
+ private readonly int _Line;
+
+ private readonly int _Column;
+
+ ///
+ /// The index in the stream (0-based).
+ ///
+ public int Index => _Index;
+
+ ///
+ /// The physical line number (1-based).
+ ///
+ public int Line => _Line;
+
+ ///
+ /// The physical column number (1-based).
+ ///
+ public int Column => _Column;
+
+ ///
+ /// Whether the location is a valid location.
+ ///
+ public bool IsValid => Line != 0 && Column != 0;
+
+ ///
+ /// Constructs a new Location for a particular source location.
+ ///
+ /// The index in the stream (0-based).
+ /// The physical line number (1-based).
+ /// The physical column number (1-based).
+ public Location(int index, int line, int column)
+ {
+ this = default(Location);
+ _Index = index;
+ _Line = line;
+ _Column = column;
+ }
+
+ ///
+ /// Compares two specified Location values to see if they are equal.
+ ///
+ /// One location to compare.
+ /// The other location to compare.
+ /// True if the locations are the same, False otherwise.
+ public static bool operator ==(Location left, Location right)
+ {
+ return left.Index == right.Index;
+ }
+
+ ///
+ /// Compares two specified Location values to see if they are not equal.
+ ///
+ /// One location to compare.
+ /// The other location to compare.
+ /// True if the locations are not the same, False otherwise.
+ public static bool operator !=(Location left, Location right)
+ {
+ return left.Index != right.Index;
+ }
+
+ ///
+ /// Compares two specified Location values to see if one is before the other.
+ ///
+ /// One location to compare.
+ /// The other location to compare.
+ /// True if the first location is before the other location, False otherwise.
+ public static bool operator <(Location left, Location right)
+ {
+ return left.Index < right.Index;
+ }
+
+ ///
+ /// Compares two specified Location values to see if one is after the other.
+ ///
+ /// One location to compare.
+ /// The other location to compare.
+ /// True if the first location is after the other location, False otherwise.
+ public static bool operator >(Location left, Location right)
+ {
+ return left.Index > right.Index;
+ }
+
+ ///
+ /// Compares two specified Location values to see if one is before or the same as the other.
+ ///
+ /// One location to compare.
+ /// The other location to compare.
+ /// True if the first location is before or the same as the other location, False otherwise.
+ public static bool operator <=(Location left, Location right)
+ {
+ return left.Index <= right.Index;
+ }
+
+ ///
+ /// Compares two specified Location values to see if one is after or the same as the other.
+ ///
+ /// One location to compare.
+ /// The other location to compare.
+ /// True if the first location is after or the same as the other location, False otherwise.
+ public static bool operator >=(Location left, Location right)
+ {
+ return left.Index >= right.Index;
+ }
+
+ ///
+ /// Compares two specified Location values.
+ ///
+ /// One location to compare.
+ /// The other location to compare.
+ /// 0 if the locations are equal, -1 if the left one is less than the right one, 1 otherwise.
+ public static int Compare(Location left, Location right)
+ {
+ if (left == right)
+ {
+ return 0;
+ }
+ if (left < right)
+ {
+ return -1;
+ }
+ return 1;
+ }
+
+ public override string ToString()
+ {
+ return "(" + Conversions.ToString(Column) + "," + Conversions.ToString(Line) + ")";
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Location)
+ {
+ return this == (Location)obj;
+ }
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ return checked((int)(Index & 0xFFFFFFFFu));
+ }
+}
diff --git a/AspClassic.Parser/LoopStatement.cs b/AspClassic.Parser/LoopStatement.cs
new file mode 100644
index 0000000..b2e9221
--- /dev/null
+++ b/AspClassic.Parser/LoopStatement.cs
@@ -0,0 +1,52 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a Loop statement.
+///
+public sealed class LoopStatement : Statement
+{
+ private readonly bool _IsWhile;
+
+ private readonly Location _WhileOrUntilLocation;
+
+ private readonly Expression _Expression;
+
+ ///
+ /// Whether the Loop has a While or Until.
+ ///
+ public bool IsWhile => _IsWhile;
+
+ ///
+ /// The location of the While or Until, if any.
+ ///
+ public Location WhileOrUntilLocation => _WhileOrUntilLocation;
+
+ ///
+ /// The loop expression, if any.
+ ///
+ public Expression Expression => _Expression;
+
+ ///
+ /// Constructs a parse tree for a Loop statement.
+ ///
+ /// The loop expression, if any.
+ /// WHether the Loop has a While or Until.
+ /// The location of the While or Until, if any.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public LoopStatement(Expression expression, bool isWhile, Location whileOrUntilLocation, Span span, IList comments)
+ : base(TreeType.LoopStatement, span, comments)
+ {
+ SetParent(expression);
+ _Expression = expression;
+ _IsWhile = isWhile;
+ _WhileOrUntilLocation = whileOrUntilLocation;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Expression);
+ }
+}
diff --git a/AspClassic.Parser/MethodDeclaration.cs b/AspClassic.Parser/MethodDeclaration.cs
new file mode 100644
index 0000000..8528232
--- /dev/null
+++ b/AspClassic.Parser/MethodDeclaration.cs
@@ -0,0 +1,62 @@
+#define DEBUG
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a Sub, Function or constructor declaration.
+///
+public abstract class MethodDeclaration : SignatureDeclaration
+{
+ private readonly NameCollection _ImplementsList;
+
+ private readonly NameCollection _HandlesList;
+
+ private readonly StatementCollection _Statements;
+
+ private readonly EndBlockDeclaration _EndDeclaration;
+
+ ///
+ /// The list of implemented members.
+ ///
+ public NameCollection ImplementsList => _ImplementsList;
+
+ ///
+ /// The events that the declaration handles.
+ ///
+ public NameCollection HandlesList => _HandlesList;
+
+ ///
+ /// The statements in the declaration.
+ ///
+ public StatementCollection Statements => _Statements;
+
+ ///
+ /// The end block declaration, if any.
+ ///
+ public EndBlockDeclaration EndDeclaration => _EndDeclaration;
+
+ protected MethodDeclaration(TreeType type, AttributeBlockCollection attributes, ModifierCollection modifiers, Location keywordLocation, SimpleName name, TypeParameterCollection typeParameters, ParameterCollection parameters, Location asLocation, AttributeBlockCollection resultTypeAttributes, TypeName resultType, NameCollection implementsList, NameCollection handlesList, StatementCollection statements, EndBlockDeclaration endDeclaration, Span span, IList comments)
+ : base(type, attributes, modifiers, keywordLocation, name, typeParameters, parameters, asLocation, resultTypeAttributes, resultType, span, comments)
+ {
+ Debug.Assert(type == TreeType.SubDeclaration || type == TreeType.FunctionDeclaration || type == TreeType.ConstructorDeclaration || type == TreeType.OperatorDeclaration);
+ SetParent(statements);
+ SetParent(endDeclaration);
+ SetParent(handlesList);
+ SetParent(implementsList);
+ _ImplementsList = implementsList;
+ _HandlesList = handlesList;
+ _Statements = statements;
+ _EndDeclaration = endDeclaration;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, ImplementsList);
+ Tree.AddChild(childList, HandlesList);
+ Tree.AddChild(childList, Statements);
+ Tree.AddChild(childList, EndDeclaration);
+ }
+}
diff --git a/AspClassic.Parser/MidAssignmentStatement.cs b/AspClassic.Parser/MidAssignmentStatement.cs
new file mode 100644
index 0000000..9bb384c
--- /dev/null
+++ b/AspClassic.Parser/MidAssignmentStatement.cs
@@ -0,0 +1,133 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a Mid assignment statement.
+///
+public sealed class MidAssignmentStatement : Statement
+{
+ private readonly bool _HasTypeCharacter;
+
+ private readonly Location _LeftParenthesisLocation;
+
+ private readonly Expression _TargetExpression;
+
+ private readonly Location _StartCommaLocation;
+
+ private readonly Expression _StartExpression;
+
+ private readonly Location _LengthCommaLocation;
+
+ private readonly Expression _LengthExpression;
+
+ private readonly Location _RightParenthesisLocation;
+
+ private readonly Location _OperatorLocation;
+
+ private readonly Expression _SourceExpression;
+
+ ///
+ /// Whether the Mid identifier had a type character.
+ ///
+ public bool HasTypeCharacter => _HasTypeCharacter;
+
+ ///
+ /// The location of the left parenthesis.
+ ///
+ public Location LeftParenthesisLocation => _LeftParenthesisLocation;
+
+ ///
+ /// The target of the assignment.
+ ///
+ public Expression TargetExpression => _TargetExpression;
+
+ ///
+ /// The location of the comma before the start expression.
+ ///
+ public Location StartCommaLocation => _StartCommaLocation;
+
+ ///
+ /// The expression representing the start of the string to replace.
+ ///
+ public Expression StartExpression => _StartExpression;
+
+ ///
+ /// The location of the comma before the length expression, if any.
+ ///
+ public Location LengthCommaLocation => _LengthCommaLocation;
+
+ ///
+ /// The expression representing the length of the string to replace, if any.
+ ///
+ public Expression LengthExpression => _LengthExpression;
+
+ ///
+ /// The right parenthesis location.
+ ///
+ public Location RightParenthesisLocation => _RightParenthesisLocation;
+
+ ///
+ /// The location of the operator.
+ ///
+ public Location OperatorLocation => _OperatorLocation;
+
+ ///
+ /// The source of the assignment.
+ ///
+ public Expression SourceExpression => _SourceExpression;
+
+ ///
+ /// Constructs a new parse tree for an assignment statement.
+ ///
+ /// Whether the Mid identifier has a type character.
+ /// The location of the left parenthesis.
+ /// The target of the assignment.
+ /// The location of the comma before the start expression.
+ /// The expression representing the start of the string to replace.
+ /// The location of the comma before the length expression, if any.
+ /// The expression representing the length of the string to replace, if any.
+ /// The location of the operator.
+ /// The source of the assignment.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public MidAssignmentStatement(bool hasTypeCharacter, Location leftParenthesisLocation, Expression targetExpression, Location startCommaLocation, Expression startExpression, Location lengthCommaLocation, Expression lengthExpression, Location rightParenthesisLocation, Location operatorLocation, Expression sourceExpression, Span span, IList comments)
+ : base(TreeType.MidAssignmentStatement, span, comments)
+ {
+ if (targetExpression == null)
+ {
+ throw new ArgumentNullException("targetExpression");
+ }
+ if (startExpression == null)
+ {
+ throw new ArgumentNullException("startExpression");
+ }
+ if (sourceExpression == null)
+ {
+ throw new ArgumentNullException("sourceExpression");
+ }
+ SetParent(targetExpression);
+ SetParent(startExpression);
+ SetParent(lengthExpression);
+ SetParent(sourceExpression);
+ _HasTypeCharacter = hasTypeCharacter;
+ _LeftParenthesisLocation = leftParenthesisLocation;
+ _TargetExpression = targetExpression;
+ _StartCommaLocation = startCommaLocation;
+ _StartExpression = startExpression;
+ _LengthCommaLocation = lengthCommaLocation;
+ _LengthExpression = lengthExpression;
+ _RightParenthesisLocation = rightParenthesisLocation;
+ _OperatorLocation = operatorLocation;
+ _SourceExpression = sourceExpression;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, TargetExpression);
+ Tree.AddChild(childList, StartExpression);
+ Tree.AddChild(childList, LengthExpression);
+ Tree.AddChild(childList, SourceExpression);
+ }
+}
diff --git a/AspClassic.Parser/ModifiedDeclaration.cs b/AspClassic.Parser/ModifiedDeclaration.cs
new file mode 100644
index 0000000..757ac51
--- /dev/null
+++ b/AspClassic.Parser/ModifiedDeclaration.cs
@@ -0,0 +1,38 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a declaration with modifiers.
+///
+public abstract class ModifiedDeclaration : Declaration
+{
+ private readonly AttributeBlockCollection _Attributes;
+
+ private readonly ModifierCollection _Modifiers;
+
+ ///
+ /// The attributes on the declaration.
+ ///
+ public AttributeBlockCollection Attributes => _Attributes;
+
+ ///
+ /// The modifiers on the declaration.
+ ///
+ public ModifierCollection Modifiers => _Modifiers;
+
+ protected ModifiedDeclaration(TreeType type, AttributeBlockCollection attributes, ModifierCollection modifiers, Span span, IList comments)
+ : base(type, span, comments)
+ {
+ SetParent(attributes);
+ SetParent(modifiers);
+ _Attributes = attributes;
+ _Modifiers = modifiers;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Attributes);
+ Tree.AddChild(childList, Modifiers);
+ }
+}
diff --git a/AspClassic.Parser/Modifier.cs b/AspClassic.Parser/Modifier.cs
new file mode 100644
index 0000000..03bb000
--- /dev/null
+++ b/AspClassic.Parser/Modifier.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a declaration modifier.
+///
+public sealed class Modifier : Tree
+{
+ private readonly ModifierTypes _ModifierType;
+
+ ///
+ /// The type of the modifier.
+ ///
+ public ModifierTypes ModifierType => _ModifierType;
+
+ ///
+ /// Constructs a new modifier parse tree.
+ ///
+ /// The type of the modifier.
+ /// The location of the parse tree.
+ public Modifier(ModifierTypes modifierType, Span span)
+ : base(TreeType.Modifier, span)
+ {
+ if ((modifierType & checked(modifierType - 1)) != 0 || modifierType < ModifierTypes.None || modifierType > ModifierTypes.Narrowing)
+ {
+ throw new ArgumentOutOfRangeException("modifierType");
+ }
+ _ModifierType = modifierType;
+ }
+}
diff --git a/AspClassic.Parser/ModifierCollection.cs b/AspClassic.Parser/ModifierCollection.cs
new file mode 100644
index 0000000..4ea272f
--- /dev/null
+++ b/AspClassic.Parser/ModifierCollection.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A read-only collection of modifiers.
+///
+public sealed class ModifierCollection : TreeCollection
+{
+ private readonly ModifierTypes _ModifierTypes;
+
+ ///
+ /// All the modifiers in the collection.
+ ///
+ public ModifierTypes ModifierTypes => _ModifierTypes;
+
+ ///
+ /// Constructs a collection of modifiers.
+ ///
+ /// The modifiers in the collection.
+ /// The location of the parse tree.
+ public ModifierCollection(IList modifiers, Span span)
+ : base(TreeType.ModifierCollection, modifiers, span)
+ {
+ if (modifiers == null || modifiers.Count == 0)
+ {
+ throw new ArgumentException("ModifierCollection cannot be empty.");
+ }
+ foreach (Modifier Modifier in modifiers)
+ {
+ _ModifierTypes |= Modifier.ModifierType;
+ }
+ }
+}
diff --git a/AspClassic.Parser/ModifierTypes.cs b/AspClassic.Parser/ModifierTypes.cs
new file mode 100644
index 0000000..79ec983
--- /dev/null
+++ b/AspClassic.Parser/ModifierTypes.cs
@@ -0,0 +1,40 @@
+using System;
+
+namespace AspClassic.Parser;
+
+///
+/// The type of a parse tree modifier.
+///
+[Flags]
+public enum ModifierTypes
+{
+ None = 0,
+ Public = 1,
+ Private = 2,
+ Protected = 4,
+ Friend = 8,
+ AccessModifiers = 0xF,
+ Static = 0x10,
+ Shared = 0x20,
+ Shadows = 0x40,
+ Overloads = 0x80,
+ MustInherit = 0x100,
+ NotInheritable = 0x200,
+ Overrides = 0x400,
+ NotOverridable = 0x800,
+ Overridable = 0x1000,
+ MustOverride = 0x2000,
+ ReadOnly = 0x4000,
+ WriteOnly = 0x8000,
+ Dim = 0x10000,
+ Const = 0x20000,
+ Default = 0x40000,
+ WithEvents = 0x80000,
+ ByVal = 0x100000,
+ ByRef = 0x200000,
+ Optional = 0x400000,
+ ParamArray = 0x800000,
+ Partial = 0x1000000,
+ Widening = 0x2000000,
+ Narrowing = 0x4000000
+}
diff --git a/AspClassic.Parser/ModuleDeclaration.cs b/AspClassic.Parser/ModuleDeclaration.cs
new file mode 100644
index 0000000..d24eb1d
--- /dev/null
+++ b/AspClassic.Parser/ModuleDeclaration.cs
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a Module declaration.
+///
+public sealed class ModuleDeclaration : BlockDeclaration
+{
+ ///
+ /// Constructs a new parse tree for a Module declaration.
+ ///
+ /// The attributes for the parse tree.
+ /// The modifiers for the parse tree.
+ /// The location of the keyword.
+ /// The name of the declaration.
+ /// The declarations in the block.
+ /// The end block declaration, if any.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public ModuleDeclaration(AttributeBlockCollection attributes, ModifierCollection modifiers, Location keywordLocation, SimpleName name, DeclarationCollection declarations, EndBlockDeclaration endStatement, Span span, IList comments)
+ : base(TreeType.ModuleDeclaration, attributes, modifiers, keywordLocation, name, declarations, endStatement, span, comments)
+ {
+ }
+}
diff --git a/AspClassic.Parser/Name.cs b/AspClassic.Parser/Name.cs
new file mode 100644
index 0000000..3902716
--- /dev/null
+++ b/AspClassic.Parser/Name.cs
@@ -0,0 +1,16 @@
+#define DEBUG
+using System.Diagnostics;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a name.
+///
+public abstract class Name : Tree
+{
+ protected Name(TreeType type, Span span)
+ : base(type, span)
+ {
+ Debug.Assert(type >= TreeType.SimpleName && type <= TreeType.MyBaseName);
+ }
+}
diff --git a/AspClassic.Parser/NameCollection.cs b/AspClassic.Parser/NameCollection.cs
new file mode 100644
index 0000000..7d11605
--- /dev/null
+++ b/AspClassic.Parser/NameCollection.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A read-only collection of names.
+///
+public sealed class NameCollection : CommaDelimitedTreeCollection
+{
+ ///
+ /// Constructs a new name collection.
+ ///
+ /// The names in the collection.
+ /// The locations of the commas in the collection.
+ /// The location of the parse tree.
+ public NameCollection(IList names, IList commaLocations, Span span)
+ : base(TreeType.NameCollection, names, commaLocations, span)
+ {
+ if (names == null || names.Count == 0)
+ {
+ throw new ArgumentException("NameCollection cannot be empty.");
+ }
+ }
+}
diff --git a/AspClassic.Parser/NameImport.cs b/AspClassic.Parser/NameImport.cs
new file mode 100644
index 0000000..dd4076c
--- /dev/null
+++ b/AspClassic.Parser/NameImport.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an Imports statement for a name.
+///
+public sealed class NameImport : Import
+{
+ private readonly TypeName _TypeName;
+
+ ///
+ /// The imported name.
+ ///
+ public TypeName TypeName => _TypeName;
+
+ ///
+ /// Constructs a new name import parse tree.
+ ///
+ /// The name to import.
+ /// The location of the parse tree.
+ public NameImport(TypeName typeName, Span span)
+ : base(TreeType.NameImport, span)
+ {
+ if (typeName == null)
+ {
+ throw new ArgumentNullException("typeName");
+ }
+ SetParent(typeName);
+ _TypeName = typeName;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, TypeName);
+ }
+}
diff --git a/AspClassic.Parser/NamedTypeName.cs b/AspClassic.Parser/NamedTypeName.cs
new file mode 100644
index 0000000..5b0d414
--- /dev/null
+++ b/AspClassic.Parser/NamedTypeName.cs
@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a named type.
+///
+public class NamedTypeName : TypeName
+{
+ private readonly Name _Name;
+
+ ///
+ /// The name of the type.
+ ///
+ public Name Name => _Name;
+
+ public override bool IsBad => Name.IsBad;
+
+ ///
+ /// Creates a new bad named type.
+ ///
+ /// The location of the bad named type.
+ /// A bad named type.
+ public static NamedTypeName GetBadNamedType(Span span)
+ {
+ return new NamedTypeName(SimpleName.GetBadSimpleName(span), span);
+ }
+
+ ///
+ /// Constructs a new named type parse tree.
+ ///
+ /// The name of the type.
+ /// The location of the parse tree.
+ public NamedTypeName(Name name, Span span)
+ : this(TreeType.NamedType, name, span)
+ {
+ }
+
+ protected NamedTypeName(TreeType treeType, Name name, Span span)
+ : base(treeType, span)
+ {
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+ SetParent(name);
+ _Name = name;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Name);
+ }
+}
diff --git a/AspClassic.Parser/NamespaceDeclaration.cs b/AspClassic.Parser/NamespaceDeclaration.cs
new file mode 100644
index 0000000..42d6de6
--- /dev/null
+++ b/AspClassic.Parser/NamespaceDeclaration.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a namespace declaration.
+///
+public sealed class NamespaceDeclaration : ModifiedDeclaration
+{
+ private readonly Location _NamespaceLocation;
+
+ private readonly Name _Name;
+
+ private readonly DeclarationCollection _Declarations;
+
+ private readonly EndBlockDeclaration _EndDeclaration;
+
+ ///
+ /// The location of 'Namespace'.
+ ///
+ public Location NamespaceLocation => _NamespaceLocation;
+
+ ///
+ /// The name of the namespace.
+ ///
+ public Name Name => _Name;
+
+ ///
+ /// The declarations in the namespace.
+ ///
+ public DeclarationCollection Declarations => _Declarations;
+
+ ///
+ /// The End Namespace declaration, if any.
+ ///
+ public EndBlockDeclaration EndDeclaration => _EndDeclaration;
+
+ ///
+ /// Constructs a parse tree for a namespace declaration.
+ ///
+ /// The attributes on the declaration.
+ /// The modifiers on the declaration.
+ /// The location of 'Namespace'.
+ /// The name of the namespace.
+ /// The declarations in the namespace.
+ /// The End Namespace statement, if any.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public NamespaceDeclaration(AttributeBlockCollection attributes, ModifierCollection modifiers, Location namespaceLocation, Name name, DeclarationCollection declarations, EndBlockDeclaration endDeclaration, Span span, IList comments)
+ : base(TreeType.NamespaceDeclaration, attributes, modifiers, span, comments)
+ {
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+ SetParent(name);
+ SetParent(declarations);
+ SetParent(endDeclaration);
+ _NamespaceLocation = namespaceLocation;
+ _Name = name;
+ _Declarations = declarations;
+ _EndDeclaration = endDeclaration;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ base.GetChildTrees(childList);
+ Tree.AddChild(childList, Name);
+ Tree.AddChild(childList, Declarations);
+ Tree.AddChild(childList, EndDeclaration);
+ }
+}
diff --git a/AspClassic.Parser/NewAggregateExpression.cs b/AspClassic.Parser/NewAggregateExpression.cs
new file mode 100644
index 0000000..08ededd
--- /dev/null
+++ b/AspClassic.Parser/NewAggregateExpression.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a New array expression.
+///
+public sealed class NewAggregateExpression : Expression
+{
+ private readonly ArrayTypeName _Target;
+
+ private readonly AggregateInitializer _Initializer;
+
+ ///
+ /// The target array type to create.
+ ///
+ public ArrayTypeName Target => _Target;
+
+ ///
+ /// The initializer for the array.
+ ///
+ public AggregateInitializer Initializer => _Initializer;
+
+ ///
+ /// The constructor for a New array expression parse tree.
+ ///
+ /// The target array type to create.
+ /// The initializer for the array.
+ /// The location of the parse tree.
+ public NewAggregateExpression(ArrayTypeName target, AggregateInitializer initializer, Span span)
+ : base(TreeType.NewAggregateExpression, span)
+ {
+ if (target == null)
+ {
+ throw new ArgumentNullException("target");
+ }
+ if (initializer == null)
+ {
+ throw new ArgumentNullException("initializer");
+ }
+ SetParent(target);
+ SetParent(initializer);
+ _Target = target;
+ _Initializer = initializer;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Target);
+ Tree.AddChild(childList, Initializer);
+ }
+}
diff --git a/AspClassic.Parser/NewExpression.cs b/AspClassic.Parser/NewExpression.cs
new file mode 100644
index 0000000..ca91702
--- /dev/null
+++ b/AspClassic.Parser/NewExpression.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a New expression.
+///
+public sealed class NewExpression : Expression
+{
+ private readonly TypeName _Target;
+
+ private readonly ArgumentCollection _Arguments;
+
+ ///
+ /// The target type to create.
+ ///
+ public TypeName Target => _Target;
+
+ ///
+ /// The arguments to the constructor.
+ ///
+ public ArgumentCollection Arguments => _Arguments;
+
+ ///
+ /// Constructs a new parse tree for a New expression.
+ ///
+ /// The target type to create.
+ /// The arguments to the constructor.
+ /// The location of the parse tree.
+ public NewExpression(TypeName target, ArgumentCollection arguments, Span span)
+ : base(TreeType.NewExpression, span)
+ {
+ if (target == null)
+ {
+ throw new ArgumentNullException("target");
+ }
+ SetParent(target);
+ SetParent(arguments);
+ _Target = target;
+ _Arguments = arguments;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Target);
+ Tree.AddChild(childList, Arguments);
+ }
+}
diff --git a/AspClassic.Parser/NextStatement.cs b/AspClassic.Parser/NextStatement.cs
new file mode 100644
index 0000000..c12a358
--- /dev/null
+++ b/AspClassic.Parser/NextStatement.cs
@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a Next statement.
+///
+public sealed class NextStatement : Statement
+{
+ private readonly ExpressionCollection _Variables;
+
+ ///
+ /// The loop control variables.
+ ///
+ public ExpressionCollection Variables => _Variables;
+
+ ///
+ /// Constructs a parse tree for a Next statement.
+ ///
+ /// The loop control variables.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public NextStatement(ExpressionCollection variables, Span span, IList comments)
+ : base(TreeType.NextStatement, span, comments)
+ {
+ SetParent(variables);
+ _Variables = variables;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Variables);
+ }
+}
diff --git a/AspClassic.Parser/NothingExpression.cs b/AspClassic.Parser/NothingExpression.cs
new file mode 100644
index 0000000..efe3207
--- /dev/null
+++ b/AspClassic.Parser/NothingExpression.cs
@@ -0,0 +1,18 @@
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for Nothing.
+///
+public sealed class NothingExpression : Expression
+{
+ public override bool IsConstant => true;
+
+ ///
+ /// Constructs a new parse tree for Nothing.
+ ///
+ /// The location of the parse tree.
+ public NothingExpression(Span span)
+ : base(TreeType.NothingExpression, span)
+ {
+ }
+}
diff --git a/AspClassic.Parser/OnErrorStatement.cs b/AspClassic.Parser/OnErrorStatement.cs
new file mode 100644
index 0000000..63d3476
--- /dev/null
+++ b/AspClassic.Parser/OnErrorStatement.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an On Error statement.
+///
+public sealed class OnErrorStatement : LabelReferenceStatement
+{
+ private readonly OnErrorType _OnErrorType;
+
+ private readonly Location _ErrorLocation;
+
+ private readonly Location _ResumeOrGoToLocation;
+
+ private readonly Location _NextOrZeroOrMinusLocation;
+
+ private readonly Location _OneLocation;
+
+ ///
+ /// The type of On Error statement.
+ ///
+ public OnErrorType OnErrorType => _OnErrorType;
+
+ ///
+ /// The location of the 'Error'.
+ ///
+ public Location ErrorLocation => _ErrorLocation;
+
+ ///
+ /// The location of the 'Resume' or 'GoTo'.
+ ///
+ public Location ResumeOrGoToLocation => _ResumeOrGoToLocation;
+
+ ///
+ /// The location of the 'Next', '0' or '-', if any.
+ ///
+ public Location NextOrZeroOrMinusLocation => _NextOrZeroOrMinusLocation;
+
+ ///
+ /// The location of the '1', if any.
+ ///
+ public Location OneLocation => _OneLocation;
+
+ ///
+ /// Constructs a parse tree for an On Error statement.
+ ///
+ /// The type of the On Error statement.
+ /// The location of the 'Error'.
+ /// The location of the 'Resume' or 'GoTo'.
+ /// The location of the 'Next', '0' or '-', if any.
+ /// The location of the '1', if any.
+ /// The label to branch to, if any.
+ /// Whether the label is a line number.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public OnErrorStatement(OnErrorType onErrorType, Location errorLocation, Location resumeOrGoToLocation, Location nextOrZeroOrMinusLocation, Location oneLocation, SimpleName name, bool isLineNumber, Span span, IList comments)
+ : base(TreeType.OnErrorStatement, name, isLineNumber, span, comments)
+ {
+ if (onErrorType < OnErrorType.Bad || onErrorType > OnErrorType.Label)
+ {
+ throw new ArgumentOutOfRangeException("onErrorType");
+ }
+ _OnErrorType = onErrorType;
+ _ErrorLocation = errorLocation;
+ _ResumeOrGoToLocation = resumeOrGoToLocation;
+ _NextOrZeroOrMinusLocation = nextOrZeroOrMinusLocation;
+ _OneLocation = oneLocation;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ if (OnErrorType == OnErrorType.Label)
+ {
+ base.GetChildTrees(childList);
+ }
+ }
+}
diff --git a/AspClassic.Parser/OnErrorType.cs b/AspClassic.Parser/OnErrorType.cs
new file mode 100644
index 0000000..2de6e38
--- /dev/null
+++ b/AspClassic.Parser/OnErrorType.cs
@@ -0,0 +1,13 @@
+namespace AspClassic.Parser;
+
+///
+/// The type of an On Error statement.
+///
+public enum OnErrorType
+{
+ Bad,
+ Next,
+ Zero,
+ MinusOne,
+ Label
+}
diff --git a/AspClassic.Parser/OperatorDeclaration.cs b/AspClassic.Parser/OperatorDeclaration.cs
new file mode 100644
index 0000000..d018060
--- /dev/null
+++ b/AspClassic.Parser/OperatorDeclaration.cs
@@ -0,0 +1,37 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an overloaded operator declaration.
+///
+public sealed class OperatorDeclaration : MethodDeclaration
+{
+ private readonly Token _OperatorToken;
+
+ ///
+ /// The operator being overloaded.
+ ///
+ public Token OperatorToken => _OperatorToken;
+
+ ///
+ /// Creates a new parse tree for an overloaded operator declaration.
+ ///
+ /// The attributes for the parse tree.
+ /// The modifiers for the parse tree.
+ /// The location of the keyword.
+ /// The operator being overloaded.
+ /// The parameters of the declaration.
+ /// The location of the 'As', if any.
+ /// The attributes on the result type, if any.
+ /// The result type, if any.
+ /// The statements in the declaration.
+ /// The end block declaration, if any.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public OperatorDeclaration(AttributeBlockCollection attributes, ModifierCollection modifiers, Location keywordLocation, Token operatorToken, ParameterCollection parameters, Location asLocation, AttributeBlockCollection resultTypeAttributes, TypeName resultType, StatementCollection statements, EndBlockDeclaration endDeclaration, Span span, IList comments)
+ : base(TreeType.OperatorDeclaration, attributes, modifiers, keywordLocation, null, null, parameters, asLocation, resultTypeAttributes, resultType, null, null, statements, endDeclaration, span, comments)
+ {
+ _OperatorToken = operatorToken;
+ }
+}
diff --git a/AspClassic.Parser/OperatorType.cs b/AspClassic.Parser/OperatorType.cs
new file mode 100644
index 0000000..051989d
--- /dev/null
+++ b/AspClassic.Parser/OperatorType.cs
@@ -0,0 +1,37 @@
+namespace AspClassic.Parser;
+
+///
+/// The type of a unary operator expression.
+///
+public enum OperatorType
+{
+ None,
+ UnaryPlus,
+ Negate,
+ Not,
+ Plus,
+ Minus,
+ Multiply,
+ Divide,
+ IntegralDivide,
+ Concatenate,
+ ShiftLeft,
+ ShiftRight,
+ Power,
+ Modulus,
+ Or,
+ OrElse,
+ And,
+ AndAlso,
+ Xor,
+ Like,
+ Is,
+ IsNot,
+ To,
+ Equals,
+ NotEquals,
+ LessThan,
+ LessThanEquals,
+ GreaterThan,
+ GreaterThanEquals
+}
diff --git a/AspClassic.Parser/OptionDeclaration.cs b/AspClassic.Parser/OptionDeclaration.cs
new file mode 100644
index 0000000..4e5cf23
--- /dev/null
+++ b/AspClassic.Parser/OptionDeclaration.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for an Option declaration.
+///
+public sealed class OptionDeclaration : Declaration
+{
+ private readonly OptionType _OptionType;
+
+ private readonly Location _OptionTypeLocation;
+
+ private readonly Location _OptionArgumentLocation;
+
+ ///
+ /// The type of Option statement.
+ ///
+ public OptionType OptionType => _OptionType;
+
+ ///
+ /// The location of the Option type (e.g. "Strict"), if any.
+ ///
+ public Location OptionTypeLocation => _OptionTypeLocation;
+
+ ///
+ /// The location of the Option argument (e.g. "On"), if any.
+ ///
+ public Location OptionArgumentLocation => _OptionArgumentLocation;
+
+ ///
+ /// Constructs a new parse tree for an Option declaration.
+ ///
+ /// The type of the Option declaration.
+ /// The location of the Option type, if any.
+ /// The location of the Option argument, if any.
+ /// The location of the parse tree.
+ /// The comments for the parse tree.
+ public OptionDeclaration(OptionType optionType, Location optionTypeLocation, Location optionArgumentLocation, Span span, IList comments)
+ : base(TreeType.OptionDeclaration, span, comments)
+ {
+ if (optionType < OptionType.SyntaxError || optionType > OptionType.CompareText)
+ {
+ throw new ArgumentOutOfRangeException("optionType");
+ }
+ _OptionType = optionType;
+ _OptionTypeLocation = optionTypeLocation;
+ _OptionArgumentLocation = optionArgumentLocation;
+ }
+}
diff --git a/AspClassic.Parser/OptionType.cs b/AspClassic.Parser/OptionType.cs
new file mode 100644
index 0000000..9e6e479
--- /dev/null
+++ b/AspClassic.Parser/OptionType.cs
@@ -0,0 +1,17 @@
+namespace AspClassic.Parser;
+
+///
+/// The type of an Option declaration.
+///
+public enum OptionType
+{
+ SyntaxError,
+ Explicit,
+ ExplicitOn,
+ ExplicitOff,
+ Strict,
+ StrictOn,
+ StrictOff,
+ CompareBinary,
+ CompareText
+}
diff --git a/AspClassic.Parser/Parameter.cs b/AspClassic.Parser/Parameter.cs
new file mode 100644
index 0000000..89e005f
--- /dev/null
+++ b/AspClassic.Parser/Parameter.cs
@@ -0,0 +1,100 @@
+using System;
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a parameter.
+///
+public sealed class Parameter : Tree
+{
+ private readonly AttributeBlockCollection _Attributes;
+
+ private readonly ModifierCollection _Modifiers;
+
+ private readonly VariableName _VariableName;
+
+ private readonly Location _AsLocation;
+
+ private readonly TypeName _ParameterType;
+
+ private readonly Location _EqualsLocation;
+
+ private readonly Initializer _Initializer;
+
+ ///
+ /// The attributes on the parameter.
+ ///
+ public AttributeBlockCollection Attributes => _Attributes;
+
+ ///
+ /// The modifiers on the parameter.
+ ///
+ public ModifierCollection Modifiers => _Modifiers;
+
+ ///
+ /// The name of the parameter.
+ ///
+ public VariableName VariableName => _VariableName;
+
+ ///
+ /// The location of the 'As', if any.
+ ///
+ public Location AsLocation => _AsLocation;
+
+ ///
+ /// The parameter type, if any.
+ ///
+ public TypeName ParameterType => _ParameterType;
+
+ ///
+ /// The location of the '=', if any.
+ ///
+ public Location EqualsLocation => _EqualsLocation;
+
+ ///
+ /// The initializer for the parameter, if any.
+ ///
+ public Initializer Initializer => _Initializer;
+
+ ///
+ /// Constructs a new parameter parse tree.
+ ///
+ /// The attributes on the parameter.
+ /// The modifiers on the parameter.
+ /// The name of the parameter.
+ /// The location of the 'As'.
+ /// The type of the parameter. Can be Nothing.
+ /// The location of the '='.
+ /// The initializer for the parameter. Can be Nothing.
+ /// The location of the parse tree.
+ public Parameter(AttributeBlockCollection attributes, ModifierCollection modifiers, VariableName variableName, Location asLocation, TypeName parameterType, Location equalsLocation, Initializer initializer, Span span)
+ : base(TreeType.Parameter, span)
+ {
+ if (variableName == null)
+ {
+ throw new ArgumentNullException("variableName");
+ }
+ SetParent(attributes);
+ SetParent(modifiers);
+ SetParent(variableName);
+ SetParent(parameterType);
+ SetParent(initializer);
+ _Attributes = attributes;
+ _Modifiers = modifiers;
+ _VariableName = variableName;
+ _AsLocation = asLocation;
+ _ParameterType = parameterType;
+ _EqualsLocation = equalsLocation;
+ _Initializer = initializer;
+ }
+
+ protected override void GetChildTrees(IList childList)
+ {
+ Tree.AddChild(childList, Attributes);
+ Tree.AddChild(childList, Modifiers);
+ Tree.AddChild(childList, VariableName);
+ Tree.AddChild(childList, ParameterType);
+ Tree.AddChild(childList, Initializer);
+ }
+}
diff --git a/AspClassic.Parser/ParameterCollection.cs b/AspClassic.Parser/ParameterCollection.cs
new file mode 100644
index 0000000..f20443e
--- /dev/null
+++ b/AspClassic.Parser/ParameterCollection.cs
@@ -0,0 +1,29 @@
+using System.Collections.Generic;
+
+namespace AspClassic.Parser;
+
+///
+/// A collection of parameters.
+///
+public sealed class ParameterCollection : CommaDelimitedTreeCollection
+{
+ private readonly Location _RightParenthesisLocation;
+
+ ///
+ /// The location of the ')'.
+ ///
+ public Location RightParenthesisLocation => _RightParenthesisLocation;
+
+ ///
+ /// Constructs a new collection of parameters.
+ ///
+ /// The parameters in the collection
+ /// The locations of the commas.
+ /// The location of the right parenthesis.
+ /// The location of the parse tree.
+ public ParameterCollection(IList parameters, IList commaLocations, Location rightParenthesisLocation, Span span)
+ : base(TreeType.ParameterCollection, parameters, commaLocations, span)
+ {
+ _RightParenthesisLocation = rightParenthesisLocation;
+ }
+}
diff --git a/AspClassic.Parser/ParentheticalExpression.cs b/AspClassic.Parser/ParentheticalExpression.cs
new file mode 100644
index 0000000..a7c48ae
--- /dev/null
+++ b/AspClassic.Parser/ParentheticalExpression.cs
@@ -0,0 +1,26 @@
+namespace AspClassic.Parser;
+
+///
+/// A parse tree for a parenthesized expression.
+///
+public sealed class ParentheticalExpression : UnaryExpression
+{
+ private readonly Location _RightParenthesisLocation;
+
+ ///
+ /// The location of the ')'.
+ ///
+ public Location RightParenthesisLocation => _RightParenthesisLocation;
+
+ ///
+ /// Constructs a new parenthesized expression parse tree.
+ ///
+ /// The operand of the expression.
+ /// The location of the ')'.
+ /// The location of the parse tree.
+ public ParentheticalExpression(Expression operand, Location rightParenthesisLocation, Span span)
+ : base(TreeType.ParentheticalExpression, operand, span)
+ {
+ _RightParenthesisLocation = rightParenthesisLocation;
+ }
+}
diff --git a/AspClassic.Parser/Parser.cs b/AspClassic.Parser/Parser.cs
new file mode 100644
index 0000000..9f60dc3
--- /dev/null
+++ b/AspClassic.Parser/Parser.cs
@@ -0,0 +1,5769 @@
+#define DEBUG
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using Microsoft.VisualBasic.CompilerServices;
+
+namespace AspClassic.Parser;
+
+///
+/// A parser for the Visual Basic .NET language based on the grammar
+/// documented in the Language Specification.
+///
+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 ErrorTable;
+
+ private IList ExternalLineMappings;
+
+ private IList SourceRegions;
+
+ private IList ExternalChecksums;
+
+ private IDictionary ConditionalCompilationConstants;
+
+ private bool ErrorInConstruct;
+
+ private bool AtBeginningOfLine;
+
+ private bool Preprocess;
+
+ private bool CanContinueWithoutLineTerminator;
+
+ private Stack BlockContextStack;
+
+ private ExternalSourceContext CurrentExternalSourceContext;
+
+ private Stack RegionContextStack;
+
+ private Stack ConditionalCompilationContextStack;
+
+ private bool Disposed;
+
+ public Parser()
+ {
+ BlockContextStack = new Stack();
+ RegionContextStack = new Stack();
+ ConditionalCompilationContextStack = new Stack();
+ Disposed = false;
+ }
+
+ ///
+ /// Disposes the parser.
+ ///
+ 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 ParseTrailingComments()
+ {
+ List Comments = new List();
+ 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 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 TypeArguments = new List();
+ List CommaLocations = new List();
+ 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 CommaLocations = new List();
+ Debug.Assert(Peek().Type == TokenType.LeftParenthesis);
+ if (startType == null)
+ {
+ startType = Peek();
+ }
+ Read();
+ List 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();
+ 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 Initializers = new List();
+ List CommaLocations = new List();
+ 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 Arguments = new List();
+ List CommaLocations = new List();
+ 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 Expressions = new List();
+ List CommaLocations = new List();
+ 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 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 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 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 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 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 CatchBlocks = new List();
+ StatementCollection CatchBlockList = null;
+ FinallyBlockStatement FinallyBlock = null;
+ List 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 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 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 CommaLocations = new List();
+ List Cases = new List();
+ 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 CaseBlocks = new List();
+ StatementCollection CaseBlockList = null;
+ CaseElseBlockStatement CaseElseBlockStatement = null;
+ List 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 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 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 ElseIfBlocks = new List();
+ StatementCollection ElseIfBlockList = null;
+ ElseBlockStatement ElseBlockStatement = null;
+ List 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 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 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 Comments = new List();
+ 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(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 Comments = new List();
+ 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