Add diagnostics

This commit is contained in:
Alexander Luzgarev 2018-10-17 20:08:16 +02:00
parent d928c262fa
commit cdbb0ffb72
9 changed files with 130 additions and 31 deletions

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Parser;
using ProjectConsole;
using Semantics;
@ -40,9 +41,9 @@ namespace ConsoleDemo
}
}
public static void Render(SyntaxNode node)
public static void RenderTree(SyntaxTree tree)
{
RenderNode(node, "", true);
RenderNode(tree.Root, "", true);
}
}
@ -79,15 +80,24 @@ namespace ConsoleDemo
function [a, b c] = functionName(d, e, f)
a = d + e;
end
%{
comment
";
var window = new TextWindowWithNull(text, "noname");
var parser = CreateParser(window);
var tree = parser.Parse();
TreeRenderer.Render(tree);
TreeRenderer.RenderTree(tree);
if (tree.Diagnostics.Any())
{
foreach (var diagnostic in tree.Diagnostics)
{
Console.WriteLine($"ERROR: {diagnostic.Message} at position {diagnostic.Span.Start}");
}
}
Console.ReadKey();
}
private static FileSyntaxNode GetTree(string fileName)
private static SyntaxTree GetTree(string fileName)
{
var text = File.ReadAllText(fileName);
var window = new TextWindowWithNull(text, fileName);
@ -104,10 +114,11 @@ namespace ConsoleDemo
"@table",
"table.m");
var tree = GetTree(fileName);
var childNodesAndTokens = tree.GetChildNodesAndTokens();
var root = tree.Root;
var childNodesAndTokens = root.GetChildNodesAndTokens();
var node = childNodesAndTokens[0].AsNode();
var classChildNodesAndTokens = node.GetChildNodesAndTokens();
var c = GetClass.FromTree(tree, fileName);
var c = GetClass.FromTree(root, fileName);
Console.WriteLine(c.Name);
foreach (var m in c.Methods)
{
@ -135,7 +146,7 @@ namespace ConsoleDemo
"heatmap.m");
var tree = GetTree(fileName);
var printer = new DumbWalker(context);
printer.Visit(tree);
printer.Visit(tree.Root);
}
public static void UsageDemo()
@ -148,16 +159,16 @@ namespace ConsoleDemo
"heatmap.m");
var tree = GetTree(fileName);
var printer = new UsageGathering(context);
printer.Visit(tree);
printer.Visit(tree.Root);
}
public static void Main(string[] args)
{
//ParserDemo();
ParserDemo();
//SemanticsDemo();
//ContextDemo();
//DumbPrinterDemo();
UsageDemo();
//UsageDemo();
Console.ReadKey();
}
}

View File

@ -0,0 +1,16 @@
using System;
namespace Parser.Internal
{
public class Diagnostic
{
public TextSpan Span { get; }
public string Message { get; }
public Diagnostic(TextSpan span, string message)
{
Span = span;
Message = message ?? throw new ArgumentNullException(nameof(message));
}
}
}

View File

