/// <summary> /// Check if the given commented text is one of a Function declaration Header, if so the text is added to the /// Function Data commented header string buffer. /// </summary> /// <param name="nodes">The nodes indices that can correspond to afUnction Declaration node</param> /// <param name="text">The Commented Text</param> private void CheckFunctionDeclCommentedheader(LinearNodeSourceCodeMapper mapper, List <int> nodes, string text) { if (nodes == null) { return; } if (text == null) { return; } if (text.Length == 0) { return; } foreach (int node in nodes) { if (node >= 0 && mapper.Nodes[node] is LinearNodeSourceCodeMapper.NodeFunctionData) { LinearNodeSourceCodeMapper.NodeFunctionData fundata = (LinearNodeSourceCodeMapper.NodeFunctionData)mapper.Nodes[node]; if (fundata.CommentedHeader.Length == 0) {//Add a first empty comment line TextLineSnapshot h = new TextLineSnapshot(-1, "*", null); string crlf = ""; foreach (var hl in Indent(h, null)) { fundata.CommentedHeader.Append(crlf); fundata.CommentedHeader.Append(hl.Text.TrimEnd()); crlf = Environment.NewLine; } fundata.CommentedHeader.Append(crlf); } fundata.CommentedHeader.Append(text); fundata.CommentedHeader.Append(Environment.NewLine); } } }
/// <summary> /// Perform a linear Generation /// //1) A Non commented line with no Associated nodes is generated without any change. /// //2) If the line is commented then first comment all following lines that have the same intersection with the corresponding target Nodes. /// //3) For each node related to a line, and not already generated the corresponding code. /// //4) Flush of Function declations. /// <param name="mapper">The linearization representation</param> /// <param name="Input">Input source lines</param> /// <returns>The Generated Source Document</returns> /// </summary> private SourceText LinearGeneration <A>(LinearNodeSourceCodeMapper mapper, IReadOnlyList <A> Input) where A : ITextLine { SourceText targetSourceText = new GapSourceText(); //Stack Used to save current generation buffer when switching in a function declaration generation. //Beacuse a function declartion has its own buffer. Stack <SourceText> stackOuterBuffer = new Stack <SourceText>(); Stack <SourceText> stackLocalBuffer = new Stack <SourceText>(); //Bit Array of Generated Nodes. BitArray generated_node = new BitArray(mapper.NodeCount); //For detecting line having characters in columns [73-80] Lines_73_80_Flags = new HashSet <int>(); //The previous line generation buffer StringSourceText previousBuffer = null; for (int i = 0; i < mapper.LineData.Length; i++) { //-------------------------------------------------------------------------------------------------------------- //1) A Non commented line with no Associated nodes is generated without any change. if (!mapper.CommentedLines[i] && mapper.LineData[i].LineNodes == null) { //If there was a previous buffer ==> Flush it if (previousBuffer != null) { if (!mapper.IsGeneratedEmptyBuffer(previousBuffer)) { AppendBufferContent(targetSourceText, previousBuffer); } previousBuffer = null; } string text = Input[i].Text; if (mapper.LineData[i].Buffer != null) {//This line has been assigned a target Buffer mapper.LineData[i].Buffer.Insert(text, targetSourceText.Size, targetSourceText.Size); mapper.LineData[i].Buffer.Insert(Environment.NewLine, targetSourceText.Size, targetSourceText.Size); } else { targetSourceText.Insert(text, targetSourceText.Size, targetSourceText.Size); targetSourceText.Insert(Environment.NewLine, targetSourceText.Size, targetSourceText.Size); } continue; } //-------------------------------------------------------------------------------------------------------------- //2) If the line is commented then first comment all following lines that have the same intersection with // the corresponding target Nodes. List <int> line_nodes = mapper.LineData[i].LineNodes; //If there was a previous buffer ==> Flush it if (previousBuffer != null && mapper.CommentedLines[i]) { if (!mapper.IsGeneratedEmptyBuffer(previousBuffer)) { AppendBufferContent(targetSourceText, previousBuffer); } previousBuffer = null; } for (int j = i; mapper.CommentedLines[j]; j++) { List <int> current_nodes = mapper.LineData[j].LineNodes; if (!LinearNodeSourceCodeMapper.HasIntersection(line_nodes, current_nodes)) { break;//This commented line has no nodes which intersect with the previous line. } IEnumerable <ITextLine> lines = Indent(Input[j], true); foreach (var line in lines) { string text = line.Text.TrimEnd(); targetSourceText.Insert(text, targetSourceText.Size, targetSourceText.Size); targetSourceText.Insert(Environment.NewLine, targetSourceText.Size, targetSourceText.Size); CheckFunctionDeclCommentedheader(mapper, current_nodes, text); } mapper.CommentedLines[j] = false;//This commented line has been generated now line_nodes = current_nodes; } //-------------------------------------------------------------------------------------------------------------- //3)For each node related to this line, and not already generated. line_nodes = mapper.LineData[i].LineNodes; foreach (int node_index in line_nodes) { if (node_index == -1 || mapper.Nodes[node_index].node.IsFlagSet(Node.Flag.GeneratorCanIgnoreIt)) {//bad Node continue; } if (generated_node[node_index]) { continue; //Already Generated. } bool bFunctionBodyNode = mapper.Nodes[node_index].FunctionBodyNode != null; //Is this node in a function body ? StringSourceText curSourceText = mapper.Nodes[node_index].Buffer; if (curSourceText != previousBuffer && previousBuffer != null) {//Flush previous buffer if (!mapper.IsGeneratedEmptyBuffer(previousBuffer)) { AppendBufferContent(targetSourceText, previousBuffer); } previousBuffer = null; } Node node = mapper.Nodes[node_index].node; bool bGenerated = node is Generated; bool bForceGenerateLines = true; if (!bGenerated) { //This Node is not Generated: If it removed then remove its source code otherwise do Nothing it is already in the source buffer. bForceGenerateLines = false; if (mapper.Nodes[node_index].Removed) {//If this node is removed //var sourceLine = TargetDocument[i]; Position from = mapper.Nodes[node_index].From; Position to = mapper.Nodes[node_index].To; //Delete <==> Replace with blanks ReplaceByBlanks(curSourceText, from.Pos, to.Pos); } else if (mapper.Nodes[node_index].node.IsFlagSet(Node.Flag.ForceGetGeneratedLines)) {//As lines to generate and replace bForceGenerateLines = true; } } if (bForceGenerateLines) { bool bIsFunctionDecl = mapper.Nodes[node_index] is LinearNodeSourceCodeMapper.NodeFunctionData; bool bFirst = true; Position from = mapper.Nodes[node_index].From; Position to = mapper.Nodes[node_index].To; bool bIsGenerateAndReplace = node is GeneratedAndReplace; if (bIsGenerateAndReplace) {//The node has a source code that must be replaced string code = (node as GeneratedAndReplace).ReplaceCode; GenerateIntoBufferCheckLineExceed(from, to, curSourceText, code, i + 1); } else { foreach (var line in NodeLines(node, generated_node)) { bool bInsertSplit = false; StringWriter sw = new StringWriter(); if (bFirst && !bIsFunctionDecl && curSourceText != null) {//The first element don't ident it just insert it a the right position //issue #892 => Anyway Handle splitting sw.WriteLine(line.Text); bFirst = false; bInsertSplit = true; } else { foreach (var l in Indent(line, null)) { sw.WriteLine(l.Text.TrimEnd()); } } sw.Flush(); string text = sw.ToString(); if (bIsFunctionDecl) { //This the Function Header output. LinearNodeSourceCodeMapper.NodeFunctionData funData = mapper.Nodes[node_index] as LinearNodeSourceCodeMapper.NodeFunctionData; int f = Math.Min(from.Pos, curSourceText.Size); int t = Math.Min(to.Pos, curSourceText.Size); if (f != t) { //Create a the erase string to erase in the original source code //The Function header. //Erase in the original source code the Function header? ReplaceByBlanks(curSourceText, f, t); //Output the pre-stored comment header InsertLineMaybeSplit(funData.FunctionDeclBuffer, funData.CommentedHeader.ToString(), funData.FunctionDeclBuffer.Size, funData.FunctionDeclBuffer.Size, bInsertSplit); } //Insert the sequence InsertLineMaybeSplit(funData.FunctionDeclBuffer, text, funData.FunctionDeclBuffer.Size, funData.FunctionDeclBuffer.Size, bInsertSplit); } else { if (curSourceText == null) { InsertLineMaybeSplit(targetSourceText, text, targetSourceText.Size, targetSourceText.Size, bInsertSplit); } else { InsertLineMaybeSplit(curSourceText, text, Math.Min(from.Pos, curSourceText.Size), Math.Min(to.Pos, curSourceText.Size), bInsertSplit); } } from = to; sw.Close(); } } //Don't pad in case of replacement or insertion in a function declaration if (!bIsGenerateAndReplace && !bIsFunctionDecl) { //Pad a splitted segment if (mapper.Nodes[node_index].Positions != null) { int span = mapper.Nodes[node_index].Positions.Item3; string pad = new string(' ', span); curSourceText.Insert(pad, to.Pos, to.Pos); } } if (bIsFunctionDecl) { //Switch in function declaration -> push the current buffers LinearNodeSourceCodeMapper.NodeFunctionData funData = mapper.Nodes[node_index] as LinearNodeSourceCodeMapper.NodeFunctionData; stackLocalBuffer.Push(curSourceText); stackOuterBuffer.Push(targetSourceText); //Now Generate in Function Declaration Buffer. targetSourceText = funData.FunctionDeclBuffer; curSourceText = null; } } //This node is now generated. generated_node[node_index] = true; if (mapper.Nodes[node_index].node.IsFlagSet(Node.Flag.EndFunctionDeclarationNode)) { //Leaving function declaration --> Pop saved buffers. if (previousBuffer != null) { if (!mapper.IsGeneratedEmptyBuffer(previousBuffer)) { AppendBufferContent(targetSourceText, previousBuffer); } previousBuffer = null; } System.Diagnostics.Debug.Assert(stackOuterBuffer.Count > 0 && stackLocalBuffer.Count > 0); if (stackOuterBuffer.Count > 0 && stackLocalBuffer.Count > 0) { targetSourceText = stackOuterBuffer.Pop(); curSourceText = (StringSourceText)stackLocalBuffer.Pop(); } previousBuffer = curSourceText; } else { previousBuffer = curSourceText; } } //-------------------------------------------------------------------------------------------------------------- } //If there was a previous buffer ==> Flush it if (previousBuffer != null) { if (!mapper.IsGeneratedEmptyBuffer(previousBuffer)) { AppendBufferContent(targetSourceText, previousBuffer); } previousBuffer = null; } //-------------------------------------------------------------------------------------------------------------- //4)//Flush of Function declation body foreach (int fun_index in mapper.FunctionDeclarationNodeIndices) { LinearNodeSourceCodeMapper.NodeFunctionData funData = mapper.Nodes[fun_index] as LinearNodeSourceCodeMapper.NodeFunctionData; AppendBufferContent(targetSourceText, funData.FunctionDeclBuffer); } //5)//Generate Line Exceed Diagnostics GenerateExceedLineDiagnostics(); return(targetSourceText); }