private void ProcessChild(SyntaxNode syntaxNode, NodeDetails previousNodeDetails) { switch (syntaxNode.Kind()) { case SyntaxKind.ClassDeclaration: { ClassDeclarationSyntax classDeclarationSyntax = (ClassDeclarationSyntax)syntaxNode; if (classDeclarationSyntax.AttributeLists.Count > 0) { var classDetails = classDeclarationSyntax.GetClassDetails(); var classHashes = Generator.Get(classDetails.Attribute, classDetails.AttributeArgument).Select(generator => { var key = generator.GetEnumeratedType(); var value = generator.AddClass(classDetails, previousNodeDetails.ParentHashes == null ? string.Empty : previousNodeDetails.ParentHashes[key]); return(new KeyValuePair <XChains, string>(key, value)); }).ToDictionary(x => x.Key, x => x.Value); if (classDetails.IsModel) { Models.Add(classDetails.Name, new List <ModelProperty>()); } classDetails.ParentHashes = classHashes; var singleLineComments = classDeclarationSyntax.DescendantTrivia().Where(descendent => descendent.IsKind(SyntaxKind.SingleLineCommentTrivia)); foreach (var singleLineComment in singleLineComments) { var comment = singleLineComment.ToFullString().Split("//").Last().Trim(); if (Regex.IsMatch(syntaxNode.ToString(), Constants.XOnRegex) && classHashes.ContainsKey(XChains.Ethereum)) { var expressionDetails = singleLineComment.GetExpressionDetails(); Generator.Get(Constants.XOn, Constants.XOnEthereumChain).ForEach(generator => { generator.AddExpression(expressionDetails, classHashes.Where(classHash => classHash.Key == XChains.Ethereum).FirstOrDefault().Value); }); } } foreach (var member in classDeclarationSyntax.Members) { ProcessChild(member, classDetails); } } } break; case SyntaxKind.FieldDeclaration: { FieldDeclarationSyntax fieldDeclarationSyntax = (FieldDeclarationSyntax)syntaxNode; if (previousNodeDetails != null && previousNodeDetails.GetType() == typeof(ClassDetails)) { var fieldDetails = fieldDeclarationSyntax.GetFieldDetails(); if (fieldDetails.Attribute.Equals(string.Empty)) { fieldDetails.Attribute = previousNodeDetails.Attribute; fieldDetails.AttributeArgument = previousNodeDetails.AttributeArgument; } var fieldHashes = Generator.Get(fieldDetails.Attribute, fieldDetails.AttributeArgument).Select(generator => { var key = generator.GetEnumeratedType(); var value = generator.AddField(fieldDetails, previousNodeDetails.ParentHashes == null ? string.Empty : previousNodeDetails.ParentHashes[key]); return(new KeyValuePair <XChains, string>(key, value)); }).ToDictionary(x => x.Key, x => x.Value); var parsedPreviousNodeDetails = (ClassDetails)previousNodeDetails; if (parsedPreviousNodeDetails.IsModel) { foreach (var fieldHash in fieldHashes) { Models[parsedPreviousNodeDetails.Name].Add(new ModelProperty { Location = fieldHash.Key, Hash = fieldHash.Value, IsParameter = fieldDetails.IsParameter }); } } } else { throw new InvalidExpressionException("Field declared in incorrect place..."); } } break; case SyntaxKind.ConstructorDeclaration: { ConstructorDeclarationSyntax constructorDeclarationSyntax = (ConstructorDeclarationSyntax)syntaxNode; if (previousNodeDetails != null && previousNodeDetails.GetType() == typeof(ClassDetails)) { var constructorDetails = constructorDeclarationSyntax.GetConstructorDetails(); if (constructorDetails.Attribute.Equals(string.Empty)) { constructorDetails.Attribute = previousNodeDetails.Attribute; constructorDetails.AttributeArgument = previousNodeDetails.AttributeArgument; } var constructorHashes = Generator.Get(constructorDetails.Attribute, constructorDetails.AttributeArgument).Select(generator => { var key = generator.GetEnumeratedType(); var value = generator.AddConstructor(constructorDetails, previousNodeDetails.ParentHashes == null ? string.Empty : previousNodeDetails.ParentHashes[key]); return(new KeyValuePair <XChains, string>(key, value)); }).ToDictionary(x => x.Key, x => x.Value); var statementQueue = new Queue <SyntaxNode>(constructorDeclarationSyntax.Body.Statements); string lastKnownBlockHash = string.Empty; while (statementQueue.Count > 0) { var member = statementQueue.Dequeue(); if (Regex.IsMatch(member.ToString(), Constants.XOnRegex) && statementQueue.Peek().Kind() == SyntaxKind.Block) { var onChainArguments = member.ToString().Split('(', ')')[1].Split(',').ToList(); var blockAttribute = onChainArguments.First().Contains("\"") ? onChainArguments.First().Replace("\"", "") : onChainArguments.First(); var argumentList = onChainArguments.Skip(1).ToList().Select(argument => argument.Trim()).ToList(); constructorDetails.Arguments = argumentList; constructorDetails.ParentHashes = constructorHashes.Where(methodHash => methodHash.Key.ToString() == blockAttribute).ToDictionary(methodHash => methodHash.Key, methodHash => methodHash.Value); constructorDetails.Attribute = Constants.XOn; constructorDetails.AttributeArgument = blockAttribute; Generator.Get(Constants.XOn, blockAttribute).ForEach(generator => generator.AddMethodParameters(constructorDetails, constructorHashes.Where(methodHash => methodHash.Key.ToString() == blockAttribute).First().Value, GetModelParameters, Models.Select(model => model.Key).ToList())); ProcessChild(statementQueue.Dequeue(), constructorDetails); lastKnownBlockHash = blockAttribute.Equals(Constants.XOnDesktop) ? constructorHashes.First().Value : string.Empty; } else { constructorDetails.ParentHashes = constructorHashes; constructorDetails.Attribute = constructorDetails.Attribute; constructorDetails.AttributeArgument = constructorDetails.AttributeArgument; ProcessChild(member, constructorDetails); } } } else { throw new InvalidExpressionException("Constructor declared in incorrect place..."); } } break; case SyntaxKind.MethodDeclaration: { MethodDeclarationSyntax methodDeclarationSyntax = (MethodDeclarationSyntax)syntaxNode; if (previousNodeDetails != null && previousNodeDetails.GetType() == typeof(ClassDetails)) { var methodDetails = methodDeclarationSyntax.GetMethodDetails(); if (methodDetails.Attribute.Equals(string.Empty)) { methodDetails.Attribute = previousNodeDetails.Attribute; methodDetails.AttributeArgument = previousNodeDetails.AttributeArgument; } var methodHashes = Generator.Get(string.IsNullOrEmpty(methodDetails.Attribute) ? previousNodeDetails.Attribute : methodDetails.Attribute, string.IsNullOrEmpty(methodDetails.Attribute) ? previousNodeDetails.AttributeArgument : methodDetails.AttributeArgument).Select(generator => { var key = generator.GetEnumeratedType(); var value = generator.AddMethod(methodDetails, previousNodeDetails.ParentHashes == null ? string.Empty : previousNodeDetails.ParentHashes[key]); return(new KeyValuePair <XChains, string>(key, value)); }).ToDictionary(x => x.Key, x => x.Value); var statementQueue = new Queue <SyntaxNode>(methodDeclarationSyntax.Body.Statements); string lastKnownBlockHash = string.Empty; while (statementQueue.Count > 0) { var member = statementQueue.Dequeue(); if (Regex.IsMatch(member.ToString(), Constants.XOnRegex) && statementQueue.Peek().Kind() == SyntaxKind.Block) { var onChainArguments = member.ToString().Split('(', ')')[1].Split(',').ToList(); var blockAttribute = onChainArguments.First().Contains("\"") ? onChainArguments.First().Replace("\"", "") : onChainArguments.First(); var argumentList = onChainArguments.Skip(1).ToList().Select(argument => argument.Trim()).ToList(); var isSynchronous = member.ToString().StartsWith(Constants.SynchronousEscapeCharacter); methodDetails.Arguments = argumentList; methodDetails.IsSynchronous = isSynchronous; methodDetails.ParentHashes = methodHashes.Where(methodHash => methodHash.Key.ToString() == blockAttribute).ToDictionary(methodHash => methodHash.Key, methodHash => methodHash.Value); methodDetails.Attribute = Constants.XOn; methodDetails.AttributeArgument = blockAttribute; Generator.Get(Constants.XOn, blockAttribute).ForEach(generator => { var xCallArguments = generator.AddMethodParameters(methodDetails, methodHashes.Where(methodHash => methodHash.Key.ToString() == blockAttribute).First().Value, GetModelParameters, Models.Select(model => model.Key).ToList()); generator.AddMethodReturnTypes(methodDetails, methodHashes.Where(methodHash => methodHash.Key.ToString() == blockAttribute).First().Value, GetModelReturnsTypes, Models.Select(model => model.Key).ToList()); if (!blockAttribute.Equals(Constants.XOnDesktop)) { Generator.Get(Constants.XOn, Constants.XOnDesktop).ForEach(generator => { var isReturnStatement = member.ToString().StartsWith("return"); generator.AddExpression(new ExpressionDetails() { Statement = (isReturnStatement ? "return " : string.Empty) + (methodDetails.IsSynchronous ? "await " : string.Empty) + string.Format(Constants.XCallExpression, Constants.XOnEthereumChain, methodDetails.Identifier, xCallArguments) }, lastKnownBlockHash); }); } }); ProcessChild(statementQueue.Dequeue(), methodDetails); lastKnownBlockHash = blockAttribute.Equals(Constants.XOnDesktop) ? methodHashes.First().Value : string.Empty; } else { methodDetails.ParentHashes = methodHashes; methodDetails.Attribute = methodDetails.Attribute; methodDetails.AttributeArgument = methodDetails.AttributeArgument; ProcessChild(member, methodDetails); } } } else { throw new InvalidExpressionException("Method declared in incorrect place..."); } } break; case SyntaxKind.SingleLineCommentTrivia: case SyntaxKind.IfStatement: case SyntaxKind.ReturnStatement: case SyntaxKind.ExpressionStatement: case SyntaxKind.LocalDeclarationStatement: { if (previousNodeDetails != null) { var expressionDetails = syntaxNode.GetExpressionDetails(); var statementHashes = Generator.Get(previousNodeDetails.Attribute, previousNodeDetails.AttributeArgument).Select(generator => { var key = generator.GetEnumeratedType(); var value = generator.AddExpression(expressionDetails, previousNodeDetails.ParentHashes == null ? string.Empty : previousNodeDetails.ParentHashes[key], Models.Select(model => model.Key).ToList()); return(new KeyValuePair <XChains, string>(key, value)); }).ToDictionary(x => x.Key, x => x.Value); } else { throw new InvalidExpressionException("Expression declared in incorrect place..."); } } break; case SyntaxKind.Block: { BlockSyntax blockSyntax = (BlockSyntax)syntaxNode; if (previousNodeDetails != null) { foreach (var child in blockSyntax.ChildNodes()) { ProcessChild(child, previousNodeDetails); } } else { throw new InvalidExpressionException("Block declared in incorrect place..."); } break; } default: { foreach (var member in syntaxNode.ChildNodes()) { ProcessChild(member, new NodeDetails()); } break; } } }