/// <summary> /// Parses the given <paramref name="aliasElement"/> and creates an ImportStatement or AliasStatement from it. /// </summary> /// <param name="aliasElement">The alias element to parse.</param> /// <param name="context">The parser context to use.</param> /// <returns>An ImportStatement if the element is an import, or an AliasStatement if it is an alias.</returns> protected override Statement ParseAliasElement(XElement aliasElement, ParserContext context) { if (aliasElement == null) { throw new ArgumentNullException("aliasElement"); } if (aliasElement.Name != AliasElementName) { throw new ArgumentException(string.Format("Must be a SRC.{0} element", AliasElementName.LocalName), "aliasElement"); } if (context == null) { throw new ArgumentNullException("context"); } var isNamespaceImport = aliasElement.Descendants(SRC.Name).Any(n => n.Value.Contains("*")); //Elements("name").Any(n => n.Value.Contains("*")); //).Any(n => n.Value.Contains("*")); Statement stmt = null; if (isNamespaceImport) { //namespace import var import = new ImportStatement() { ProgrammingLanguage = ParserLanguage }; import.AddLocation(context.CreateLocation(aliasElement)); var nameElement = aliasElement.Element(SRC.Name); if (nameElement != null) { //we have an import that ends with .*. We remove the . and *. nameElement.LastNode.Remove(); //remove * nameElement.LastNode.Remove(); //remove . import.ImportedNamespace = ParseNameUseElement <NamespaceUse>(nameElement, context); //TODO: fix to handle the trailing operator tag } stmt = import; } else { //importing a single member, i.e. an alias var alias = new AliasStatement() { ProgrammingLanguage = ParserLanguage }; alias.AddLocation(context.CreateLocation(aliasElement)); var nameElement = aliasElement.Element(SRC.Name); if (nameElement != null) { alias.Target = ParseExpression(nameElement, context); alias.AliasName = NameHelper.GetLastName(nameElement); } stmt = alias; } return(stmt); }
/// <summary> /// Parses a Java package directive /// </summary> /// <param name="namespaceElement">A file unit</param> /// <param name="context">The parser context</param> public override void ParseNamespaceElement(XElement namespaceElement, ParserContext context) { var javaPackage = context.FileUnit.Elements(SRC.Package).FirstOrDefault(); // Add a global namespace definition var globalNamespace = new NamespaceDefinition(); context.Push(globalNamespace); if (null != javaPackage) { var namespaceElements = from name in javaPackage.Elements(SRC.Name) select name; foreach (var name in namespaceElements) { var namespaceForName = new NamespaceDefinition() { Name = name.Value, ProgrammingLanguage = ParserLanguage, }; namespaceForName.AddSourceLocation(context.CreateLocation(name)); context.Push(namespaceForName, globalNamespace); } } }
/// <summary> /// Creates a <see cref="Statement"/> object for <paramref name="stmtElement"/>. /// The expression contained within <paramref name="stmtElement"/> will be parsed and placed in /// Statement.Content. /// </summary> /// <param name="stmtElement">The SRC.ExpressionStatement element to parse.</param> /// <param name="context">The context to use.</param> /// <returns>A <see cref="Statement"/> corresponding to <paramref name="stmtElement"/>.</returns> protected override Statement ParseDeclarationStatementElement(XElement stmtElement, ParserContext context) { if (stmtElement == null) { throw new ArgumentNullException("stmtElement"); } if (stmtElement.Name != SRC.DeclarationStatement && stmtElement.Name != SRC.Property) { throw new ArgumentException("Must be a SRC.DeclarationStatement element", "stmtElement"); } if (context == null) { throw new ArgumentNullException("context"); } //first check if this is a property and parse accordingly if (stmtElement.Name == SRC.Property) { return(ParsePropertyDeclarationElement(stmtElement, context)); } else { var stmt = new DeclarationStatement() { ProgrammingLanguage = ParserLanguage, Content = ParseExpression(GetChildExpressions(stmtElement), context) }; stmt.AddLocation(context.CreateLocation(stmtElement)); return(stmt); } }
//TODO: implement support for using blocks, once SrcML has been fixed to parse them correctly ///// <summary> ///// Gets all of the variable declarations from a container ///// </summary> ///// <param name="container">the container</param> ///// <param name="fileUnit">the containing file unit</param> ///// <returns>An enumerable of variable declarations</returns> //public override IEnumerable<VariableDeclaration> GetVariableDeclarationsFromContainer(XElement container, XElement fileUnit, Scope parentScope) { // if(null == container) return Enumerable.Empty<VariableDeclaration>(); // if(container.Name != SRC.Using) { return // base.GetVariableDeclarationsFromContainer(container, fileUnit, parentScope); } //parse // using typeUseElement //} #region Private methods private NamespaceUse CreateNamespaceUsePrefix(XElement nameElement, ParserContext context) { IEnumerable <XElement> parentNameElements = Enumerable.Empty <XElement>(); parentNameElements = NameHelper.GetNameElementsExceptLast(nameElement); NamespaceUse current = null, root = null; if (parentNameElements.Any()) { foreach (var element in parentNameElements) { var namespaceUse = new NamespaceUse { Name = element.Value, Location = context.CreateLocation(element, false), ProgrammingLanguage = this.ParserLanguage, }; if (null == root) { root = namespaceUse; } if (current != null) { current.ChildScopeUse = namespaceUse; } current = namespaceUse; } } return(root); }
/// <summary> /// Parses a C# namespace block /// </summary> /// <param name="namespaceElement">the namespace element to parse</param> /// <param name="context">the parser context</param> protected override NamespaceDefinition ParseNamespaceElement(XElement namespaceElement, ParserContext context) { if (namespaceElement == null) { throw new ArgumentNullException("namespaceElement"); } if (!NamespaceElementNames.Contains(namespaceElement.Name)) { throw new ArgumentException(string.Format("Not a valid namespace element: {0}", namespaceElement.Name), "namespaceElement"); } if (context == null) { throw new ArgumentNullException("context"); } var nameElement = namespaceElement.Element(SRC.Name); if (nameElement == null) { throw new ParseException(context.FileName, namespaceElement.GetSrcLineNumber(), namespaceElement.GetSrcLinePosition(), this, "No SRC.Name element found in namespace.", null); } //parse the name and create a NamespaceDefinition for each component NamespaceDefinition topNS = null; NamespaceDefinition lastNS = null; foreach (var name in NameHelper.GetNameElementsFromName(nameElement)) { var newNS = new NamespaceDefinition { Name = name.Value, ProgrammingLanguage = ParserLanguage }; newNS.AddLocation(context.CreateLocation(name)); if (topNS == null) { topNS = newNS; } if (lastNS != null) { lastNS.AddChildStatement(newNS); } lastNS = newNS; } //add body of namespace to lastNS var blockElement = namespaceElement.Element(SRC.Block); if (blockElement != null) { foreach (var child in blockElement.Elements()) { lastNS.AddChildStatement(ParseStatement(child, context)); } } return(topNS); }
/// <summary> /// Creates a ForStatement or ForeachStatement from the given element. /// </summary> /// <param name="forElement">The SRC.For element to parse.</param> /// <param name="context">The parser context to use.</param> /// <returns>A ForStatement or ForeachStatement corresponding to forElement.</returns> protected override ConditionBlockStatement ParseForElement(XElement forElement, ParserContext context) { if (forElement == null) { throw new ArgumentNullException("forElement"); } if (forElement.Name != SRC.For) { throw new ArgumentException("Must be a SRC.For element", "forElement"); } if (context == null) { throw new ArgumentNullException("context"); } var controlElement = forElement.Element(SRC.Control); if (controlElement.Element(SRC.Condition) != null) { //this is a standard for-loop, use the base processing return(base.ParseForElement(forElement, context)); } //else, this is a Java-style foreach loop var foreachStmt = new ForeachStatement() { ProgrammingLanguage = ParserLanguage }; foreachStmt.AddLocation(context.CreateLocation(forElement)); foreach (var child in forElement.Elements()) { if (child.Name == SRC.Init) { //fill in condition/initializer var expElement = GetFirstChildExpression(child); if (expElement != null) { foreachStmt.Condition = ParseExpression(expElement, context); } } else if (child.Name == SRC.Block) { //add children from block var blockStatements = child.Elements().Select(e => ParseStatement(e, context)); foreachStmt.AddChildStatements(blockStatements); } else { //add child foreachStmt.AddChildStatement(ParseStatement(child, context)); } } return(foreachStmt); }
/// <summary> /// Parses an element corresponding to a type definition and creates a TypeDefinition object /// </summary> /// <param name="typeElement">The type element to parse. This must be one of the elements contained in TypeElementNames.</param> /// <param name="context">The parser context</param> /// <returns>A TypeDefinition parsed from the element</returns> protected override TypeDefinition ParseTypeElement(XElement typeElement, ParserContext context) { if (null == typeElement) { throw new ArgumentNullException("typeElement"); } if (context == null) { throw new ArgumentNullException("context"); } var typeDefinition = new TypeDefinition() { Accessibility = GetAccessModifierForType(typeElement), Kind = XNameMaps.GetKindForXElement(typeElement), Name = GetNameForType(typeElement), ProgrammingLanguage = ParserLanguage }; typeDefinition.AddLocation(context.CreateLocation(typeElement, ContainerIsReference(typeElement))); foreach (var parentTypeElement in GetParentTypeUseElements(typeElement)) { var parentTypeUse = ParseTypeUseElement(parentTypeElement, context); typeDefinition.AddParentType(parentTypeUse); } var typeBlock = typeElement.Element(SRC.Block); if (typeBlock != null) { foreach (var child in typeBlock.Elements()) { if (child.Name == SRC.Private) { typeDefinition.AddChildStatements(ParseClassChildren(child, context, AccessModifier.Private)); } else if (child.Name == SRC.Protected) { typeDefinition.AddChildStatements(ParseClassChildren(child, context, AccessModifier.Protected)); } else if (child.Name == SRC.Public) { typeDefinition.AddChildStatements(ParseClassChildren(child, context, AccessModifier.Public)); } else { typeDefinition.AddChildStatement(ParseStatement(child, context)); } } } return(typeDefinition); }
/// <summary> /// Parses a java file unit. This handles the "package" directive by calling /// <see cref="ParseNamespaceElement"/> /// </summary> /// <param name="unitElement">The file unit to parse.</param> /// <param name="context">The parser context to use.</param> protected override NamespaceDefinition ParseUnitElement(XElement unitElement, ParserContext context) { if (null == unitElement) { throw new ArgumentNullException("unitElement"); } if (SRC.Unit != unitElement.Name) { throw new ArgumentException("should be a SRC.Unit", "unitElement"); } if (context == null) { throw new ArgumentNullException("context"); } context.FileUnit = unitElement; //var aliases = from aliasStatement in GetAliasElementsForFile(unitElement) // select ParseAliasElement(aliasStatement, context); //context.Aliases = new Collection<Alias>(aliases.ToList()); //create a global namespace for the file unit var namespaceForUnit = new NamespaceDefinition() { ProgrammingLanguage = ParserLanguage }; namespaceForUnit.AddLocation(context.CreateLocation(unitElement)); NamespaceDefinition bottomNamespace = namespaceForUnit; //create a namespace for the package, and attach to global namespace var packageElement = unitElement.Element(SRC.Package); if (packageElement != null) { var namespaceForPackage = ParseNamespaceElement(packageElement, context); namespaceForUnit.AddChildStatement(namespaceForPackage); bottomNamespace = namespaceForPackage.GetDescendantsAndSelf <NamespaceDefinition>().Last(); } //add children to bottom namespace foreach (var child in unitElement.Elements()) { var childStmt = ParseStatement(child, context); if (childStmt != null) { bottomNamespace.AddChildStatement(childStmt); } } return(namespaceForUnit); }
/// <summary> /// Parses the given typeUseElement and returns a TypeUse object. This handles the "var" /// keyword for C# if used /// </summary> /// <param name="typeUseElement">The XML type use element</param> /// <param name="context">The parser context</param> /// <returns>A new TypeUse object</returns> public override ITypeUse ParseTypeUseElement(XElement typeUseElement, ParserContext context) { if (typeUseElement == null) { throw new ArgumentNullException("typeUseElement"); } XElement typeElement; XElement typeNameElement; // validate the type use typeUseElement (must be a SRC.Name or SRC.Type) if (typeUseElement.Name == SRC.Type) { typeElement = typeUseElement; typeNameElement = typeUseElement.Elements(SRC.Name).LastOrDefault(); } else if (typeUseElement.Name == SRC.Name) { typeElement = typeUseElement.Ancestors(SRC.Type).FirstOrDefault(); typeNameElement = typeUseElement; } else { throw new ArgumentException("typeUseElement should be of type type or name", "typeUseElement"); } if (typeNameElement.Value == "var") { var initElement = typeElement.ElementsAfterSelf(SRC.Init).FirstOrDefault(); var expressionElement = (null == initElement ? null : initElement.Element(SRC.Expression)); var callElement = (null == expressionElement ? null : expressionElement.Element(SRC.Call)); IResolvesToType initializer = (null == callElement ? null : ParseCallElement(callElement, context)); var typeUse = new CSharpVarTypeUse() { Name = typeNameElement.Value, Initializer = initializer, ParentScope = context.CurrentScope, Location = context.CreateLocation(typeNameElement), ProgrammingLanguage = this.ParserLanguage, }; return(typeUse); } else { return(base.ParseTypeUseElement(typeUseElement, context)); } }
/// <summary> /// Creates a NamespaceDefinition object from the given Java package element. /// This will create a NamespaceDefinition for each component of the name, e.g. com.java.foo.bar, and link them as children of each other. /// This will not add any child statements to the bottom namespace. /// </summary> /// <param name="packageElement">The SRC.Package element to parse.</param> /// <param name="context">The parser context to use.</param> /// <returns>A NamespaceDefinition corresponding to <paramref name="packageElement"/>.</returns> protected override NamespaceDefinition ParseNamespaceElement(XElement packageElement, ParserContext context) { if (packageElement == null) { throw new ArgumentNullException("packageElement"); } if (packageElement.Name != SRC.Package) { throw new ArgumentException("must be a SRC.Package", "packageElement"); } if (context == null) { throw new ArgumentNullException("context"); } var nameElement = packageElement.Element(SRC.Name); if (nameElement == null) { throw new ParseException(context.FileName, packageElement.GetSrcLineNumber(), packageElement.GetSrcLinePosition(), this, "No SRC.Name element found in namespace.", null); } //parse the name and create a NamespaceDefinition for each component NamespaceDefinition topNS = null; NamespaceDefinition lastNS = null; foreach (var name in NameHelper.GetNameElementsFromName(nameElement)) { var newNS = new NamespaceDefinition { Name = name.Value, ProgrammingLanguage = ParserLanguage }; newNS.AddLocation(context.CreateLocation(name)); if (topNS == null) { topNS = newNS; } if (lastNS != null) { lastNS.AddChildStatement(newNS); } lastNS = newNS; } return(topNS); }
/// <summary> /// Creates a <see cref="PropertyDefinition"/> object for <paramref name="declElement"/>. /// </summary> /// <param name="declElement">The SRC.Declaration element to parse. This must be a declaration of a property.</param> /// <param name="context">The context to use.</param> /// <returns>A <see cref="PropertyDefinition"/> corresponding to <paramref name="declElement"/>.</returns> protected virtual PropertyDefinition ParsePropertyDeclarationElement(XElement declElement, ParserContext context) { if (declElement == null) { throw new ArgumentNullException("declElement"); } if (declElement.Name != SRC.Declaration) { throw new ArgumentException("Must be a SRC.Declaration element", "declElement"); } if (context == null) { throw new ArgumentNullException("context"); } var propertyDef = new PropertyDefinition { ProgrammingLanguage = ParserLanguage }; propertyDef.AddLocation(context.CreateLocation(declElement)); foreach (var child in declElement.Elements()) { if (child.Name == SRC.Type) { propertyDef.Accessibility = GetAccessModifierFromTypeUseElement(child); propertyDef.ReturnType = ParseTypeUseElement(child, context); } else if (child.Name == SRC.Name) { propertyDef.Name = child.Value; } else if (child.Name == SRC.Block) { //add children from block. This should be the getter/setter methods var blockStatements = child.Elements().Select(e => ParseStatement(e, context)); propertyDef.AddChildStatements(blockStatements); } else { propertyDef.AddChildStatement(ParseStatement(child, context)); } } return(propertyDef); }
/// <summary> /// Parses the given <paramref name="usingElement"/> and creates a <see cref="UsingBlockStatement"/> from it. /// </summary> /// <param name="usingElement">The SRC.Using element to parse.</param> /// <param name="context">The parser context to use.</param> /// <returns>A UsingBlockStatement created from the given usingElement.</returns> protected virtual UsingBlockStatement ParseUsingBlockElement(XElement usingElement, ParserContext context) { if (usingElement == null) { throw new ArgumentNullException("usingElement"); } if (usingElement.Name != SRC.Using) { throw new ArgumentException("Must be a SRC.Using element", "usingElement"); } if (context == null) { throw new ArgumentNullException("context"); } var usingStmt = new UsingBlockStatement() { ProgrammingLanguage = ParserLanguage }; usingStmt.AddLocation(context.CreateLocation(usingElement)); foreach (var child in usingElement.Elements()) { if (child.Name == SRC.Init) { //TODO: waiting for update to srcml usingStmt.Initializer = ParseExpression(GetChildExpressions(child), context); } else if (child.Name == SRC.Block) { var blockStatements = child.Elements().Select(e => ParseStatement(e, context)); usingStmt.AddChildStatements(blockStatements); } else { usingStmt.AddChildStatement(ParseStatement(child, context)); } } return(usingStmt); }
/// <summary> /// Parses a Java package directive /// </summary> /// <param name="namespaceElement">A file unit</param> /// <param name="context">The parser context</param> public override void ParseNamespaceElement(XElement namespaceElement, ParserContext context) { var javaPackage = context.FileUnit.Elements(SRC.Package).FirstOrDefault(); // Add a global namespace definition var globalNamespace = new NamespaceDefinition(); context.Push(globalNamespace); if(null != javaPackage) { var namespaceElements = from name in javaPackage.Elements(SRC.Name) select name; foreach(var name in namespaceElements) { var namespaceForName = new NamespaceDefinition() { Name = name.Value, ProgrammingLanguage = ParserLanguage, }; namespaceForName.AddSourceLocation(context.CreateLocation(name)); context.Push(namespaceForName, globalNamespace); } } }
/// <summary> /// Parses a C# namespace block /// </summary> /// <param name="namespaceElement">the namespace element to parse</param> /// <param name="context">the parser context</param> public override void ParseNamespaceElement(XElement namespaceElement, ParserContext context) { if (namespaceElement == null) { throw new ArgumentNullException("namespaceElement"); } if (!NamespaceElementNames.Contains(namespaceElement.Name)) { throw new ArgumentException(string.Format("Not a valid namespace element: {0}", namespaceElement.Name), "namespaceElement"); } var nameElement = namespaceElement.Element(SRC.Name); string namespaceName; if (nameElement == null) { namespaceName = string.Empty; } else { NamespaceDefinition root = null; foreach (var name in NameHelper.GetNameElementsFromName(nameElement)) { var namespaceForName = new NamespaceDefinition() { Name = name.Value, ProgrammingLanguage = ParserLanguage, }; if (root == null) { root = namespaceForName; } else { namespaceForName.AddSourceLocation(context.CreateLocation(name)); } context.Push(namespaceForName, root); } } }
/// <summary> /// Creates a NamespaceDefinition object for the given namespace typeUseElement. This must /// be one of the typeUseElement types defined in NamespaceElementNames. /// </summary> /// <param name="namespaceElement">the namespace element</param> /// <param name="context">The parser context</param> /// <returns>a new NamespaceDefinition object</returns> protected override NamespaceDefinition ParseNamespaceElement(XElement namespaceElement, ParserContext context) { if (namespaceElement == null) { throw new ArgumentNullException("namespaceElement"); } if (!NamespaceElementNames.Contains(namespaceElement.Name)) { throw new ArgumentException(string.Format("Not a valid namespace element: {0}", namespaceElement.Name), "namespaceElement"); } if (context == null) { throw new ArgumentNullException("context"); } var nameElement = namespaceElement.Element(SRC.Name); var namespaceName = nameElement != null ? nameElement.Value : string.Empty; var nd = new NamespaceDefinition { Name = namespaceName, ProgrammingLanguage = ParserLanguage, }; nd.AddLocation(context.CreateLocation(namespaceElement)); //add children var blockElement = namespaceElement.Element(SRC.Block); if (blockElement != null) { foreach (var child in blockElement.Elements()) { nd.AddChildStatement(ParseStatement(child, context)); } } return(nd); }
/// <summary> /// Parses a C# namespace block /// </summary> /// <param name="namespaceElement">the namespace element to parse</param> /// <param name="context">the parser context</param> public override void ParseNamespaceElement(XElement namespaceElement, ParserContext context) { if(namespaceElement == null) throw new ArgumentNullException("namespaceElement"); if(!NamespaceElementNames.Contains(namespaceElement.Name)) throw new ArgumentException(string.Format("Not a valid namespace element: {0}", namespaceElement.Name), "namespaceElement"); var nameElement = namespaceElement.Element(SRC.Name); string namespaceName; if(nameElement == null) { namespaceName = string.Empty; } else { NamespaceDefinition root = null; foreach(var name in NameHelper.GetNameElementsFromName(nameElement)) { var namespaceForName = new NamespaceDefinition() { Name = name.Value, ProgrammingLanguage = ParserLanguage, }; if(root == null) { root = namespaceForName; } else { namespaceForName.AddSourceLocation(context.CreateLocation(name)); } context.Push(namespaceForName, root); } } }
/// <summary> /// Creates a <see cref="Statement"/> object for <paramref name="stmtElement"/>. /// The expression contained within <paramref name="stmtElement"/> will be parsed and placed in /// Statement.Content. /// </summary> /// <param name="stmtElement">The SRC.DeclarationStatement element to parse.</param> /// <param name="context">The context to use.</param> /// <returns>A <see cref="DeclarationStatement"/> corresponding to <paramref name="stmtElement"/>. /// The return type is <see cref="Statement"/> so that subclasses can return another type, as necessary. </returns> protected override Statement ParseDeclarationStatementElement(XElement stmtElement, ParserContext context) { if (stmtElement == null) { throw new ArgumentNullException("stmtElement"); } if (stmtElement.Name != SRC.DeclarationStatement && stmtElement.Name != SRC.Property) { throw new ArgumentException("Must be a SRC.DeclarationStatement or SRC.Property element", "stmtElement"); } if (context == null) { throw new ArgumentNullException("context"); } var stmt = new DeclarationStatement() { ProgrammingLanguage = ParserLanguage, Content = ParseExpression(GetChildExpressions(stmtElement), context) }; stmt.AddLocation(context.CreateLocation(stmtElement)); return(stmt); }
/// <summary> /// Parses a C# namespace block /// </summary> /// <param name="namespaceElement">the namespace element to parse</param> /// <param name="context">the parser context</param> protected override NamespaceDefinition ParseNamespaceElement(XElement namespaceElement, ParserContext context) { if(namespaceElement == null) throw new ArgumentNullException("namespaceElement"); if(!NamespaceElementNames.Contains(namespaceElement.Name)) throw new ArgumentException(string.Format("Not a valid namespace element: {0}", namespaceElement.Name), "namespaceElement"); if(context == null) throw new ArgumentNullException("context"); var nameElement = namespaceElement.Element(SRC.Name); if(nameElement == null) { throw new ParseException(context.FileName, namespaceElement.GetSrcLineNumber(), namespaceElement.GetSrcLinePosition(), this, "No SRC.Name element found in namespace.", null); } //parse the name and create a NamespaceDefinition for each component NamespaceDefinition topNS = null; NamespaceDefinition lastNS = null; foreach(var name in NameHelper.GetNameElementsFromName(nameElement)) { var newNS = new NamespaceDefinition { Name = name.Value, ProgrammingLanguage = ParserLanguage }; newNS.AddLocation(context.CreateLocation(name)); if(topNS == null) { topNS = newNS; } if(lastNS != null) { lastNS.AddChildStatement(newNS); } lastNS = newNS; } //add body of namespace to lastNS var blockElement = namespaceElement.Element(SRC.Block); if(blockElement != null) { foreach(var child in blockElement.Elements()) { lastNS.AddChildStatement(ParseStatement(child, context)); } } return topNS; }
/// <summary> /// Creates variable declaration objects from the given declaration element /// </summary> /// <param name="declarationElement">The variable declaration to parse. Must belong to <see cref="VariableDeclarationElementNames"/></param> /// <param name="context">The parser context</param> /// <returns>One variable declaration object for each declaration in <paramref name="declarationElement"/></returns> public virtual IEnumerable<VariableDeclaration> ParseDeclarationElement(XElement declarationElement, ParserContext context) { if(declarationElement == null) throw new ArgumentNullException("declaration"); if(!VariableDeclarationElementNames.Contains(declarationElement.Name)) throw new ArgumentException("XElement.Name must be in VariableDeclarationElementNames"); XElement declElement; if(declarationElement.Name == SRC.Declaration || declarationElement.Name == SRC.FunctionDeclaration) { declElement = declarationElement; } else { declElement = declarationElement.Element(SRC.Declaration); } var typeElement = declElement.Element(SRC.Type); var declarationType = ParseTypeUseElement(typeElement, context); foreach(var nameElement in declElement.Elements(SRC.Name)) { var variableDeclaration = new VariableDeclaration() { VariableType = declarationType, Name = nameElement.Value, Location = context.CreateLocation(nameElement), Scope = context.CurrentScope, }; yield return variableDeclaration; } }
/// <summary> /// Creates a method call object /// </summary> /// <param name="callElement">The XML element to parse</param> /// <param name="context">The parser context</param> /// <returns>A method call for <paramref name="callElement"/></returns> public virtual MethodCall ParseCallElement(XElement callElement, ParserContext context) { string name = String.Empty; bool isConstructor = false; bool isDestructor = false; IEnumerable<XElement> callingObjectNames = Enumerable.Empty<XElement>(); var nameElement = callElement.Element(SRC.Name); if(null != nameElement) { name = NameHelper.GetLastName(nameElement); callingObjectNames = NameHelper.GetNameElementsExceptLast(nameElement); } var precedingElements = callElement.ElementsBeforeSelf(); foreach(var pe in precedingElements) { if(pe.Name == OP.Operator && pe.Value == "new") { isConstructor = true; } else if(pe.Name == OP.Operator && pe.Value == "~") { isDestructor = true; } } var methodCall = new MethodCall() { Name = name, IsConstructor = isConstructor, IsDestructor = isDestructor, ParentScope = context.CurrentScope, Location = context.CreateLocation(callElement), }; var arguments = from argument in callElement.Element(SRC.ArgumentList).Elements(SRC.Argument) select CreateResolvableUse(argument, context); methodCall.Arguments = new Collection<IResolvesToType>(arguments.ToList<IResolvesToType>()); IResolvesToType current = methodCall; // This foreach block gets all of the name elements included in the actual <call> element // this is done primarily in C# and Java where they can reliably be included there foreach(var callingObjectName in callingObjectNames.Reverse()) { var callingObject = this.CreateVariableUse(callingObjectName, context); current.CallingObject = callingObject; current = callingObject; } // after getting those, we look at the name elements that appear *before* a call // we keep taking name elements as long as they are preceded by "." or "->" // we want to accept get 'a', 'b', and 'c' from "a.b->c" only 'b' and 'c' from // "a + b->c" var elementsBeforeCall = callElement.ElementsBeforeSelf().ToArray(); int i = elementsBeforeCall.Length - 1; while(i > 0 && elementsBeforeCall[i].Name == OP.Operator && (elementsBeforeCall[i].Value == "." || elementsBeforeCall[i].Value == "->")) { i--; if(i >= 0 && elementsBeforeCall[i].Name == SRC.Name) { var callingObject = CreateVariableUse(elementsBeforeCall[i], context); current.CallingObject = callingObject; current = callingObject; } i--; } if(methodCall.CallingObject == null) { methodCall.AddAliases(context.Aliases); } // TODO can we add aliases to calling object? return methodCall; }
/// <summary> /// Generates a parameter declaration for the given declaration /// </summary> /// <param name="declElement">The declaration XElement from within the parameter element. Must be a <see cref="ABB.SrcML.SRC.Declaration"/> or <see cref="ABB.SrcML.SRC.FunctionDeclaration"/></param> /// <param name="context">the parser context</param> /// <returns>A parameter declaration object</returns> public virtual ParameterDeclaration ParseMethodParameterElement(XElement declElement, ParserContext context) { if(declElement == null) throw new ArgumentNullException("declElement"); if(declElement.Name != SRC.Declaration && declElement.Name != SRC.FunctionDeclaration) throw new ArgumentException("must be of element type SRC.Declaration or SRC.FunctionDeclaration", "declElement"); var typeElement = declElement.Element(SRC.Type); var nameElement = declElement.Element(SRC.Name); var name = (nameElement == null ? String.Empty : nameElement.Value); var parameterDeclaration = new ParameterDeclaration { VariableType = ParseTypeUseElement(typeElement, context), Name = name, Scope = context.CurrentScope }; parameterDeclaration.Locations.Add(context.CreateLocation(declElement)); return parameterDeclaration; }
/// <summary> /// Parses the given <paramref name="aliasElement"/> and creates an ImportStatement or AliasStatement from it. /// </summary> /// <param name="aliasElement">The alias element to parse.</param> /// <param name="context">The parser context to use.</param> /// <returns>An ImportStatement if the element is an import, or an AliasStatement if it is an alias.</returns> protected override Statement ParseAliasElement(XElement aliasElement, ParserContext context) { if (aliasElement == null) { throw new ArgumentNullException("aliasElement"); } if (aliasElement.Name != AliasElementName) { throw new ArgumentException(string.Format("Must be a SRC.{0} element", AliasElementName.LocalName), "aliasElement"); } if (context == null) { throw new ArgumentNullException("context"); } Statement stmt = null; if (GetTextNodes(aliasElement).Any(n => n.Value.Contains("("))) { //using block stmt = ParseUsingBlockElement(aliasElement, context); } else if (aliasElement.Element(SRC.Init) != null) { //alias var alias = new AliasStatement() { ProgrammingLanguage = ParserLanguage }; alias.AddLocation(context.CreateLocation(aliasElement)); var nameElement = aliasElement.Element(SRC.Name); if (nameElement != null) { alias.AliasName = nameElement.Value; } var initElement = aliasElement.Element(SRC.Init); alias.Target = ParseExpression <TypeContainerUse>(GetFirstChildExpression(initElement), context); stmt = alias; } else { //import var import = new ImportStatement() { ProgrammingLanguage = ParserLanguage }; import.AddLocation(context.CreateLocation(aliasElement)); var nameElement = aliasElement.Element(SRC.Name); if (nameElement != null) { import.ImportedNamespace = ParseNameUseElement <NamespaceUse>(nameElement, context); } stmt = import; } return(stmt); }
/// <summary> /// Creates a <see cref="Statement"/> object for <paramref name="stmtElement"/>. /// The expression contained within <paramref name="stmtElement"/> will be parsed and placed in /// Statement.Content. /// </summary> /// <param name="stmtElement">The SRC.ExpressionStatement element to parse.</param> /// <param name="context">The context to use.</param> /// <returns>A <see cref="Statement"/> corresponding to <paramref name="stmtElement"/>.</returns> protected override Statement ParseDeclarationStatementElement(XElement stmtElement, ParserContext context) { if(stmtElement == null) throw new ArgumentNullException("stmtElement"); if (stmtElement.Name != SRC.DeclarationStatement && stmtElement.Name != SRC.Property) throw new ArgumentException("Must be a SRC.DeclarationStatement element", "stmtElement"); if(context == null) throw new ArgumentNullException("context"); //first check if this is a property and parse accordingly if (stmtElement.Name == SRC.Property) { return ParsePropertyDeclarationElement(stmtElement, context); } else { var stmt = new DeclarationStatement() { ProgrammingLanguage = ParserLanguage, Content = ParseExpression(GetChildExpressions(stmtElement), context) }; stmt.AddLocation(context.CreateLocation(stmtElement)); return stmt; } }
/// <summary> /// Creates a <see cref="PropertyDefinition"/> object for <paramref name="propertyElement"/>. /// </summary> /// <param name="propertyElement">The SRC.Declaration element to parse. This must be a declaration of a property.</param> /// <param name="context">The context to use.</param> /// <returns>A <see cref="PropertyDefinition"/> corresponding to <paramref name="propertyElement"/>.</returns> protected virtual PropertyDefinition ParsePropertyDeclarationElement(XElement propertyElement, ParserContext context) { if(propertyElement == null) throw new ArgumentNullException("propertyElement"); if(propertyElement.Name != SRC.Property) throw new ArgumentException("Must be a SRC.Property element", "propertyElement"); if(context == null) throw new ArgumentNullException("context"); var propertyDef = new PropertyDefinition {ProgrammingLanguage = ParserLanguage}; propertyDef.AddLocation(context.CreateLocation(propertyElement)); foreach(var child in propertyElement.Elements()) { if(child.Name == SRC.Type) { propertyDef.Accessibility = GetAccessModifierFromTypeUseElement(child); propertyDef.ReturnType = ParseTypeUseElement(child, context); } else if(child.Name == SRC.Name) { propertyDef.Name = child.Value; } else if(child.Name == SRC.Block) { //add children from block. This should be the getter/setter methods var blockStatements = child.Elements().Select(e => ParseStatement(e, context)); propertyDef.AddChildStatements(blockStatements); } else { propertyDef.AddChildStatement(ParseStatement(child, context)); } } return propertyDef; }
/// <summary> /// Parses the given <paramref name="aliasElement"/> and creates an ImportStatement or AliasStatement from it. /// </summary> /// <param name="aliasElement">The alias element to parse.</param> /// <param name="context">The parser context to use.</param> /// <returns>An ImportStatement if the element is an import, or an AliasStatement if it is an alias.</returns> protected override Statement ParseAliasElement(XElement aliasElement, ParserContext context) { if (null == aliasElement) { throw new ArgumentNullException("aliasElement"); } if (aliasElement.Name != AliasElementName) { throw new ArgumentException(string.Format("Must be a SRC.{0} element", AliasElementName.LocalName), "aliasElement"); } if (context == null) { throw new ArgumentNullException("context"); } Statement stmt = null; var namespaceElement = aliasElement.Element(SRC.Namespace); if (namespaceElement != null) { //import statement var import = new ImportStatement() { ProgrammingLanguage = ParserLanguage }; import.AddLocation(context.CreateLocation(aliasElement)); var nameElement = namespaceElement.Element(SRC.Name); if (nameElement != null) { import.ImportedNamespace = ParseNameUseElement <NamespaceUse>(nameElement, context); } stmt = import; } else { //alias statement var alias = new AliasStatement() { ProgrammingLanguage = ParserLanguage }; alias.AddLocation(context.CreateLocation(aliasElement)); //TODO: Make sure that using descendant is correct for nameElement var nameElement = aliasElement.Element(SRC.Name); var initElement = aliasElement.Element(SRC.Init); if (initElement != null) { //example: using foo = std::bar; if (nameElement != null) { alias.AliasName = nameElement.Value; } //TODO check this once srcml is updated to see if it's accurate alias.Target = ParseExpression(GetFirstChildExpression(initElement), context); } else { //example: using std::cout; if (nameElement != null) { alias.Target = ParseTypeUseElement(nameElement, context); alias.AliasName = NameHelper.GetLastName(nameElement); } } stmt = alias; } return(stmt); }
private NamespaceUse CreateNamespaceUsePrefix(XElement nameElement, ParserContext context) { IEnumerable<XElement> parentNameElements = Enumerable.Empty<XElement>(); parentNameElements = NameHelper.GetNameElementsExceptLast(nameElement); NamespaceUse current = null, root = null; if(parentNameElements.Any()) { foreach(var element in parentNameElements) { var namespaceUse = new NamespaceUse { Name = element.Value, Location = context.CreateLocation(element, false), ProgrammingLanguage = this.ParserLanguage, }; if(null == root) { root = namespaceUse; } if(current != null) { current.ChildScopeUse = namespaceUse; } current = namespaceUse; } } return root; }
/// <summary> /// Creates a type use element /// </summary> /// <param name="typeUseElement">the element to parse. Must be of a <see cref="ABB.SrcML.SRC.Type"/> or <see cref="ABB.SrcML.SRC.Name"/></param> /// <param name="context">the parser context</param> /// <returns>A Type Use object</returns> public virtual TypeUse ParseTypeUseElement(XElement typeUseElement, ParserContext context) { if(typeUseElement == null) throw new ArgumentNullException("typeUseElement"); XElement typeNameElement; // validate the type use typeUseElement (must be a SRC.Name or SRC.Type) if(typeUseElement.Name == SRC.Type) { typeNameElement = typeUseElement.Elements(SRC.Name).LastOrDefault(); } else if(typeUseElement.Name == SRC.Name) { typeNameElement = typeUseElement; } else { throw new ArgumentException("typeUseElement should be of type type or name", "typeUseElement"); } XElement lastNameElement = null; // this is the name element that identifies the type being used NamedScopeUse prefix = null; // This is the prefix (in A::B::C, this would be the chain A::B) XElement typeParameterArgumentList = null; // the argument list element holds the parameters for generic type uses var typeParameters = Enumerable.Empty<TypeUse>(); // enumerable for the actual generic parameters // get the last name element and the prefix if(typeNameElement != null) { lastNameElement = NameHelper.GetLastNameElement(typeNameElement); prefix = ParseNamedScopeUsePrefix(typeNameElement, context); } // if the last name element exists, then this *may* be a generic type use // go look for the argument list element if(lastNameElement != null) { if(prefix == null) { // if there is no prefix, then the argument list element will be the first sibling of lastNameElement typeParameterArgumentList = lastNameElement.ElementsAfterSelf(SRC.ArgumentList).FirstOrDefault(); } else { // otherwise, it will be the first *child* of lastNameElement typeParameterArgumentList = lastNameElement.Elements(SRC.ArgumentList).FirstOrDefault(); } } if(typeParameterArgumentList != null) { typeParameters = from argument in typeParameterArgumentList.Elements(SRC.Argument) where argument.Elements(SRC.Name).Any() select ParseTypeUseElement(argument.Element(SRC.Name), context); // if this is a generic type use and there is a prefix (A::B::C) then the last name element will actually be the first child of lastNameElement if(prefix != null) { lastNameElement = lastNameElement.Element(SRC.Name); } } // construct the type use var typeUse = new TypeUse() { Name = (lastNameElement != null ? lastNameElement.Value : string.Empty), ParentScope = context.CurrentScope, Location = context.CreateLocation(lastNameElement != null ? lastNameElement : typeUseElement), Prefix = prefix, ProgrammingLanguage = this.ParserLanguage, }; typeUse.AddTypeParameters(typeParameters); typeUse.AddAliases(context.Aliases); return typeUse; }
/// <summary> /// Creates an <see cref="Alias"/> object from a using import (such as using in C++ and C# and import in Java). /// </summary> /// <param name="aliasStatement">The statement to parse. Should be of type <see cref="AliasElementName"/></param> /// <param name="context">The context to place the resulting alias in</param> /// <returns>a new alias object that represents this alias statement</returns> public Alias ParseAliasElement(XElement aliasStatement, ParserContext context) { if(null == aliasStatement) throw new ArgumentNullException("aliasStatement"); if(aliasStatement.Name != AliasElementName) throw new ArgumentException(String.Format("must be a {0} statement", AliasElementName), "usingStatement"); var alias = new Alias() { Location = context.CreateLocation(aliasStatement, true), ProgrammingLanguage = ParserLanguage, }; IEnumerable<XElement> namespaceNames = GetNamesFromAlias(aliasStatement); if(!AliasIsNamespaceImport(aliasStatement)) { var lastNameElement = namespaceNames.LastOrDefault(); namespaceNames = from name in namespaceNames where name.IsBefore(lastNameElement) select name; alias.ImportedNamedScope = new NamedScopeUse() { Name = lastNameElement.Value, Location = context.CreateLocation(lastNameElement), ProgrammingLanguage = ParserLanguage, }; } NamespaceUse current = null; foreach(var namespaceName in namespaceNames) { var use = new NamespaceUse() { Name = namespaceName.Value, Location = context.CreateLocation(namespaceName), ProgrammingLanguage = ParserLanguage, }; if(alias.ImportedNamespace == null) { alias.ImportedNamespace = use; current = use; } else { current.ChildScopeUse = use; current = use; } } return alias; }
/// <summary> /// This is the main function that parses srcML nodes. It selects the appropriate parse element to call and then adds declarations, method calls, and children to it /// </summary> /// <param name="element">The element to parse</param> /// <param name="context">The parser context</param> /// <returns>The scope representing <paramref name="element"/></returns> public virtual Scope ParseElement_Concurrent(XElement element, ParserContext context) { if(element.Name == SRC.Unit) { ParseUnitElement(element, context); } else if(TypeElementNames.Contains(element.Name)) { ParseTypeElement(element, context); } else if(NamespaceElementNames.Contains(element.Name)) { ParseNamespaceElement(element, context); } else if(MethodElementNames.Contains(element.Name)) { ParseMethodElement(element, context); } else { ParseContainerElement(element, context); } IEnumerable<XElement> Elements = GetDeclarationsFromElement(element); foreach(var declarationElement in Elements) { foreach(var declaration in ParseDeclarationElement(declarationElement, context)) { context.CurrentScope.AddDeclaredVariable(declaration); } } IEnumerable<XElement> methodCalls = GetMethodCallsFromElement(element); foreach(var methodCallElement in methodCalls) { var methodCall = ParseCallElement(methodCallElement, context); context.CurrentScope.AddMethodCall(methodCall); } IEnumerable<XElement> children = GetChildContainers(element); ConcurrentQueue<Exception> exceptions = new ConcurrentQueue<Exception>(); ConcurrentQueue<Scope> cq = new ConcurrentQueue<Scope>(); Parallel.ForEach(children, currentChild => { try { var subContext = new ParserContext() { Aliases = context.Aliases, FileUnit = context.FileUnit, }; Scope childScope = ParseElement(currentChild, subContext); cq.Enqueue(childScope); } catch(Exception e) { exceptions.Enqueue(e); } }); if(exceptions.Count > 0) throw new Exception(); while(!cq.IsEmpty) { Scope childScope = new Scope(); cq.TryDequeue(out childScope); context.CurrentScope.AddChildScope(childScope); } var currentScope = context.Pop(); currentScope.AddSourceLocation(context.CreateLocation(element, ContainerIsReference(element))); currentScope.ProgrammingLanguage = ParserLanguage; return currentScope; }
/// <summary> /// Creates a <see cref="Statement"/> object for <paramref name="stmtElement"/>. /// The expression contained within <paramref name="stmtElement"/> will be parsed and placed in /// Statement.Content. /// </summary> /// <param name="stmtElement">The SRC.DeclarationStatement element to parse.</param> /// <param name="context">The context to use.</param> /// <returns>A <see cref="DeclarationStatement"/> corresponding to <paramref name="stmtElement"/>. /// The return type is <see cref="Statement"/> so that subclasses can return another type, as necessary. </returns> protected override Statement ParseDeclarationStatementElement(XElement stmtElement, ParserContext context) { if (stmtElement == null) throw new ArgumentNullException("stmtElement"); if (stmtElement.Name != SRC.DeclarationStatement && stmtElement.Name != SRC.Property) throw new ArgumentException("Must be a SRC.DeclarationStatement or SRC.Property element", "stmtElement"); if (context == null) throw new ArgumentNullException("context"); var stmt = new DeclarationStatement() { ProgrammingLanguage = ParserLanguage, Content = ParseExpression(GetChildExpressions(stmtElement), context) }; stmt.AddLocation(context.CreateLocation(stmtElement)); return stmt; }
/// <summary> /// Creates a NamespaceDefinition object for the given namespace typeUseElement. This must /// be one of the typeUseElement types defined in NamespaceElementNames. /// </summary> /// <param name="namespaceElement">the namespace element</param> /// <param name="context">The parser context</param> /// <returns>a new NamespaceDefinition object</returns> protected override NamespaceDefinition ParseNamespaceElement(XElement namespaceElement, ParserContext context) { if(namespaceElement == null) throw new ArgumentNullException("namespaceElement"); if(!NamespaceElementNames.Contains(namespaceElement.Name)) throw new ArgumentException(string.Format("Not a valid namespace element: {0}", namespaceElement.Name), "namespaceElement"); if(context == null) throw new ArgumentNullException("context"); var nameElement = namespaceElement.Element(SRC.Name); var namespaceName = nameElement != null ? nameElement.Value : string.Empty; var nd = new NamespaceDefinition { Name = namespaceName, ProgrammingLanguage = ParserLanguage, }; nd.AddLocation(context.CreateLocation(namespaceElement)); //add children var blockElement = namespaceElement.Element(SRC.Block); if(blockElement != null) { foreach(var child in blockElement.Elements()) { nd.AddChildStatement(ParseStatement(child, context)); } } return nd; }
/// <summary> /// Creates a resolvable use from an expression /// </summary> /// <param name="element">The element to parse</param> /// <param name="context">The parser context</param> /// <returns>A resolvable use object</returns> // TODO make this fit in with the rest of the parse methods (rename to parse) public virtual IResolvesToType CreateResolvableUse(XElement element, ParserContext context) { var use = new VariableUse() { Location = context.CreateLocation(element, true), ParentScope = context.CurrentScope, ProgrammingLanguage = ParserLanguage, }; return use; }
/// <summary> /// Creates a variable use from the given element. Must be a <see cref="ABB.SrcML.SRC.Expression"/>, <see cref="ABB.SrcML.SRC.Name"/>, or <see cref="ABB.SrcML.SRC.ExpressionStatement"/> /// </summary> /// <param name="element">The element to parse</param> /// <param name="context">The parser context</param> /// <returns>A variable use object</returns> // TODO make this fit in with the rest of the parse methods public virtual VariableUse CreateVariableUse(XElement element, ParserContext context) { XElement nameElement; if(element.Name == SRC.Name) { nameElement = element; } else if(element.Name == SRC.Expression) { nameElement = element.Element(SRC.Name); } else if(element.Name == SRC.ExpressionStatement || element.Name == SRC.Argument) { nameElement = element.Element(SRC.Expression).Element(SRC.Name); } else { throw new ArgumentException("element should be an expression, expression statement, argument, or name", "element"); } var lastNameElement = NameHelper.GetLastNameElement(nameElement); var variableUse = new VariableUse() { Location = context.CreateLocation(lastNameElement, true), Name = lastNameElement.Value, ParentScope = context.CurrentScope, ProgrammingLanguage = ParserLanguage, }; return variableUse; }
/// <summary> /// Parses the given <paramref name="aliasElement"/> and creates an ImportStatement or AliasStatement from it. /// </summary> /// <param name="aliasElement">The alias element to parse.</param> /// <param name="context">The parser context to use.</param> /// <returns>An ImportStatement if the element is an import, or an AliasStatement if it is an alias.</returns> protected override Statement ParseAliasElement(XElement aliasElement, ParserContext context) { if(aliasElement == null) throw new ArgumentNullException("aliasElement"); if(aliasElement.Name != AliasElementName) throw new ArgumentException(string.Format("Must be a SRC.{0} element", AliasElementName.LocalName), "aliasElement"); if(context == null) throw new ArgumentNullException("context"); Statement stmt = null; if(GetTextNodes(aliasElement).Any(n => n.Value.Contains("("))) { //using block stmt = ParseUsingBlockElement(aliasElement, context); } else if(aliasElement.Element(SRC.Init) != null) { //alias var alias = new AliasStatement() {ProgrammingLanguage = ParserLanguage}; alias.AddLocation(context.CreateLocation(aliasElement)); var nameElement = aliasElement.Element(SRC.Name); if(nameElement != null) { alias.AliasName = nameElement.Value; } var initElement = aliasElement.Element(SRC.Init); alias.Target = ParseExpression<TypeContainerUse>(GetFirstChildExpression(initElement), context); stmt = alias; } else { //import var import = new ImportStatement() {ProgrammingLanguage = ParserLanguage}; import.AddLocation(context.CreateLocation(aliasElement)); var nameElement = aliasElement.Element(SRC.Name); if(nameElement != null) { import.ImportedNamespace = ParseNameUseElement<NamespaceUse>(nameElement, context); } stmt = import; } return stmt; }
/// <summary> /// Parses the given <paramref name="usingElement"/> and creates a <see cref="UsingBlockStatement"/> from it. /// </summary> /// <param name="usingElement">The SRC.Using element to parse.</param> /// <param name="context">The parser context to use.</param> /// <returns>A UsingBlockStatement created from the given usingElement.</returns> protected override UsingBlockStatement ParseUsingBlockElement(XElement usingElement, ParserContext context) { if(usingElement == null) throw new ArgumentNullException("usingElement"); if(usingElement.Name != SRC.Using_Stmt) throw new ArgumentException("Must be a SRC.Using element", "usingElement"); if(context == null) throw new ArgumentNullException("context"); var usingStmt = new UsingBlockStatement() {ProgrammingLanguage = ParserLanguage}; usingStmt.AddLocation(context.CreateLocation(usingElement)); foreach(var child in usingElement.Elements()) { if(child.Name == SRC.Init) { //TODO: waiting for update to srcml usingStmt.Initializer = ParseExpression(GetChildExpressions(child), context); } else if(child.Name == SRC.Block) { var blockStatements = child.Elements().Select(e => ParseStatement(e, context)); usingStmt.AddChildStatements(blockStatements); } else { usingStmt.AddChildStatement(ParseStatement(child, context)); } } return usingStmt; }
/// <summary> /// Creates a NamespaceDefinition object from the given Java package element. /// This will create a NamespaceDefinition for each component of the name, e.g. com.java.foo.bar, and link them as children of each other. /// This will not add any child statements to the bottom namespace. /// </summary> /// <param name="packageElement">The SRC.Package element to parse.</param> /// <param name="context">The parser context to use.</param> /// <returns>A NamespaceDefinition corresponding to <paramref name="packageElement"/>.</returns> protected override NamespaceDefinition ParseNamespaceElement(XElement packageElement, ParserContext context) { if(packageElement == null) throw new ArgumentNullException("packageElement"); if(packageElement.Name != SRC.Package) throw new ArgumentException("must be a SRC.Package", "packageElement"); if(context == null) throw new ArgumentNullException("context"); var nameElement = packageElement.Element(SRC.Name); if(nameElement == null) { throw new ParseException(context.FileName, packageElement.GetSrcLineNumber(), packageElement.GetSrcLinePosition(), this, "No SRC.Name element found in namespace.", null); } //parse the name and create a NamespaceDefinition for each component NamespaceDefinition topNS = null; NamespaceDefinition lastNS = null; foreach(var name in NameHelper.GetNameElementsFromName(nameElement)) { var newNS = new NamespaceDefinition { Name = name.Value, ProgrammingLanguage = ParserLanguage }; newNS.AddLocation(context.CreateLocation(name)); if(topNS == null) { topNS = newNS; } if(lastNS != null) { lastNS.AddChildStatement(newNS); } lastNS = newNS; } return topNS; }
/// <summary> /// Parses a literal use element /// </summary> /// <param name="literalElement">The literal element to parse</param> /// <param name="context">The parser context</param> /// <returns>A literal use object</returns> public virtual LiteralUse ParseLiteralElement(XElement literalElement, ParserContext context) { if(literalElement == null) throw new ArgumentNullException("literalElement"); if(literalElement.Name != LIT.Literal) throw new ArgumentException("should be a literal", "literalElement"); var kind = LiteralUse.GetLiteralKind(literalElement); string typeName = string.Empty; var use = new LiteralUse() { Kind = kind, Location = context.CreateLocation(literalElement), Name = GetTypeForLiteralValue(kind, literalElement.Value), ParentScope = context.CurrentScope, }; return use; }
/// <summary> /// Parses a java file unit. This handles the "package" directive by calling /// <see cref="ParseNamespaceElement"/> /// </summary> /// <param name="unitElement">The file unit to parse.</param> /// <param name="context">The parser context to use.</param> protected override NamespaceDefinition ParseUnitElement(XElement unitElement, ParserContext context) { if(null == unitElement) throw new ArgumentNullException("unitElement"); if(SRC.Unit != unitElement.Name) throw new ArgumentException("should be a SRC.Unit", "unitElement"); if(context == null) throw new ArgumentNullException("context"); context.FileUnit = unitElement; //var aliases = from aliasStatement in GetAliasElementsForFile(unitElement) // select ParseAliasElement(aliasStatement, context); //context.Aliases = new Collection<Alias>(aliases.ToList()); //create a global namespace for the file unit var namespaceForUnit = new NamespaceDefinition() {ProgrammingLanguage = ParserLanguage}; namespaceForUnit.AddLocation(context.CreateLocation(unitElement)); NamespaceDefinition bottomNamespace = namespaceForUnit; //create a namespace for the package, and attach to global namespace var packageElement = unitElement.Element(SRC.Package); if(packageElement != null) { var namespaceForPackage = ParseNamespaceElement(packageElement, context); namespaceForUnit.AddChildStatement(namespaceForPackage); bottomNamespace = namespaceForPackage.GetDescendantsAndSelf<NamespaceDefinition>().Last(); } //add children to bottom namespace foreach(var child in unitElement.Elements()) { var childStmt = ParseStatement(child, context); if(childStmt != null) { bottomNamespace.AddChildStatement(childStmt); } } return namespaceForUnit; }
/// <summary> /// Creates a ForStatement or ForeachStatement from the given element. /// </summary> /// <param name="forElement">The SRC.For element to parse.</param> /// <param name="context">The parser context to use.</param> /// <returns>A ForStatement or ForeachStatement corresponding to forElement.</returns> protected override ConditionBlockStatement ParseForElement(XElement forElement, ParserContext context) { if(forElement == null) throw new ArgumentNullException("forElement"); if(forElement.Name != SRC.For) throw new ArgumentException("Must be a SRC.For element", "forElement"); if(context == null) throw new ArgumentNullException("context"); var controlElement = forElement.Element(SRC.Control); if(controlElement.Element(SRC.Condition) != null) { //this is a standard for-loop, use the base processing return base.ParseForElement(forElement, context); } //else, this is a Java-style foreach loop var foreachStmt = new ForeachStatement() {ProgrammingLanguage = ParserLanguage}; foreachStmt.AddLocation(context.CreateLocation(forElement)); foreach(var child in forElement.Elements()) { if(child.Name == SRC.Init) { //fill in condition/initializer var expElement = GetFirstChildExpression(child); if(expElement != null) { foreachStmt.Condition = ParseExpression(expElement, context); } } else if(child.Name == SRC.Block) { //add children from block var blockStatements = child.Elements().Select(e => ParseStatement(e, context)); foreachStmt.AddChildStatements(blockStatements); } else { //add child foreachStmt.AddChildStatement(ParseStatement(child, context)); } } return foreachStmt; }
/// <summary> /// Parses an element corresponding to a type definition and creates a TypeDefinition object /// </summary> /// <param name="typeElement">The type element to parse. This must be one of the elements contained in TypeElementNames.</param> /// <param name="context">The parser context</param> /// <returns>A TypeDefinition parsed from the element</returns> protected override TypeDefinition ParseTypeElement(XElement typeElement, ParserContext context) { if(null == typeElement) throw new ArgumentNullException("typeElement"); if(context == null) throw new ArgumentNullException("context"); var typeDefinition = new TypeDefinition() { Accessibility = GetAccessModifierForType(typeElement), Kind = XNameMaps.GetKindForXElement(typeElement), Name = GetNameForType(typeElement), ProgrammingLanguage = ParserLanguage }; typeDefinition.AddLocation(context.CreateLocation(typeElement, ContainerIsReference(typeElement))); foreach(var parentTypeElement in GetParentTypeUseElements(typeElement)) { var parentTypeUse = ParseTypeUseElement(parentTypeElement, context); typeDefinition.AddParentType(parentTypeUse); } var typeBlock = typeElement.Element(SRC.Block); if(typeBlock != null) { foreach(var child in typeBlock.Elements()) { if(child.Name == SRC.Private) { typeDefinition.AddChildStatements(ParseClassChildren(child, context, AccessModifier.Private)); } else if(child.Name == SRC.Protected) { typeDefinition.AddChildStatements(ParseClassChildren(child, context, AccessModifier.Protected)); } else if(child.Name == SRC.Public) { typeDefinition.AddChildStatements(ParseClassChildren(child, context, AccessModifier.Public)); } else { typeDefinition.AddChildStatement(ParseStatement(child, context)); } } } return typeDefinition; }
/// <summary> /// Parses the given <paramref name="aliasElement"/> and creates an ImportStatement or AliasStatement from it. /// </summary> /// <param name="aliasElement">The alias element to parse.</param> /// <param name="context">The parser context to use.</param> /// <returns>An ImportStatement if the element is an import, or an AliasStatement if it is an alias.</returns> protected override Statement ParseAliasElement(XElement aliasElement, ParserContext context) { if(aliasElement == null) throw new ArgumentNullException("aliasElement"); if(aliasElement.Name != AliasElementName) throw new ArgumentException(string.Format("Must be a SRC.{0} element", AliasElementName.LocalName), "aliasElement"); if(context == null) throw new ArgumentNullException("context"); var isNamespaceImport = aliasElement.Descendants(SRC.Name).Any(n => n.Value.Contains("*")); //Elements("name").Any(n => n.Value.Contains("*")); //).Any(n => n.Value.Contains("*")); Statement stmt = null; if(isNamespaceImport) { //namespace import var import = new ImportStatement() {ProgrammingLanguage = ParserLanguage}; import.AddLocation(context.CreateLocation(aliasElement)); var nameElement = aliasElement.Element(SRC.Name); if(nameElement != null) { //we have an import that ends with .*. We remove the . and *. nameElement.LastNode.Remove();//remove * nameElement.LastNode.Remove();//remove . import.ImportedNamespace = ParseNameUseElement<NamespaceUse>(nameElement, context); //TODO: fix to handle the trailing operator tag } stmt = import; } else { //importing a single member, i.e. an alias var alias = new AliasStatement() {ProgrammingLanguage = ParserLanguage}; alias.AddLocation(context.CreateLocation(aliasElement)); var nameElement = aliasElement.Element(SRC.Name); if(nameElement != null) { alias.Target = ParseExpression(nameElement, context); alias.AliasName = NameHelper.GetLastName(nameElement); } stmt = alias; } return stmt; }
/// <summary> /// Parses the given <paramref name="aliasElement"/> and creates an ImportStatement or AliasStatement from it. /// </summary> /// <param name="aliasElement">The alias element to parse.</param> /// <param name="context">The parser context to use.</param> /// <returns>An ImportStatement if the element is an import, or an AliasStatement if it is an alias.</returns> protected override Statement ParseAliasElement(XElement aliasElement, ParserContext context) { if(null == aliasElement) throw new ArgumentNullException("aliasElement"); if(aliasElement.Name != AliasElementName) throw new ArgumentException(string.Format("Must be a SRC.{0} element", AliasElementName.LocalName), "aliasElement"); if(context == null) throw new ArgumentNullException("context"); Statement stmt = null; var namespaceElement = aliasElement.Element(SRC.Namespace); if(namespaceElement != null) { //import statement var import = new ImportStatement() {ProgrammingLanguage = ParserLanguage}; import.AddLocation(context.CreateLocation(aliasElement)); var nameElement = namespaceElement.Element(SRC.Name); if(nameElement != null) { import.ImportedNamespace = ParseNameUseElement<NamespaceUse>(nameElement, context); } stmt = import; } else { //alias statement var alias = new AliasStatement() {ProgrammingLanguage = ParserLanguage}; alias.AddLocation(context.CreateLocation(aliasElement)); //TODO: Make sure that using descendant is correct for nameElement var nameElement = aliasElement.Element(SRC.Name); var initElement = aliasElement.Element(SRC.Init); if(initElement != null) { //example: using foo = std::bar; if(nameElement != null) { alias.AliasName = nameElement.Value; } //TODO check this once srcml is updated to see if it's accurate alias.Target = ParseExpression(GetFirstChildExpression(initElement), context); } else { //example: using std::cout; if(nameElement != null) { alias.Target = ParseTypeUseElement(nameElement, context); alias.AliasName = NameHelper.GetLastName(nameElement); } } stmt = alias; } return stmt; }
/// <summary> /// This is the main function that parses srcML nodes. It selects the appropriate parse element to call and then adds declarations, method calls, and children to it /// </summary> /// <param name="element">The element to parse</param> /// <param name="context">The parser context</param> /// <returns>The scope representing <paramref name="element"/></returns> public virtual Scope ParseElement(XElement element, ParserContext context) { if(element.Name == SRC.Unit) { ParseUnitElement(element, context); } else if(TypeElementNames.Contains(element.Name)) { ParseTypeElement(element, context); } else if(NamespaceElementNames.Contains(element.Name)) { ParseNamespaceElement(element, context); } else if(MethodElementNames.Contains(element.Name)) { ParseMethodElement(element, context); } else { ParseContainerElement(element, context); } IEnumerable<XElement> Elements = GetDeclarationsFromElement(element); foreach(var declarationElement in Elements) { foreach(var declaration in ParseDeclarationElement(declarationElement, context)) { context.CurrentScope.AddDeclaredVariable(declaration); } } IEnumerable<XElement> methodCalls = GetMethodCallsFromElement(element); foreach(var methodCallElement in methodCalls) { var methodCall = ParseCallElement(methodCallElement, context); context.CurrentScope.AddMethodCall(methodCall); } IEnumerable<XElement> children = GetChildContainers(element); foreach(var childElement in children) { //var subContext = new ParserContext() { // Aliases = context.Aliases, // FileUnit = context.FileUnit, //}; var childScope = ParseElement(childElement, context); //Scope childScope = ParseElement(childElement, subContext); context.CurrentScope.AddChildScope(childScope); } var currentScope = context.Pop(); currentScope.AddSourceLocation(context.CreateLocation(element, ContainerIsReference(element))); currentScope.ProgrammingLanguage = ParserLanguage; return currentScope; }