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.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq;
using Parser; using Parser;
using ProjectConsole; using ProjectConsole;
using Semantics; 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) function [a, b c] = functionName(d, e, f)
a = d + e; a = d + e;
end end
%{
comment
"; ";
var window = new TextWindowWithNull(text, "noname"); var window = new TextWindowWithNull(text, "noname");
var parser = CreateParser(window); var parser = CreateParser(window);
var tree = parser.Parse(); 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(); Console.ReadKey();
} }
private static FileSyntaxNode GetTree(string fileName) private static SyntaxTree GetTree(string fileName)
{ {
var text = File.ReadAllText(fileName); var text = File.ReadAllText(fileName);
var window = new TextWindowWithNull(text, fileName); var window = new TextWindowWithNull(text, fileName);
@ -104,10 +114,11 @@ namespace ConsoleDemo
"@table", "@table",
"table.m"); "table.m");
var tree = GetTree(fileName); var tree = GetTree(fileName);
var childNodesAndTokens = tree.GetChildNodesAndTokens(); var root = tree.Root;
var childNodesAndTokens = root.GetChildNodesAndTokens();
var node = childNodesAndTokens[0].AsNode(); var node = childNodesAndTokens[0].AsNode();
var classChildNodesAndTokens = node.GetChildNodesAndTokens(); var classChildNodesAndTokens = node.GetChildNodesAndTokens();
var c = GetClass.FromTree(tree, fileName); var c = GetClass.FromTree(root, fileName);
Console.WriteLine(c.Name); Console.WriteLine(c.Name);
foreach (var m in c.Methods) foreach (var m in c.Methods)
{ {
@ -135,7 +146,7 @@ namespace ConsoleDemo
"heatmap.m"); "heatmap.m");
var tree = GetTree(fileName); var tree = GetTree(fileName);
var printer = new DumbWalker(context); var printer = new DumbWalker(context);
printer.Visit(tree); printer.Visit(tree.Root);
} }
public static void UsageDemo() public static void UsageDemo()
@ -148,16 +159,16 @@ namespace ConsoleDemo
"heatmap.m"); "heatmap.m");
var tree = GetTree(fileName); var tree = GetTree(fileName);
var printer = new UsageGathering(context); var printer = new UsageGathering(context);
printer.Visit(tree); printer.Visit(tree.Root);
} }
public static void Main(string[] args) public static void Main(string[] args)
{ {
//ParserDemo(); ParserDemo();
//SemanticsDemo(); //SemanticsDemo();
//ContextDemo(); //ContextDemo();
//DumbPrinterDemo(); //DumbPrinterDemo();
UsageDemo(); //UsageDemo();
Console.ReadKey(); 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 int TokensSinceNewLine { get; set; }
private Stack<TokenKind> TokenStack { get; } private Stack<TokenKind> TokenStack { get; }
public DiagnosticsBag Diagnostics { get; } = new DiagnosticsBag();
public MLexerGreen(ITextWindow window) public MLexerGreen(ITextWindow window)
{ {
Window = window; Window = window;
@ -50,10 +52,11 @@ namespace Parser.Internal
var c = Window.PeekChar(n); var c = Window.PeekChar(n);
if (c == '\0') 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; 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 public class MParser
{ {
private readonly ITextWindow _window; private readonly ITextWindow _window;
public MParser(ITextWindow window) public MParser(ITextWindow window)
{ {
_window = window; _window = window;
} }
public FileSyntaxNode Parse() public SyntaxTree Parse()
{ {
var lexer = new Internal.MLexerGreen(_window); var lexer = new Internal.MLexerGreen(_window);
var diagnostics = lexer.Diagnostics;
var tokens = lexer.ParseAll(); var tokens = lexer.ParseAll();
var parser = new Internal.MParserGreen(tokens, new Internal.SyntaxFactory()); var parser = new Internal.MParserGreen(tokens, new Internal.SyntaxFactory());
var green = parser.ParseFile(); 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 string FileName { get; set; }
public int Line { get; set; } public int Line { get; set; }
public int Column { get; set; } public int Column { get; set; }
public int Offset { get; set; }
public override string ToString() public override string ToString()
{ {

View File

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

View File

@ -13,7 +13,7 @@
public override char PeekChar(int n) 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);
} }
} }
} }