@ -0,0 +1,38 @@
using System.Collections;
using System.Collections.Generic;
namespace Parser.Internal
{
public class DiagnosticsBag : IEnumerable<Diagnostic>
{
internal DiagnosticsBag()
{
_diagnostics = new List<Diagnostic>();
}
private readonly List<Diagnostic> _diagnostics;
public IReadOnlyCollection<Diagnostic> Diagnostics => _diagnostics.AsReadOnly();
private void Report(TextSpan span, string message)
{
var diagnostic = new Diagnostic(span, message);
_diagnostics.Add(diagnostic);
}
internal void ReportUnexpectedEndOfFile(TextSpan span)
{
Report(span, "Unexpected end of file.");
}
public IEnumerator<Diagnostic> GetEnumerator()
{
return _diagnostics.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

View File

@ -19,6 +19,8 @@ namespace Parser.Internal
private int TokensSinceNewLine { get; set; }
private Stack<TokenKind> TokenStack { get; }
public DiagnosticsBag Diagnostics { get; } = new DiagnosticsBag();
public MLexerGreen(ITextWindow window)
{
Window = window;
@ -50,10 +52,11 @@ namespace Parser.Internal
var c = Window.PeekChar(n);
if (c == '\0')
{
throw new ParsingException("Unexpected end of file while parsing multi-line comment.");
Diagnostics.ReportUnexpectedEndOfFile(new TextSpan(Window.Position.Offset, 0));
return TokenFactory.CreateTrivia(TokenKind.Comment, Window.GetAndConsumeChars(n));
}
if (c == '\n')
if (c == '\n' || (c == '\r' && Window.PeekChar(n + 1) == '\n'))
{
atFirstLine = false;
}

View File

@ -0,0 +1,15 @@
namespace Parser.Internal
{
public class TextSpan
{
public TextSpan(int start, int length)
{
Start = start;
Length = length;
}
public int Start { get; }
public int Length { get; }
public int End => Start + Length;
}
}

View File

@ -1,21 +1,39 @@
namespace Parser
using System;
using Parser.Internal;
namespace Parser
{
public class MParser
{
private readonly ITextWindow _window;
public MParser(ITextWindow window)
{
_window = window;
}
public FileSyntaxNode Parse()
public SyntaxTree Parse()
{
var lexer = new Internal.MLexerGreen(_window);
var diagnostics = lexer.Diagnostics;
var tokens = lexer.ParseAll();
var parser = new Internal.MParserGreen(tokens, new Internal.SyntaxFactory());
var green = parser.ParseFile();
return new FileSyntaxNode(null, green);
var root = new FileSyntaxNode(null, green);
return new SyntaxTree(root, diagnostics);
}
}
public class SyntaxTree
{
public SyntaxTree(FileSyntaxNode root, DiagnosticsBag diagnostics)
{
Root = root ?? throw new ArgumentNullException(nameof(root));
Diagnostics = diagnostics ?? throw new ArgumentNullException(nameof(diagnostics));
}
public FileSyntaxNode Root { get; }
public DiagnosticsBag Diagnostics { get; }
}
}

View File

@ -5,6 +5,7 @@
public string FileName { get; set; }
public int Line { get; set; }
public int Column { get; set; }
public int Offset { get; set; }
public override string ToString()
{

View File

@ -3,42 +3,39 @@
public class TextWindow : ITextWindow
{
protected readonly string Text;
protected int Offset { get; set; }
private Position _position;
public Position Position => _position;
public TextWindow(string text, string fileName = null)
{
Text = text;
Offset = 0;
_position = new Position
{
FileName = fileName,
Line = 0,
Column = 0
Column = 0,
Offset = 0
};
}
public bool IsEof()
{
return Offset >= Text.Length;
return _position.Offset >= Text.Length;
}
public virtual char PeekChar()
{
return Text[Offset];
return Text[_position.Offset];
}
public virtual char PeekChar(int n)
{
return Text[Offset + n];
return Text[_position.Offset + n];
}
public void ConsumeChar()
{
if (Text[Offset] == '\n' || Text[Offset] == '\r')
if (Text[_position.Offset] == '\n' || Text[_position.Offset] == '\r')
{
_position.Line++;
_position.Column = 0;
@ -47,7 +44,7 @@
{
_position.Column++;
}
Offset++;
_position.Offset++;
}
public void ConsumeChars(int n)
@ -64,26 +61,26 @@
_position.Column++;
}
}
Offset += n;
_position.Offset += n;
}
public char GetAndConsumeChar()
{
var c = Text[Offset];
var c = Text[_position.Offset];
ConsumeChar();
return c;
}
public string GetAndConsumeChars(int n)
{
var s = Text.Substring(Offset, n);
var s = Text.Substring(_position.Offset, n);
ConsumeChars(n);
return s;
}
public int CharactersLeft()
{
return Text.Length - Offset;
return Text.Length - _position.Offset;
}
}
}

View File

@ -13,7 +13,7 @@
public override char PeekChar(int n)
{
return Offset + n >= Text.Length ? '\0' : base.PeekChar(n);
return Position.Offset + n >= Text.Length ? '\0' : base.PeekChar(n);
}
}
}