Start implementing Evaluator

This commit is contained in:
Alexander Luzgarev 2020-07-14 13:44:37 +02:00
parent f4921ac9f9
commit 8c1ddb0cf7
11 changed files with 472 additions and 65 deletions

View File

@ -1,5 +1,4 @@
using Parser; using Parser;
using Semantics;
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -72,7 +71,7 @@ namespace ConsoleDemo
var childNodesAndTokens = root.GetChildNodesAndTokens(); 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(root, fileName); var c = Semantics.GetClass.FromTree(root, fileName);
Console.WriteLine(c.Name); Console.WriteLine(c.Name);
foreach (var m in c.Methods) foreach (var m in c.Methods)
{ {
@ -86,13 +85,13 @@ namespace ConsoleDemo
public static void ContextDemo() public static void ContextDemo()
{ {
var context = new Context(); var context = new Semantics.Context();
context.ScanPath(BaseDirectory); context.ScanPath(BaseDirectory);
} }
public static void DumbPrinterDemo() public static void DumbPrinterDemo()
{ {
var context = new Context(); var context = new Semantics.Context();
context.ScanPath(BaseDirectory); context.ScanPath(BaseDirectory);
var fileName = Path.Combine( var fileName = Path.Combine(
BaseDirectory, BaseDirectory,
@ -105,7 +104,7 @@ namespace ConsoleDemo
public static void UsageDemo() public static void UsageDemo()
{ {
var context = new Context(); var context = new Semantics.Context();
context.ScanPath(BaseDirectory); context.ScanPath(BaseDirectory);
var fileName = Path.Combine( var fileName = Path.Combine(
BaseDirectory, BaseDirectory,
@ -130,7 +129,6 @@ namespace ConsoleDemo
//ContextDemo(); //ContextDemo();
//DumbPrinterDemo(); //DumbPrinterDemo();
//UsageDemo(); //UsageDemo();
Console.ReadKey();
} }
} }
} }

23
Parser/Compilation.cs Normal file
View File

@ -0,0 +1,23 @@
namespace Parser
{
public class Compilation
{
private readonly SyntaxTree _syntaxTree;
private Compilation(SyntaxTree syntaxTree)
{
_syntaxTree = syntaxTree;
}
public static Compilation Create(SyntaxTree syntaxTree)
{
return new Compilation(syntaxTree);
}
public EvaluationResult Evaluate(CompilationContext context)
{
var evaluator = new Evaluator(_syntaxTree, context);
return evaluator.Evaluate();
}
}
}

View File

@ -0,0 +1,7 @@
namespace Parser
{
public class CompilationContext
{
public static CompilationContext Empty => new CompilationContext();
}
}

View File

@ -0,0 +1,19 @@
using Parser.Internal;
using Parser.Objects;
using System.Collections.Immutable;
namespace Parser
{
public class EvaluationResult
{
public EvaluationResult(MObject? value, ImmutableArray<Diagnostic> diagnostics)
{
Value = value;
Diagnostics = diagnostics;
}
public MObject? Value { get; }
public ImmutableArray<Diagnostic> Diagnostics { get; }
}
}

282
Parser/Evaluator.cs Normal file
View File

@ -0,0 +1,282 @@
using Parser.Internal;
using Parser.Objects;
using System;
using System.Collections.Immutable;
namespace Parser
{
internal class Evaluator
{
private SyntaxTree _syntaxTree;
private CompilationContext _context;
private DiagnosticsBag _diagnostics;
public Evaluator(SyntaxTree syntaxTree, CompilationContext context)
{
_syntaxTree = syntaxTree;
_context = context;
_diagnostics = new DiagnosticsBag();
}
internal EvaluationResult Evaluate()
{
var result = EvaluateFile(_syntaxTree.Root);
return new EvaluationResult(result, _diagnostics.ToImmutableArray());
}
private MObject? EvaluateFile(FileSyntaxNode root)
{
MObject? lastResult = null;
foreach (var nodeOrToken in root.StatementList)
{
if (nodeOrToken.IsNode)
{
var statement = (StatementSyntaxNode)nodeOrToken.AsNode()!;
lastResult = EvaluateStatement(statement) ?? lastResult;
}
}
return lastResult;
}
private MObject? EvaluateStatement(StatementSyntaxNode statement)
{
return statement.Kind switch
{
TokenKind.ExpressionStatement =>
EvaluateExpressionStatement((ExpressionStatementSyntaxNode)statement),
TokenKind.MethodDefinition =>
EvaluateMethodDefinition((MethodDefinitionSyntaxNode)statement),
TokenKind.AbstractMethodDeclaration =>
EvaluateAbstractMethodDeclaration((AbstractMethodDeclarationSyntaxNode)statement),
TokenKind.FunctionDeclaration =>
EvaluateFunctionDeclaration((FunctionDeclarationSyntaxNode)statement),
TokenKind.SwitchStatement =>
EvaluateSwitchStatement((SwitchStatementSyntaxNode)statement),
TokenKind.WhileStatement =>
EvaluateWhileStatement((WhileStatementSyntaxNode)statement),
TokenKind.IfStatement =>
EvaluateIfStatement((IfStatementSyntaxNode)statement),
TokenKind.ForStatement =>
EvaluateForStatement((ForStatementSyntaxNode)statement),
TokenKind.TryCatchStatement =>
EvaluateTryCatchStatement((TryCatchStatementSyntaxNode)statement),
TokenKind.EmptyStatement =>
EvaluateEmptyStatement((EmptyStatementSyntaxNode)statement),
TokenKind.ClassDeclaration =>
EvaluateClassDeclaration((ClassDeclarationSyntaxNode)statement),
_ => throw new NotImplementedException($"Invalid statement kind '{statement.Kind}'."),
};
}
private MObject? EvaluateClassDeclaration(ClassDeclarationSyntaxNode statement)
{
throw new NotImplementedException();
}
private MObject? EvaluateEmptyStatement(EmptyStatementSyntaxNode statement)
{
throw new NotImplementedException();
}
private MObject? EvaluateTryCatchStatement(TryCatchStatementSyntaxNode statement)
{
throw new NotImplementedException();
}
private MObject? EvaluateForStatement(ForStatementSyntaxNode statement)
{
throw new NotImplementedException();
}
private MObject? EvaluateIfStatement(IfStatementSyntaxNode statement)
{
throw new NotImplementedException();
}
private MObject? EvaluateWhileStatement(WhileStatementSyntaxNode statement)
{
throw new NotImplementedException();
}
private MObject? EvaluateSwitchStatement(SwitchStatementSyntaxNode statement)
{
throw new NotImplementedException();
}
private MObject? EvaluateFunctionDeclaration(FunctionDeclarationSyntaxNode statement)
{
throw new NotImplementedException();
}
private MObject? EvaluateAbstractMethodDeclaration(AbstractMethodDeclarationSyntaxNode statement)
{
throw new NotImplementedException();
}
private MObject? EvaluateMethodDefinition(MethodDefinitionSyntaxNode statement)
{
throw new NotImplementedException();
}
private MObject? EvaluateExpressionStatement(ExpressionStatementSyntaxNode statement)
{
return EvaluateExpression(statement.Expression);
}
private MObject? EvaluateExpression(ExpressionSyntaxNode expression)
{
return expression.Kind switch
{
TokenKind.Lambda =>
EvaluateLambda((LambdaSyntaxNode)expression),
TokenKind.AssignmentExpression =>
EvaluateAssignmentExpression((AssignmentExpressionSyntaxNode)expression),
TokenKind.EmptyExpression =>
EvaluateEmptyExpression((EmptyExpressionSyntaxNode)expression),
TokenKind.UnaryPrefixOperationExpression =>
EvaluateUnaryPrefixOperationExpression((UnaryPrefixOperationExpressionSyntaxNode)expression),
TokenKind.CompoundName =>
EvaluateCompoundName((CompoundNameSyntaxNode)expression),
TokenKind.BinaryOperation =>
EvaluateBinaryOperation((BinaryOperationExpressionSyntaxNode)expression),
TokenKind.IdentifierName =>
EvaluateIdentifierName((IdentifierNameSyntaxNode)expression),
TokenKind.NumberLiteralExpression =>
EvaluateNumberLiteralExpression((NumberLiteralSyntaxNode)expression),
TokenKind.StringLiteralExpression =>
EvaluateStringLiteralExpression((StringLiteralSyntaxNode)expression),
TokenKind.DoubleQuotedStringLiteralExpression =>
EvaluateDoubleQuotedStringLiteralExpression((DoubleQuotedStringLiteralSyntaxNode)expression),
TokenKind.UnquotedStringLiteralExpression =>
EvaluateUnquotedStringLiteralExpression((UnquotedStringLiteralSyntaxNode)expression),
TokenKind.ArrayLiteralExpression =>
EvaluateArrayLiteralExpression((ArrayLiteralExpressionSyntaxNode)expression),
TokenKind.CellArrayLiteralExpression =>
EvaluateCellArrayLiteralExpression((CellArrayLiteralExpressionSyntaxNode)expression),
TokenKind.ParenthesizedExpression =>
EvaluateNamedFunctionHandle((NamedFunctionHandleSyntaxNode)expression),
TokenKind.CellArrayElementAccess =>
EvaluateCellArrayElementAccess((CellArrayElementAccessExpressionSyntaxNode)expression),
TokenKind.FunctionCall =>
EvaluateFunctionCall((FunctionCallExpressionSyntaxNode)expression),
TokenKind.MemberAccess =>
EvaluateMemberAccess((MemberAccessSyntaxNode)expression),
TokenKind.UnaryPostfixOperationExpression =>
EvaluateUnaryPostfixOperationExpression((UnaryPostixOperationExpressionSyntaxNode)expression),
TokenKind.IndirectMemberAccess =>
EvaluateIndirectMemberAccess((IndirectMemberAccessSyntaxNode)expression),
TokenKind.Command =>
EvaluateCommand((CommandExpressionSyntaxNode)expression),
TokenKind.ClassInvokation =>
EvaluateClassInvokation((BaseClassInvokationSyntaxNode)expression),
_ => throw new NotImplementedException($"Invalid expression kind '{expression.Kind}'."),
};
}
private MObject? EvaluateClassInvokation(BaseClassInvokationSyntaxNode expression)
{
throw new NotImplementedException();
}
private MObject? EvaluateCommand(CommandExpressionSyntaxNode expression)
{
throw new NotImplementedException();
}
private MObject? EvaluateIndirectMemberAccess(IndirectMemberAccessSyntaxNode expression)
{
throw new NotImplementedException();
}
private MObject? EvaluateUnaryPostfixOperationExpression(UnaryPostixOperationExpressionSyntaxNode expression)
{
throw new NotImplementedException();
}
private MObject? EvaluateMemberAccess(MemberAccessSyntaxNode expression)
{
throw new NotImplementedException();
}
private MObject? EvaluateFunctionCall(FunctionCallExpressionSyntaxNode expression)
{
throw new NotImplementedException();
}
private MObject? EvaluateCellArrayElementAccess(CellArrayElementAccessExpressionSyntaxNode expression)
{
throw new NotImplementedException();
}
private MObject? EvaluateCellArrayLiteralExpression(CellArrayLiteralExpressionSyntaxNode expression)
{
throw new NotImplementedException();
}
private MObject? EvaluateArrayLiteralExpression(ArrayLiteralExpressionSyntaxNode expression)
{
throw new NotImplementedException();
}
private MObject? EvaluateUnquotedStringLiteralExpression(UnquotedStringLiteralSyntaxNode expression)
{
throw new NotImplementedException();
}
private MObject? EvaluateDoubleQuotedStringLiteralExpression(DoubleQuotedStringLiteralSyntaxNode expression)
{
throw new NotImplementedException();
}
private MObject? EvaluateStringLiteralExpression(StringLiteralSyntaxNode expression)
{
throw new NotImplementedException();
}
private MObject? EvaluateNumberLiteralExpression(NumberLiteralSyntaxNode expression)
{
throw new NotImplementedException();
}
private MObject? EvaluateIdentifierName(IdentifierNameSyntaxNode expression)
{
throw new NotImplementedException();
}
private MObject? EvaluateBinaryOperation(BinaryOperationExpressionSyntaxNode expression)
{
throw new NotImplementedException();
}
private MObject? EvaluateCompoundName(CompoundNameSyntaxNode expression)
{
throw new NotImplementedException();
}
private MObject? EvaluateUnaryPrefixOperationExpression(UnaryPrefixOperationExpressionSyntaxNode expression)
{
throw new NotImplementedException();
}
private MObject? EvaluateEmptyExpression(EmptyExpressionSyntaxNode expression)
{
throw new NotImplementedException();
}
private MObject? EvaluateAssignmentExpression(AssignmentExpressionSyntaxNode expression)
{
throw new NotImplementedException();
}
private MObject? EvaluateLambda(LambdaSyntaxNode expression)
{
throw new NotImplementedException();
}
private MObject? EvaluateNamedFunctionHandle(NamedFunctionHandleSyntaxNode expression)
{
throw new NotImplementedException();
}
}
}

View File

@ -1,6 +1,4 @@
using System; using Parser.Internal;
using System.Collections.Generic;
using Parser.Internal;
using System.Linq; using System.Linq;
namespace Parser namespace Parser
@ -27,18 +25,4 @@ namespace Parser
return new SyntaxTree(root, totalDiagnostics); return new SyntaxTree(root, totalDiagnostics);
} }
} }
public class SyntaxTree
{
public SyntaxTree(RootSyntaxNode nullRoot, DiagnosticsBag diagnostics)
{
NullRoot = nullRoot ?? throw new ArgumentNullException(nameof(nullRoot));
Diagnostics = diagnostics ?? throw new ArgumentNullException(nameof(diagnostics));
}
public RootSyntaxNode NullRoot { get; }
public FileSyntaxNode Root => NullRoot.File;
public DiagnosticsBag Diagnostics { get; }
}
} }

