diff --git a/ConsoleDemo/Program.cs b/ConsoleDemo/Program.cs index 8f74c47..1b2f418 100644 --- a/ConsoleDemo/Program.cs +++ b/ConsoleDemo/Program.cs @@ -1,5 +1,4 @@ using Parser; -using Semantics; using System; using System.IO; using System.Linq; @@ -72,7 +71,7 @@ namespace ConsoleDemo var childNodesAndTokens = root.GetChildNodesAndTokens(); var node = childNodesAndTokens[0].AsNode(); var classChildNodesAndTokens = node.GetChildNodesAndTokens(); - var c = GetClass.FromTree(root, fileName); + var c = Semantics.GetClass.FromTree(root, fileName); Console.WriteLine(c.Name); foreach (var m in c.Methods) { @@ -86,13 +85,13 @@ namespace ConsoleDemo public static void ContextDemo() { - var context = new Context(); + var context = new Semantics.Context(); context.ScanPath(BaseDirectory); } public static void DumbPrinterDemo() { - var context = new Context(); + var context = new Semantics.Context(); context.ScanPath(BaseDirectory); var fileName = Path.Combine( BaseDirectory, @@ -105,7 +104,7 @@ namespace ConsoleDemo public static void UsageDemo() { - var context = new Context(); + var context = new Semantics.Context(); context.ScanPath(BaseDirectory); var fileName = Path.Combine( BaseDirectory, @@ -130,7 +129,6 @@ namespace ConsoleDemo //ContextDemo(); //DumbPrinterDemo(); //UsageDemo(); - Console.ReadKey(); } } } diff --git a/Parser/Compilation.cs b/Parser/Compilation.cs new file mode 100644 index 0000000..c4668c6 --- /dev/null +++ b/Parser/Compilation.cs @@ -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(); + } + } +} \ No newline at end of file diff --git a/Parser/CompilationContext.cs b/Parser/CompilationContext.cs new file mode 100644 index 0000000..df3c6fc --- /dev/null +++ b/Parser/CompilationContext.cs @@ -0,0 +1,7 @@ +namespace Parser +{ + public class CompilationContext + { + public static CompilationContext Empty => new CompilationContext(); + } +} \ No newline at end of file diff --git a/Parser/EvaluationResult.cs b/Parser/EvaluationResult.cs new file mode 100644 index 0000000..97e0c56 --- /dev/null +++ b/Parser/EvaluationResult.cs @@ -0,0 +1,19 @@ +using Parser.Internal; +using Parser.Objects; +using System.Collections.Immutable; + +namespace Parser +{ + public class EvaluationResult + { + public EvaluationResult(MObject? value, ImmutableArray diagnostics) + { + Value = value; + Diagnostics = diagnostics; + } + + public MObject? Value { get; } + + public ImmutableArray Diagnostics { get; } + } +} \ No newline at end of file diff --git a/Parser/Evaluator.cs b/Parser/Evaluator.cs new file mode 100644 index 0000000..ed0bf15 --- /dev/null +++ b/Parser/Evaluator.cs @@ -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(); + } + } +} \ No newline at end of file diff --git a/Parser/MParser.cs b/Parser/MParser.cs index e47a1a8..f2766b5 100644 --- a/Parser/MParser.cs +++ b/Parser/MParser.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using Parser.Internal; +using Parser.Internal; using System.Linq; namespace Parser @@ -27,18 +25,4 @@ namespace Parser 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; } - } - } \ No newline at end of file diff --git a/Parser/Objects/MDoubleNumber.cs b/Parser/Objects/MDoubleNumber.cs new file mode 100644 index 0000000..b745a64 --- /dev/null +++ b/Parser/Objects/MDoubleNumber.cs @@ -0,0 +1,6 @@ +namespace Parser.Objects +{ + public class MDoubleNumber : MObject + { + } +} \ No newline at end of file diff --git a/Parser/Objects/MObject.cs b/Parser/Objects/MObject.cs new file mode 100644 index 0000000..f84b55d --- /dev/null +++ b/Parser/Objects/MObject.cs @@ -0,0 +1,6 @@ +namespace Parser.Objects +{ + public abstract class MObject + { + } +} \ No newline at end of file diff --git a/Parser/SyntaxTree.cs b/Parser/SyntaxTree.cs new file mode 100644 index 0000000..598bf5d --- /dev/null +++ b/Parser/SyntaxTree.cs @@ -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; + } + } + +} \ No newline at end of file diff --git a/Repl/MRepl.cs b/Repl/MRepl.cs index b64feb0..c43e3e8 100644 --- a/Repl/MRepl.cs +++ b/Repl/MRepl.cs @@ -5,63 +5,74 @@ namespace Repl { public class MRepl { + private readonly CompilationContext _context; + + public MRepl() + { + _context = CompilationContext.Empty; + } + public void Run() { while (true) { - Console.Write("> "); - var line = Console.ReadLine(); - var window = new TextWindowWithNull(line); - var parser = new MParser(window); - var tree = parser.Parse(); - if (tree.Diagnostics.Diagnostics.Count > 0) + var line = Read(); + if (line.StartsWith('#')) { - 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); + return string.Empty; } - } - } - 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(); - } + TreeRenderer.RenderTree(tree); - 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 evaluationResult = compilation.Evaluate(_context); + + foreach (var diagnostic in evaluationResult.Diagnostics) { - var child = children[index]; - if (child.IsNode) - { - RenderNode(child.AsNode(), indent, index == last); - } - else if (child.IsToken) - { - RenderToken(child.AsToken(), indent, index == last); - } + Console.ForegroundColor = ConsoleColor.DarkRed; + Console.WriteLine($"{diagnostic.Span}: {diagnostic.Message}"); + Console.ResetColor(); } - } - public static void RenderTree(SyntaxTree tree) - { - RenderNode(tree.Root, "", true); + return evaluationResult.Value?.ToString() ?? string.Empty; } } } diff --git a/Repl/TreeRenderer.cs b/Repl/TreeRenderer.cs new file mode 100644 index 0000000..c22ebee --- /dev/null +++ b/Repl/TreeRenderer.cs @@ -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); + } + } +}