/// <summary> /// Directly replace the the corresponding Segment by Blanks, preserving '\r' and '\n' /// characters. /// </summary> /// <param name="curSourceText"></param> /// <param name="from">The start position in the buffer</param> /// <param name="to">The ending position in the buffer</param> private void ReplaceByBlanks(StringSourceText sourceText, int from, int to) { for (int i = from; i < to; i++) { char c = sourceText[i]; sourceText[i] = (c == '\r' || c == '\n' || Char.IsWhiteSpace(c)) ? c : ' '; } }
/// <summary> /// Create a Delete string Corresponding to a segment in a buffer. /// We want to create a replacement string that only contains whitespaces /// and '\r' or \n' characters. /// </summary> /// <param name="curSourceText"></param> /// <param name="from">The start position in the buffer</param> /// <param name="to">The ending position in the buffer</param> /// <returns>The replacement characters</returns> protected char[] GetDeleteString(StringSourceText sourceText, int from, int to) { char[] result = new char[to - from]; for (int i = 0; i < result.Length; i++) { char c = sourceText[from + i]; result[i] = (c == '\r' || c == '\n' || Char.IsWhiteSpace(c)) ? c : ' '; } return(result); }
static SourceText?TryLoadSourceText(string directory, string path) { var full = Path.GetFullPath(Path.Combine(directory, Path.ChangeExtension(path, ModuleFileNameExtension) !)); try { return(StringSourceText.FromAsync(full, File.OpenRead(full)).Result); } catch (Exception) { // TODO: Catch more specific exceptions? return(null); } }
int Run(Options options) { var path = options.Module.FullName; if (!options.Module.Exists) { Log.ErrorLine("Module '{0}' could not be found.", path); return(1); } var loader = new StandardModuleLoader(ModuleLoaderMode.Normal); _ = loader.SearchPaths.Add(Path.GetDirectoryName(path) !); var text = StringSourceText.FromAsync(path, File.OpenRead(path)).Result; var context = new SyntaxContext(); try { var mod = loader.LoadModule(text, context); foreach (var decl in mod.Declarations.OfType <Function>()) { decl.Test(); } } catch (ModuleLoadException) { // All errors will be reported in the context. } foreach (var diag in context.Diagnostics) { LogDiagnostic(diag); } // TODO return(context.HasDiagnostics ? 1 : 0); }
/// <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); }
protected override SourceText?GetSourceText(ModulePath path) { // Core modules are not subject to any security checks, so make sure they're not loaded // from arbitrary file system locations. if (path.IsCore) { try { var rsc = $"{nameof(Flare)}.{string.Join('.', path.Components)}.{ModuleFileNameExtension}"; var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(rsc); return(stream != null?StringSourceText.FromAsync(Path.Combine(_assemblyPath, rsc), stream).Result : null); } catch (Exception e) { throw new ModuleLoadException($"Core module '{path}' failed to load: {e.Message}", e); } } var str = string.Join(Path.DirectorySeparatorChar, path.Components); foreach (var dir in SearchPaths) { if (TryLoadSourceText(dir, str) is SourceText source) { return(source); } } if (!UseEnvironmentVariable) { return(null); } foreach (var dir in GetSearchPaths(EnvironmentVariableTarget.Process)) { if (TryLoadSourceText(dir, str) is SourceText source) { return(source); } } foreach (var dir in GetSearchPaths(EnvironmentVariableTarget.User)) { if (TryLoadSourceText(dir, str) is SourceText source) { return(source); } } foreach (var dir in GetSearchPaths(EnvironmentVariableTarget.Machine)) { if (TryLoadSourceText(dir, str) is SourceText source) { return(source); } } return(null); }
int Run(Options options) { ReadLine.AutoCompletionHandler = null; var loader = new StandardModuleLoader(ModuleLoaderMode.Interactive); var i = 0; while (true) { Console.ForegroundColor = ConsoleColor.Cyan; Console.Write($"flare({i})> "); Console.ResetColor(); var text = new StringBuilder(); var quit = false; var continued = false; while (true) { var input = ReadLine.Read(); if (input != string.Empty) { ReadLine.AddHistory(input); } var broken = false; if (input == "'repl:quit") { quit = true; break; } if (continued && input == "'repl:break") { broken = true; } else { _ = text.AppendLine(input); } var lex = LanguageLexer.Lex(StringSourceText.From("<repl>", text.ToString())); foreach (var diag in lex.Diagnostics) { LogDiagnostic(diag); } if (!lex.IsSuccess) { break; } var parse = LanguageParser.Parse(lex, SyntaxMode.Interactive); if (!broken && IsIncomplete(parse)) { Console.ForegroundColor = ConsoleColor.Cyan; Console.Write($".....({i})> "); Console.ResetColor(); continued = true; continue; } foreach (var diag in parse.Diagnostics) { LogDiagnostic(diag); } var analysis = LanguageAnalyzer.Analyze(parse, loader, new SyntaxContext()); foreach (var diag in analysis.Diagnostics) { LogDiagnostic(diag); } break; } if (quit) { break; } i++; } return(0); }