View File

@ -0,0 +1,6 @@
namespace Parser.Objects
{
public class MDoubleNumber : MObject
{
}
}

View File

@ -0,0 +1,6 @@
namespace Parser.Objects
{
public abstract class MObject
{
}
}

27
Parser/SyntaxTree.cs Normal file
View File

@ -0,0 +1,27 @@
using System;
using Parser.Internal;
namespace Parser
{
public class SyntaxTree
{
public SyntaxTree(RootSyntaxNode nullRoot, DiagnosticsBag diagnostics)
{
NullRoot = nullRoot ?? throw new ArgumentNullException(nameof(nullRoot));
Diagnostics = diagnostics ?? throw new ArgumentNullException(nameof(diagnostics));
}
public RootSyntaxNode NullRoot { get; }
public FileSyntaxNode Root => NullRoot.File;
public DiagnosticsBag Diagnostics { get; }
public static SyntaxTree Parse(string text)
{
var window = new TextWindowWithNull(text);
var parser = new MParser(window);
var tree = parser.Parse();
return tree;
}
}
}

View File

@ -5,63 +5,74 @@ namespace Repl
{ {
public class MRepl public class MRepl
{ {
private readonly CompilationContext _context;
public MRepl()
{
_context = CompilationContext.Empty;
}
public void Run() public void Run()
{ {
while (true) while (true)
{ {
Console.Write("> "); var line = Read();
var line = Console.ReadLine(); if (line.StartsWith('#'))
var window = new TextWindowWithNull(line);
var parser = new MParser(window);
var tree = parser.Parse();
if (tree.Diagnostics.Diagnostics.Count > 0)
{ {
foreach (var diagnostic in tree.Diagnostics.Diagnostics) line = line.Trim();
if (line == "#q")
{ {
Console.WriteLine($"{diagnostic.Span}: {diagnostic.Message}"); break;
} }
Console.ForegroundColor = ConsoleColor.DarkRed;
Console.WriteLine($"Unknown command '{line}'.");
Console.ResetColor();
continue;
}
var result = Evaluate(line);
Print(result);
}
}
private void Print(string result)
{
Console.Write(result);
}
private string Read()
{
Console.Write("> ");
return Console.ReadLine();
}
private string Evaluate(string submission)
{
var tree = SyntaxTree.Parse(submission);
var compilation = Compilation.Create(tree);
if (tree.Diagnostics.Diagnostics.Count > 0)
{
foreach (var diagnostic in tree.Diagnostics.Diagnostics)
{
Console.ForegroundColor = ConsoleColor.DarkRed;
Console.WriteLine($"{diagnostic.Span}: {diagnostic.Message}");
Console.ResetColor();
} }
TreeRenderer.RenderTree(tree); TreeRenderer.RenderTree(tree);
return string.Empty;
} }
}
}
public class TreeRenderer TreeRenderer.RenderTree(tree);
{
private static void RenderToken(SyntaxToken token, string indent, bool isLast)
{
Console.Write(indent + (isLast ? "└── " : "├── "));
Console.Write($"<{token.Kind}>");
Console.Write($" {token.Text}");
Console.WriteLine();
}
private static void RenderNode(SyntaxNode node, string indent, bool isLast) var evaluationResult = compilation.Evaluate(_context);
{
Console.Write(indent); foreach (var diagnostic in evaluationResult.Diagnostics)
Console.Write(isLast ? "└── " : "├── ");
Console.Write($"<{node.Kind}>");
Console.WriteLine();
var children = node.GetChildNodesAndTokens();
var last = children.Count - 1;
indent += isLast ? " " : "│ ";
for (var index = 0; index <= last; index++)
{ {
var child = children[index]; Console.ForegroundColor = ConsoleColor.DarkRed;
if (child.IsNode) Console.WriteLine($"{diagnostic.Span}: {diagnostic.Message}");
{ Console.ResetColor();
RenderNode(child.AsNode(), indent, index == last);
}
else if (child.IsToken)
{
RenderToken(child.AsToken(), indent, index == last);
}
} }
}
public static void RenderTree(SyntaxTree tree) return evaluationResult.Value?.ToString() ?? string.Empty;
{
RenderNode(tree.Root, "", true);
} }
} }
} }

44
Repl/TreeRenderer.cs Normal file
View File

@ -0,0 +1,44 @@
using System;
using Parser;
namespace Repl
{
public class TreeRenderer
{
private static void RenderToken(SyntaxToken token, string indent, bool isLast)
{
Console.Write(indent + (isLast ? "└── " : "├── "));
Console.Write($"<{token.Kind}>");
Console.Write($" {token.Text}");
Console.WriteLine();
}
private static void RenderNode(SyntaxNode node, string indent, bool isLast)
{
Console.Write(indent);
Console.Write(isLast ? "└── " : "├── ");
Console.Write($"<{node.Kind}>");
Console.WriteLine();
var children = node.GetChildNodesAndTokens();
var last = children.Count - 1;
indent += isLast ? " " : "│ ";
for (var index = 0; index <= last; index++)
{
var child = children[index];
if (child.IsNode)
{
RenderNode(child.AsNode(), indent, index == last);
}
else if (child.IsToken)
{
RenderToken(child.AsToken(), indent, index == last);
}
}
}
public static void RenderTree(SyntaxTree tree)
{
RenderNode(tree.Root, "", true);
}
}
}