MParser/Parser/Evaluator.cs

435 lines
16 KiB
C#

using Parser.Binding;
using Parser.Internal;
using Parser.MFunctions;
using Parser.Objects;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
namespace Parser
{
internal class Evaluator
{
private readonly BoundProgram _program;
private readonly CompilationContext _context;
private readonly DiagnosticsBag _diagnostics = new DiagnosticsBag();
private bool _insideFunction = false;
private readonly Stack<EvaluationScope> _scopeStack = new Stack<EvaluationScope>();
public Evaluator(BoundProgram program, CompilationContext context)
{
_program = program;
_context = context;
var outerScope = new EvaluationScope();
_scopeStack.Push(outerScope);
}
internal EvaluationResult Evaluate()
{
var result = EvaluateFile(_program.Root);
return new EvaluationResult(result, _diagnostics.ToImmutableArray());
}
private MObject? EvaluateFile(BoundFile root)
{
MObject? lastResult = null;
foreach (var statement in root.Statements)
{
lastResult = EvaluateStatement(statement) ?? lastResult;
}
return lastResult;
}
private MObject? EvaluateStatement(BoundStatement node)
{
return node.Kind switch
{
BoundNodeKind.AbstractMethodDeclaration =>
EvaluateAbstractMethodDeclaration((BoundAbstractMethodDeclaration)node),
BoundNodeKind.ClassDeclaration =>
EvaluateClassDeclaration((BoundClassDeclaration)node),
BoundNodeKind.EmptyStatement =>
EvaluateEmptyStatement((BoundEmptyStatement)node),
BoundNodeKind.ExpressionStatement =>
EvaluateExpressionStatement((BoundExpressionStatement)node),
BoundNodeKind.ForStatement =>
EvaluateForStatement((BoundForStatement)node),
BoundNodeKind.FunctionDeclaration =>
EvaluateFunctionDeclaration((BoundFunctionDeclaration)node),
BoundNodeKind.IfStatement =>
EvaluateIfStatement((BoundIfStatement)node),
BoundNodeKind.ConcreteMethodDeclaration =>
EvaluateMethodDefinition((BoundConcreteMethodDeclaration)node),
BoundNodeKind.SwitchStatement =>
EvaluateSwitchStatement((BoundSwitchStatement)node),
BoundNodeKind.TryCatchStatement =>
EvaluateTryCatchStatement((BoundTryCatchStatement)node),
BoundNodeKind.WhileStatement =>
EvaluateWhileStatement((BoundWhileStatement)node),
_ => throw new NotImplementedException($"Invalid statement kind '{node.Kind}'."),
};
}
private MObject? EvaluateClassDeclaration(BoundClassDeclaration node)
{
throw new NotImplementedException();
}
private MObject? EvaluateEmptyStatement(BoundEmptyStatement node)
{
throw new NotImplementedException();
}
private MObject? EvaluateTryCatchStatement(BoundTryCatchStatement node)
{
throw new NotImplementedException();
}
private MObject? EvaluateForStatement(BoundForStatement node)
{
throw new NotImplementedException();
}
private MObject? EvaluateIfStatement(BoundIfStatement node)
{
throw new NotImplementedException();
}
private MObject? EvaluateWhileStatement(BoundWhileStatement node)
{
throw new NotImplementedException();
}
private MObject? EvaluateSwitchStatement(BoundSwitchStatement node)
{
throw new NotImplementedException();
}
private MObject? EvaluateFunctionDeclaration(BoundFunctionDeclaration node)
{
throw new NotImplementedException();
}
private MObject? EvaluateAbstractMethodDeclaration(BoundAbstractMethodDeclaration node)
{
throw new NotImplementedException();
}
private MObject? EvaluateMethodDefinition(BoundConcreteMethodDeclaration node)
{
throw new NotImplementedException();
}
private MObject? EvaluateExpressionStatement(BoundExpressionStatement node)
{
return EvaluateExpression(node.Expression);
}
private MObject? EvaluateExpression(BoundExpression node)
{
return node.Kind switch
{
BoundNodeKind.ArrayLiteralExpression =>
EvaluateArrayLiteralExpression((BoundArrayLiteralExpression)node),
BoundNodeKind.AssignmentExpression =>
EvaluateAssignmentExpression((BoundAssignmentExpression)node),
BoundNodeKind.BinaryOperationExpression =>
EvaluateBinaryOperation((BoundBinaryOperationExpression)node),
BoundNodeKind.CellArrayElementAccessExpression =>
EvaluateCellArrayElementAccess((BoundCellArrayElementAccessExpression)node),
BoundNodeKind.CellArrayLiteralExpression =>
EvaluateCellArrayLiteralExpression((BoundCellArrayLiteralExpression)node),
BoundNodeKind.ClassInvokationExpression =>
EvaluateClassInvokation((BoundClassInvokationExpression)node),
BoundNodeKind.CommandExpression =>
EvaluateCommand((BoundCommandExpression)node),
BoundNodeKind.CompoundNameExpression =>
EvaluateCompoundName((BoundCompoundNameExpression)node),
BoundNodeKind.DoubleQuotedStringLiteralExpression =>
EvaluateDoubleQuotedStringLiteralExpression((BoundDoubleQuotedStringLiteralExpression)node),
BoundNodeKind.EmptyExpression =>
EvaluateEmptyExpression((BoundEmptyExpression)node),
BoundNodeKind.FunctionCallExpression =>
EvaluateFunctionCall((BoundFunctionCallExpression)node),
BoundNodeKind.IdentifierNameExpression =>
EvaluateIdentifierNameExpression((BoundIdentifierNameExpression)node),
BoundNodeKind.IndirectMemberAccessExpression =>
EvaluateIndirectMemberAccess((BoundIndirectMemberAccessExpression)node),
BoundNodeKind.LambdaExpression =>
EvaluateLambdaExpression((BoundLambdaExpression)node),
BoundNodeKind.MemberAccessExpression =>
EvaluateMemberAccess((BoundMemberAccessExpression)node),
BoundNodeKind.NamedFunctionHandleExpression =>
EvaluateNamedFunctionHandleExpression((BoundNamedFunctionHandleExpression)node),
BoundNodeKind.NumberLiteralExpression =>
EvaluateNumberLiteralExpression((BoundNumberLiteralExpression)node),
BoundNodeKind.ParenthesizedExpression =>
EvaluateParenthesizedExpression((BoundParenthesizedExpression)node),
BoundNodeKind.StringLiteralExpression =>
EvaluateStringLiteralExpression((BoundStringLiteralExpression)node),
BoundNodeKind.UnaryPrefixOperationExpression =>
EvaluateUnaryPrefixOperationExpression((BoundUnaryPrefixOperationExpression)node),
BoundNodeKind.UnaryPostfixOperationExpression =>
EvaluateUnaryPostfixOperationExpression((BoundUnaryPostfixOperationExpression)node),
BoundNodeKind.UnquotedStringLiteralExpression =>
EvaluateUnquotedStringLiteralExpression((BoundUnquotedStringLiteralExpression)node),
_ => throw new NotImplementedException($"Invalid expression kind '{node.Kind}'."),
};
}
private MObject? EvaluateParenthesizedExpression(BoundParenthesizedExpression node)
{
return EvaluateExpression(node.Expression);
}
private MObject? EvaluateClassInvokation(BoundClassInvokationExpression node)
{
throw new NotImplementedException();
}
private MObject? EvaluateCommand(BoundCommandExpression node)
{
throw new NotImplementedException();
}
private MObject? EvaluateIndirectMemberAccess(BoundIndirectMemberAccessExpression node)
{
throw new NotImplementedException();
}
private MObject? EvaluateUnaryPostfixOperationExpression(BoundUnaryPostfixOperationExpression node)
{
throw new NotImplementedException();
}
private MObject? EvaluateMemberAccess(BoundMemberAccessExpression node)
{
throw new NotImplementedException();
}
private MObject? EvaluateFunctionCall(BoundFunctionCallExpression node)
{
var arguments = new List<MObject>();
var allGood = true;
foreach (var argument in node.Arguments)
{
var evaluatedArgument = EvaluateExpression(argument);
if (argument is null)
{
_diagnostics.ReportCannotEvaluateExpression(
new TextSpan(argument.Syntax.Position, argument.Syntax.FullWidth));
allGood = false;
}
else
{
arguments.Add(evaluatedArgument);
}
}
if (!allGood)
{
return null;
}
var function = GetFunctionSymbol(node.Name);
if (function.Name == "disp")
{
return EvaluateDisp(arguments);
}
else
{
throw new NotImplementedException("Functions are not supported.");
}
}
private MObject? EvaluateDisp(List<MObject> arguments)
{
if (arguments.Count != 1)
{
throw new NotImplementedException($"Cannot evaluate disp() with {arguments.Count} arguments.");
}
Console.WriteLine(arguments[0]);
return arguments[0];
}
private FunctionSymbol GetFunctionSymbol(BoundExpression functionName)
{
if (functionName.Kind == BoundNodeKind.IdentifierNameExpression)
{
return new FunctionSymbol(((BoundIdentifierNameExpression)functionName).Name);
}
throw new NotImplementedException($"Unknown function symbol '{functionName.Syntax.Text}'.");
}
private MObject? EvaluateCellArrayElementAccess(BoundCellArrayElementAccessExpression node)
{
throw new NotImplementedException();
}
private MObject? EvaluateCellArrayLiteralExpression(BoundCellArrayLiteralExpression node)
{
throw new NotImplementedException();
}
private MObject? EvaluateArrayLiteralExpression(BoundArrayLiteralExpression node)
{
throw new NotImplementedException();
}
private MObject? EvaluateUnquotedStringLiteralExpression(BoundUnquotedStringLiteralExpression node)
{
throw new NotImplementedException();
}
private MObject? EvaluateDoubleQuotedStringLiteralExpression(BoundDoubleQuotedStringLiteralExpression node)
{
throw new NotImplementedException();
}
private MObject? EvaluateStringLiteralExpression(BoundStringLiteralExpression node)
{
return node.Value switch
{
string s => MObject.CreateCharArray(s.ToCharArray()),
_ => null,
};
}
private MObject? EvaluateNumberLiteralExpression(BoundNumberLiteralExpression node)
{
return MObject.CreateDoubleNumber(node.Value);
}
private MObject? EvaluateIdentifierNameExpression(BoundIdentifierNameExpression node)
{
var variableName = node.Name;
var maybeValue = GetVariableValue(variableName);
if (maybeValue is null)
{
_diagnostics.ReportVariableNotFound(
new TextSpan(node.Syntax.Position, node.Syntax.FullWidth),
variableName);
}
return maybeValue;
}
private MObject? EvaluateBinaryOperation(BoundBinaryOperationExpression node)
{
var left = EvaluateExpression(node.Left);
if (left is null)
{
return null;
}
var right = EvaluateExpression(node.Right);
if (right is null)
{
return null;
}
return node.Op.Kind switch
{
BoundBinaryOperatorKind.Plus => MOperations.Plus(left, right),
BoundBinaryOperatorKind.Minus => MOperations.Minus(left, right),
BoundBinaryOperatorKind.Star => MOperations.Star(left, right),
BoundBinaryOperatorKind.Slash => MOperations.Slash(left, right),
_ => throw new NotImplementedException($"Binary operation {node.Op.Kind} is not implemented."),
};
}
private MObject? EvaluateCompoundName(BoundCompoundNameExpression node)
{
throw new NotImplementedException();
}
private MObject? EvaluateUnaryPrefixOperationExpression(BoundUnaryPrefixOperationExpression node)
{
throw new NotImplementedException();
}
private MObject? EvaluateEmptyExpression(BoundEmptyExpression node)
{
throw new NotImplementedException();
}
private MObject? EvaluateAssignmentExpression(BoundAssignmentExpression node)
{
var rightValue = EvaluateExpression(node.Right);
if (rightValue is null)
{
_diagnostics.ReportCannotEvaluateExpression(
new TextSpan(node.Right.Syntax.Position, node.Right.Syntax.Position + node.Right.Syntax.FullWidth));
return null;
}
var left = node.Left;
if (left.Kind == BoundNodeKind.IdentifierNameExpression)
{
var leftIdentifier = (BoundIdentifierNameExpression)left;
var variableName = leftIdentifier.Name;
SetVariableValue(variableName, rightValue);
return rightValue;
}
throw new NotImplementedException();
}
private MObject? GetVariableValue(string name)
{
if (_insideFunction)
{
if (_context.Variables.TryGetValue(name, out var globalValue))
{
return globalValue;
}
var currentScope = _scopeStack.Peek();
return currentScope.Variables.TryGetValue(name, out var localValue) ? globalValue : null;
}
else
{
if (_context.Variables.TryGetValue(name, out var globalValue))
{
return globalValue;
}
return null;
}
}
private void SetVariableValue(string name, MObject value)
{
if (_insideFunction)
{
if (_context.Variables.ContainsKey(name))
{
_context.Variables[name] = value;
}
else
{
var currentScope = _scopeStack.Peek();
currentScope.Variables[name] = value;
}
}
else
{
_context.Variables[name] = value;
}
}
private MObject? EvaluateLambdaExpression(BoundLambdaExpression node)
{
throw new NotImplementedException();
}
private MObject? EvaluateNamedFunctionHandleExpression(BoundNamedFunctionHandleExpression node)
{
throw new NotImplementedException();
}
}
}