Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Collections.Specialized;
- using System.Diagnostics;
- using System.Globalization;
- using System.Text;
- using DDW.Collections;
- using DDW.Enums;
- using DDW.Names;
- namespace DDW
- {
- public class Parser
- {
- public static readonly Token EOF = new Token(TokenID.Eof);
- private static readonly Modifier[] modMap;
- private static readonly byte[] precedence;
- private static readonly Dictionary<string, PreprocessorID> preprocessor;
- public static int ASSOC_LEFT = 1;
- public static int ASSOC_RIGHT;
- public static int no_name_index;
- public static byte PRECEDENCE_MULTIPLICcIVE = 0x7f;
- public static byte PRECEDENCE_PRIMARY = 0x90;
- public static byte PRECEDENCE_UNARY = 0x80;
- public static char[] QualifiedIdentifierDelimiters = new[] { '.' };
- private readonly string currentFileName = string.Empty;
- /// <summary>
- /// all parsed errors are stored in this list
- /// </summary>
- public readonly List<Error> Errors = new List<Error>();
- /// <summary>
- /// accessed by <see cref="ParseLocalDeclaration"/>
- /// </summary>
- private Stack<BlockStatement> blockStack;
- /// <summary>
- /// This dictionary stores all parsed constructed types.
- /// The key is the full qualified namespace plus the unique identifier of the type
- /// ( <see cref="ConstructedTypeNode.GenericIdentifier"/> ).
- /// I.e. : namespace1.namespace2.type
- ///
- /// This field has two objectives :
- /// 1. control the unicity of each type between all parsed files.
- /// 2. grabs together partial class defined in different files.
- /// </summary>
- private Dictionary<string, ConstructedTypeNode> constructedTypes;
- private CompilationUnitNode cu;
- private NodeCollection<AttributeNode> curAttributes;
- private InterfaceNode curInterface;
- /// <summary>
- /// used by ParseYieldStatement to check that an iterator is really iterator :
- /// A class which inherits from the IIterator interface could be iterator and it could be not iterator.
- /// It depends on its return type.
- /// </summary>
- private IIterator curIterator;
- /// <summary>
- /// many syntax checks need to access method parameter list
- /// </summary>
- private MethodNode curMethod;
- private Modifier curmods;
- private OperatorNode curOperator;
- private string currentDocComment = string.Empty;
- private ParseStateCollection curState;
- private Token curtok;
- private Dictionary<string, Constraint> curTypeParameterConstraints;
- /// <summary>
- /// can not be Dictionary<string, TypeParameterNode> because in the case
- /// class test : i<X,X>, the keys 'X' will be duplicated
- /// </summary>
- private List<TypeParameterNode> curTypeParameters;
- private Stack<ExpressionNode> exprStack;
- /// <summary>
- /// stores all parsed generic type
- /// </summary>
- private List<IGeneric> genericList;
- /// <summary>
- /// to travel information from the try to catch to notify it that the try has a 'yield return'
- /// </summary>
- private bool hasYieldReturnInTry;
- private bool inPPDirective;
- /// <summary>
- /// this flag is set when we enter in an anonymous delegate declaration
- /// this is an integer because we can declare anonymous delegate in anonymous delegate ...
- /// </summary>
- private int isAnonymous;
- private int isCatch;
- private int isFinally;
- private bool isLocalConst;
- private bool isNewStatement;
- /// <summary>
- /// this flag is set when we enter in an try, catch or finally block
- /// this is an integer because we can declare try another try ...
- /// </summary>
- private int isTry;
- /// <summary>
- /// this flag is set when we enter in an unsafe block
- /// this is an integer because we can declare unsafe block in unsafe block ...
- ///
- /// It is usefull to travel the unsafe state in child block :
- /// for example, a block declared in an unsafe block, i unsafe, so
- /// it inherits the unsafe state of his parent block
- /// </summary>
- private int isUnsafe;
- //iterator constant
- /// <summary>
- /// this field is used to keep a list of interface that made a method an iterator
- /// </summary>
- private StringCollection iteratorsClass;
- private int lineCount = 1;
- private bool mayBeLocalDecl;
- private Stack<NamespaceNode> namespaceStack;
- private bool nextIsPartial;
- /// <summary>
- /// This is always the following token of the curtok.
- /// Don't use it for lookahead though, as it may be a whitespace, newline, comment or hash token!!!
- /// </summary>
- private LinkedListNode<Token> nextTokNode;
- private bool ppCondition;
- private List<string> strings;
- private TokenCollection tokens;
- private Stack<ClassNode> typeStack;
- static Parser()
- {
- // all default to zero
- modMap = new Modifier[0xFF];
- modMap[(int)TokenID.New] = Modifier.New;
- modMap[(int)TokenID.Public] = Modifier.Public;
- modMap[(int)TokenID.Protected] = Modifier.Protected;
- modMap[(int)TokenID.Internal] = Modifier.Internal;
- modMap[(int)TokenID.Private] = Modifier.Private;
- modMap[(int)TokenID.Abstract] = Modifier.Abstract;
- modMap[(int)TokenID.Sealed] = Modifier.Sealed;
- modMap[(int)TokenID.Static] = Modifier.Static;
- modMap[(int)TokenID.Virtual] = Modifier.Virtual;
- modMap[(int)TokenID.Override] = Modifier.Override;
- modMap[(int)TokenID.Extern] = Modifier.Extern;
- modMap[(int)TokenID.Readonly] = Modifier.Readonly;
- modMap[(int)TokenID.Volatile] = Modifier.Volatile;
- modMap[(int)TokenID.Ref] = Modifier.Ref;
- modMap[(int)TokenID.Out] = Modifier.Out;
- // modMap[(int)TokenID.Assembly] = Modifier.Assembly;
- // modMap[(int)TokenID.Field] = Modifier.Field;
- modMap[(int)TokenID.Event] = Modifier.Event;
- // modMap[(int)TokenID.Method] = Modifier.Method;
- // modMap[(int)TokenID.Param] = Modifier.Param;
- // modMap[(int)TokenID.Property] = Modifier.Property;
- modMap[(int)TokenID.Return] = Modifier.Return;
- // modMap[(int)TokenID.Type] = Modifier.Type;
- // modMap[(int)TokenID.Partial] = Modifier.Partial;
- modMap[(int)TokenID.Unsafe] = Modifier.Unsafe;
- modMap[(int)TokenID.Fixed] = Modifier.Fixed;
- // all default to zero
- precedence = new byte[0xFF];
- // these start at 80 for no particular reason
- precedence[(int)TokenID.LBracket] = PRECEDENCE_PRIMARY;
- precedence[(int)TokenID.Dot] = PRECEDENCE_PRIMARY;
- precedence[(int)TokenID.MinusGreater] = PRECEDENCE_PRIMARY;
- precedence[(int)TokenID.LParen] = PRECEDENCE_UNARY; // 0x80
- precedence[(int)TokenID.Not] = PRECEDENCE_UNARY;
- precedence[(int)TokenID.Tilde] = PRECEDENCE_UNARY;
- precedence[(int)TokenID.PlusPlus] = PRECEDENCE_UNARY;
- precedence[(int)TokenID.MinusMinus] = PRECEDENCE_UNARY;
- precedence[(int)TokenID.Star] = PRECEDENCE_MULTIPLICcIVE; // 0x7f
- precedence[(int)TokenID.Slash] = PRECEDENCE_MULTIPLICcIVE;
- precedence[(int)TokenID.Percent] = PRECEDENCE_MULTIPLICcIVE;
- precedence[(int)TokenID.Plus] = 0x7E;
- precedence[(int)TokenID.Minus] = 0x7E;
- precedence[(int)TokenID.ShiftLeft] = 0x7D;
- precedence[(int)TokenID.ShiftRight] = 0x7D;
- precedence[(int)TokenID.Less] = 0x7C;
- precedence[(int)TokenID.Greater] = 0x7C;
- precedence[(int)TokenID.LessEqual] = 0x7C;
- precedence[(int)TokenID.GreaterEqual] = 0x7C;
- precedence[(int)TokenID.Is] = 0x7C;
- precedence[(int)TokenID.As] = 0x7C;
- precedence[(int)TokenID.EqualEqual] = 0x7B;
- precedence[(int)TokenID.NotEqual] = 0x7B;
- precedence[(int)TokenID.BAnd] = 0x7A;
- precedence[(int)TokenID.BXor] = 0x79;
- precedence[(int)TokenID.BOr] = 0x78;
- precedence[(int)TokenID.And] = 0x77;
- precedence[(int)TokenID.Or] = 0x76;
- precedence[(int)TokenID.QuestionQuestion] = 0x75;
- precedence[(int)TokenID.Question] = 0x74;
- precedence[(int)TokenID.Equal] = 0x73;
- precedence[(int)TokenID.PlusEqual] = 0x73;
- precedence[(int)TokenID.MinusEqual] = 0x73;
- precedence[(int)TokenID.StarEqual] = 0x73;
- precedence[(int)TokenID.SlashEqual] = 0x73;
- precedence[(int)TokenID.PercentEqual] = 0x73;
- precedence[(int)TokenID.BAndEqual] = 0x73;
- precedence[(int)TokenID.BOrEqual] = 0x73;
- precedence[(int)TokenID.BXorEqual] = 0x73;
- precedence[(int)TokenID.ShiftLeftEqual] = 0x73;
- precedence[(int)TokenID.ShiftRightEqual] = 0x73;
- preprocessor = new Dictionary<string, PreprocessorID>();
- preprocessor.Add("define", PreprocessorID.Define);
- preprocessor.Add("undef", PreprocessorID.Undef);
- preprocessor.Add("if", PreprocessorID.If);
- preprocessor.Add("elif", PreprocessorID.Elif);
- preprocessor.Add("else", PreprocessorID.Else);
- preprocessor.Add("endif", PreprocessorID.Endif);
- preprocessor.Add("line", PreprocessorID.Line);
- preprocessor.Add("error", PreprocessorID.Error);
- preprocessor.Add("warning", PreprocessorID.Warning);
- preprocessor.Add("region", PreprocessorID.Region);
- preprocessor.Add("endregion", PreprocessorID.Endregion);
- preprocessor.Add("pragma", PreprocessorID.Pragma);
- }
- public Parser(string currentFileName)
- {
- this.currentFileName = currentFileName;
- }
- #region Name Resolution
- private readonly Context currentContext = new Context();
- private readonly NameResolutionTable nameTable = new NameResolutionTable();
- private void EnterNamespace(string qualifiedName)
- {
- string[] nameParts = qualifiedName.Split(Type.Delimiter);
- for (int i = 0; i < nameParts.Length; i++)
- {
- nameTable.AddIdentifier(new NamespaceName(nameParts[i], currentContext));
- currentContext.Enter(nameParts[i], true);
- }
- }
- private void LeaveNamespace(string qualifiedName)
- {
- int index = -1;
- while ((index = qualifiedName.IndexOf(Type.Delimiter, index + 1)) != -1)
- {
- currentContext.Leave();
- }
- currentContext.Leave();
- }
- private static NameVisibilityRestriction ToVisibilityRestriction(Modifier modifier)
- {
- Modifier relevantMods = modifier & Modifier.Accessibility;
- NameVisibilityRestriction restriction = NameVisibilityRestriction.Self;
- if ((relevantMods & Modifier.Protected) != Modifier.Empty)
- {
- restriction = NameVisibilityRestriction.Family;
- }
- if (((relevantMods & Modifier.Internal) != Modifier.Empty) ||
- ((relevantMods & Modifier.Public) != Modifier.Empty))
- {
- restriction = NameVisibilityRestriction.Everyone;
- }
- return restriction;
- }
- #endregion
- public ParseStateCollection CurrentState
- {
- get { return curState; }
- }
- public CompilationUnitNode Parse(TokenCollection tokens, List<string> strings)
- {
- this.tokens = tokens;
- this.strings = strings;
- curmods = Modifier.Empty;
- curAttributes = new NodeCollection<AttributeNode>();
- curTypeParameters = new List<TypeParameterNode>();
- curTypeParameterConstraints = new Dictionary<string, Constraint>();
- blockStack = new Stack<BlockStatement>();
- curState = new ParseStateCollection();
- cu = new CompilationUnitNode();
- namespaceStack = new Stack<NamespaceNode>();
- namespaceStack.Push(cu.DefaultNamespace);
- typeStack = new Stack<ClassNode>();
- genericList = new List<IGeneric>();
- constructedTypes = new Dictionary<string, ConstructedTypeNode>();
- iteratorsClass = new StringCollection();
- iteratorsClass.Add("IEnumerator");
- iteratorsClass.Add("IEnumerable");
- iteratorsClass.Add("Collections.IEnumerator");
- iteratorsClass.Add("Collections.IEnumerable");
- iteratorsClass.Add("System.Collections.IEnumerator");
- iteratorsClass.Add("System.Collections.IEnumerable");
- iteratorsClass.Add("IEnumerator<>");
- iteratorsClass.Add("IEnumerable<>");
- iteratorsClass.Add("Generic.IEnumerator<>");
- iteratorsClass.Add("Generic.IEnumerable<>");
- iteratorsClass.Add("Collections.Generic.IEnumerator<>");
- iteratorsClass.Add("Collections.Generic.IEnumerable<>");
- iteratorsClass.Add("System.Collections.Generic.IEnumerator<>");
- iteratorsClass.Add("System.Collections.Generic.IEnumerable<>");
- exprStack = new Stack<ExpressionNode>();
- // begin parse
- nextTokNode = tokens.First;
- Advance();
- try
- {
- ParseNamespaceOrTypes();
- }
- catch
- {
- Console.WriteLine("Crashed for token: " + curtok + " at line " + curtok.Line + " column " + curtok.Col);
- //throw;
- return cu;
- }
- cu.NameTable = nameTable;
- return cu;
- }
- private void ParseNamespaceOrTypes()
- {
- while (!curtok.Equals(EOF))
- {
- // todo: account for assembly attributes
- ParsePossibleAttributesAndDocComment(true);
- if (curAttributes.Count > 0)
- {
- for (int i = 0; i < curAttributes.Count; ++i)
- {
- AttributeNode an = curAttributes[i];
- if ((an.Modifiers & Modifier.Assembly) == Modifier.Assembly
- || (an.Modifiers & Modifier.Module) == Modifier.Module)
- {
- cu.DefaultNamespace.Attributes.Add(an);
- curAttributes.RemoveAt(i);
- i--;
- }
- }
- //curAttributes.Clear();
- }
- // can be usingDirectives, globalAttribs, or NamespaceMembersDecls
- // NamespaceMembersDecls include namespaces, class, struct, interface, enum, delegate
- switch (curtok.ID)
- {
- case TokenID.Using:
- // using directive
- ParseUsingDirectives();
- break;
- case TokenID.New:
- case TokenID.Public:
- case TokenID.Protected:
- case TokenID.Internal:
- case TokenID.Private:
- case TokenID.Abstract:
- case TokenID.Sealed:
- case TokenID.Static:
- case TokenID.Unsafe:
- //parseTypeModifier();
- curmods |= modMap[(int)curtok.ID];
- Advance();
- break;
- case TokenID.Namespace:
- ParseNamespace();
- break;
- case TokenID.Class:
- ParseClass();
- break;
- case TokenID.Struct:
- ParseStruct();
- break;
- case TokenID.Interface:
- ParseInterface();
- break;
- case TokenID.Enum:
- ParseEnum();
- break;
- case TokenID.Delegate:
- ParseDelegate();
- break;
- case TokenID.Semi:
- Advance();
- break;
- case TokenID.Extern:
- ParseExternAlias();
- break;
- case TokenID.Ident:
- if (strings[curtok.Data] == "partial")
- {
- Advance();
- if (curtok.ID != TokenID.Class
- && curtok.ID != TokenID.Interface
- && curtok.ID != TokenID.Struct)
- {
- RecoverFromError("Only class, struct and interface may be declared partial.",
- TokenID.Class, TokenID.Struct, TokenID.Interface);
- }
- else
- {
- nextIsPartial = true;
- }
- break;
- }
- goto default;
- case TokenID.RCurly:
- return;
- case TokenID.Eof:
- if (namespaceStack.Count != 1)
- ReportError("Unexpected EOF", curtok);
- return;
- default:
- ReportError("Unexpected token", curtok);
- return;
- }
- }
- }
- private void ParseExternAlias()
- {
- Advance(); // over extern
- if (curtok.ID != TokenID.Ident || strings[curtok.Data] != "alias")
- ReportError("Expected 'alias', but found: " + curtok.ID, curtok);
- Advance(); // over alias
- ExternAliasDirectiveNode node = new ExternAliasDirectiveNode(curtok);
- node.ExternAliasName = ParseIdentifierOrKeyword(false, false, false, false, false);
- namespaceStack.Peek().ExternAliases.Add(node);
- }
- private void ParseUsingDirectives()
- {
- do
- {
- Advance();
- UsingDirectiveNode node = new UsingDirectiveNode(curtok);
- QualifiedIdentifierExpression nameOrAlias = ParseQualifiedIdentifier(true, false, false);
- if (curtok.ID == TokenID.Equal)
- {
- Advance();
- if (nameOrAlias.Expressions.Count > 1)
- ReportError("An alias name may not be qualified", nameOrAlias.RelatedToken);
- // an alias could be written like
- // using alias = path.identifier
- //
- // or like
- // using alias = path.identifier<object>
- //
- // it is not possible to know before if this a type or an qualified identifier
- // so we always parse it as a Qualified expression, and if the result is not a type
- // we keep only the identifier part
- QualifiedIdentifierExpression target = ParseQualifiedIdentifier(true, false, false);
- if (target.IsType)
- {
- node.Target = new TypeNode(target);
- }
- else
- {
- // it does not mean that this is not a type.
- // it only means that actually we can not resolve the type
- // but in a next stage, we will probably resolve it as a type.
- node.Target = target;
- }
- node.AliasName = nameOrAlias.Expressions[0] as IdentifierExpression;
- if (node.AliasName == null)
- {
- ReportError("An alias name must be an identifier", nameOrAlias.RelatedToken);
- node.AliasName = IdentifierExpression.GetErrorIdentifier(nameOrAlias.RelatedToken);
- }
- }
- else
- {
- node.Target = nameOrAlias;
- }
- AssertAndAdvance(TokenID.Semi);
- namespaceStack.Peek().UsingDirectives.Add(node);
- currentContext.AddUsingDirective(node);
- } while (curtok.ID == TokenID.Using);
- }
- private bool EvalPPExpression(ExpressionNode expr)
- {
- BinaryExpression binExpr = expr as BinaryExpression;
- if (binExpr != null)
- {
- switch (binExpr.Op)
- {
- case TokenID.Or:
- return EvalPPExpression(binExpr.Left) || EvalPPExpression(binExpr.Right);
- case TokenID.And:
- return EvalPPExpression(binExpr.Left) && EvalPPExpression(binExpr.Right);
- case TokenID.EqualEqual:
- return EvalPPExpression(binExpr.Left) == EvalPPExpression(binExpr.Right);
- case TokenID.NotEqual:
- return EvalPPExpression(binExpr.Left) != EvalPPExpression(binExpr.Right);
- default:
- ReportError("Illegal binary preprocessor expression", binExpr.RelatedToken);
- return false;
- }
- }
- UnaryExpression unExpr = expr as UnaryExpression;
- if (unExpr != null)
- {
- if (unExpr.Op == TokenID.Not)
- return !EvalPPExpression(unExpr.Child);
- ReportError("Illegal unary preprocessor expression", binExpr.RelatedToken);
- return false;
- }
- IdentifierExpression idExpr = expr as IdentifierExpression;
- if (idExpr != null)
- return cu.PPDefs.ContainsKey(idExpr.Identifier);
- BooleanPrimitive boolPrim = expr as BooleanPrimitive;
- if (boolPrim != null)
- return boolPrim.Value;
- ParenthesizedExpression parenExpr = expr as ParenthesizedExpression;
- if (parenExpr != null)
- return EvalPPExpression(parenExpr.Expression);
- ReportError("Illegal preprocessor expression", expr.RelatedToken);
- return false;
- }
- private bool SameLine(int oldLine)
- {
- if (curtok.Line != oldLine)
- {
- ReportError("Unexpected end of line", curtok);
- return false;
- }
- return true;
- }
- private void ParsePreprocessorExpressionSegment(int oldLine)
- {
- int startStackCount = exprStack.Count;
- TokenID startToken = curtok.ID;
- switch (curtok.ID)
- {
- case TokenID.True:
- exp
Add Comment
Please, Sign In to add comment