Evaluation in REPL
This commit is contained in:
parent
df0cd4dea3
commit
886b897a4c
@ -1,7 +1,11 @@
|
|||||||
namespace Parser
|
using Parser.Objects;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Parser
|
||||||
{
|
{
|
||||||
public class CompilationContext
|
public class CompilationContext
|
||||||
{
|
{
|
||||||
|
public Dictionary<string, MObject> Variables { get; } = new Dictionary<string, MObject>();
|
||||||
public static CompilationContext Empty => new CompilationContext();
|
public static CompilationContext Empty => new CompilationContext();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,21 +1,31 @@
|
|||||||
using Parser.Internal;
|
using Parser.Internal;
|
||||||
|
using Parser.MFunctions;
|
||||||
using Parser.Objects;
|
using Parser.Objects;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
namespace Parser
|
namespace Parser
|
||||||
{
|
{
|
||||||
|
internal class EvaluationScope
|
||||||
|
{
|
||||||
|
public Dictionary<string, MObject> Variables { get; } = new Dictionary<string, MObject>();
|
||||||
|
}
|
||||||
|
|
||||||
internal class Evaluator
|
internal class Evaluator
|
||||||
{
|
{
|
||||||
private SyntaxTree _syntaxTree;
|
private readonly SyntaxTree _syntaxTree;
|
||||||
private CompilationContext _context;
|
private readonly CompilationContext _context;
|
||||||
private DiagnosticsBag _diagnostics;
|
private readonly DiagnosticsBag _diagnostics = new DiagnosticsBag();
|
||||||
|
private bool _insideFunction = false;
|
||||||
|
private readonly Stack<EvaluationScope> _scopeStack = new Stack<EvaluationScope>();
|
||||||
|
|
||||||
public Evaluator(SyntaxTree syntaxTree, CompilationContext context)
|
public Evaluator(SyntaxTree syntaxTree, CompilationContext context)
|
||||||
{
|
{
|
||||||
_syntaxTree = syntaxTree;
|
_syntaxTree = syntaxTree;
|
||||||
_context = context;
|
_context = context;
|
||||||
_diagnostics = new DiagnosticsBag();
|
var outerScope = new EvaluationScope();
|
||||||
|
_scopeStack.Push(outerScope);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal EvaluationResult Evaluate()
|
internal EvaluationResult Evaluate()
|
||||||
@ -178,7 +188,7 @@ namespace Parser
|
|||||||
|
|
||||||
private MObject? EvaluateParenthesizedExpression(ParenthesizedExpressionSyntaxNode expression)
|
private MObject? EvaluateParenthesizedExpression(ParenthesizedExpressionSyntaxNode expression)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return EvaluateExpression(expression.Expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MObject? EvaluateClassInvokation(BaseClassInvokationSyntaxNode expression)
|
private MObject? EvaluateClassInvokation(BaseClassInvokationSyntaxNode expression)
|
||||||
@ -243,17 +253,47 @@ namespace Parser
|
|||||||
|
|
||||||
private MObject? EvaluateNumberLiteralExpression(NumberLiteralSyntaxNode expression)
|
private MObject? EvaluateNumberLiteralExpression(NumberLiteralSyntaxNode expression)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return expression.Number.Value is double value
|
||||||
|
? MObject.CreateDoubleNumber(value)
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MObject? EvaluateIdentifierNameExpression(IdentifierNameExpressionSyntaxNode expression)
|
private MObject? EvaluateIdentifierNameExpression(IdentifierNameExpressionSyntaxNode expression)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
var variableName = expression.Name.Text;
|
||||||
|
var maybeValue = GetVariableValue(variableName);
|
||||||
|
if (maybeValue is null)
|
||||||
|
{
|
||||||
|
_diagnostics.ReportVariableNotFound(
|
||||||
|
new TextSpan(expression.Name.Position, expression.Name.Text.Length),
|
||||||
|
variableName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return maybeValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MObject? EvaluateBinaryOperation(BinaryOperationExpressionSyntaxNode expression)
|
private MObject? EvaluateBinaryOperation(BinaryOperationExpressionSyntaxNode expression)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
var left = EvaluateExpression(expression.Lhs);
|
||||||
|
if (left is null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var right = EvaluateExpression(expression.Rhs);
|
||||||
|
if (right is null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return expression.Operation.Kind switch
|
||||||
|
{
|
||||||
|
TokenKind.PlusToken => MOperations.Plus(left, right),
|
||||||
|
TokenKind.MinusToken => MOperations.Minus(left, right),
|
||||||
|
TokenKind.StarToken => MOperations.Star(left, right),
|
||||||
|
TokenKind.SlashToken => MOperations.Slash(left, right),
|
||||||
|
_ => throw new NotImplementedException($"Binary operation {expression.Operation.Kind} is not implemented."),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private MObject? EvaluateCompoundName(CompoundNameExpressionSyntaxNode expression)
|
private MObject? EvaluateCompoundName(CompoundNameExpressionSyntaxNode expression)
|
||||||
@ -273,9 +313,69 @@ namespace Parser
|
|||||||
|
|
||||||
private MObject? EvaluateAssignmentExpression(AssignmentExpressionSyntaxNode expression)
|
private MObject? EvaluateAssignmentExpression(AssignmentExpressionSyntaxNode expression)
|
||||||
{
|
{
|
||||||
|
var rightValue = EvaluateExpression(expression.Rhs);
|
||||||
|
if (rightValue is null)
|
||||||
|
{
|
||||||
|
_diagnostics.ReportCannotEvaluateExpression(
|
||||||
|
new TextSpan(expression.Rhs.Position, expression.Rhs.Position + expression.Rhs.FullWidth));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var left = expression.Lhs;
|
||||||
|
if (left.Kind == TokenKind.IdentifierNameExpression)
|
||||||
|
{
|
||||||
|
var leftIdentifier = (IdentifierNameExpressionSyntaxNode)left;
|
||||||
|
var variableName = leftIdentifier.Name.Text;
|
||||||
|
SetVariableValue(variableName, rightValue);
|
||||||
|
return rightValue;
|
||||||
|
}
|
||||||
|
|
||||||
throw new NotImplementedException();
|
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(LambdaExpressionSyntaxNode expression)
|
private MObject? EvaluateLambdaExpression(LambdaExpressionSyntaxNode expression)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
@ -67,6 +68,11 @@ namespace Parser.Internal
|
|||||||
Report(span, "Unmatched open parenthesis by the end of file.");
|
Report(span, "Unmatched open parenthesis by the end of file.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void ReportCannotEvaluateExpression(TextSpan span)
|
||||||
|
{
|
||||||
|
Report(span, $"Cannot evaluate expression.");
|
||||||
|
}
|
||||||
|
|
||||||
public IEnumerator<Diagnostic> GetEnumerator()
|
public IEnumerator<Diagnostic> GetEnumerator()
|
||||||
{
|
{
|
||||||
return _diagnostics.GetEnumerator();
|
return _diagnostics.GetEnumerator();
|
||||||
@ -77,5 +83,9 @@ namespace Parser.Internal
|
|||||||
return GetEnumerator();
|
return GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void ReportVariableNotFound(TextSpan span, string variableName)
|
||||||
|
{
|
||||||
|
Report(span, $"Variable '{variableName}' not found.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -43,6 +43,11 @@ namespace Parser.Internal
|
|||||||
|
|
||||||
internal abstract Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent, int position);
|
internal abstract Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent, int position);
|
||||||
|
|
||||||
|
public virtual object? GetValue()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
protected int _fullWidth;
|
protected int _fullWidth;
|
||||||
|
|
||||||
public int FullWidth => _fullWidth;
|
public int FullWidth => _fullWidth;
|
||||||
|
@ -13,6 +13,7 @@ namespace Parser.Internal
|
|||||||
public string Text { get; set; } = "";
|
public string Text { get; set; } = "";
|
||||||
public string StringValue { get; set; } = "";
|
public string StringValue { get; set; } = "";
|
||||||
public double DoubleValue { get; set; }
|
public double DoubleValue { get; set; }
|
||||||
|
public bool ImaginaryFlag { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private ITextWindow Window { get; }
|
private ITextWindow Window { get; }
|
||||||
@ -358,20 +359,48 @@ namespace Parser.Internal
|
|||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
|
tokenInfo.Kind = TokenKind.NumberLiteralToken;
|
||||||
|
Range rangeToParse;
|
||||||
if (Window.PeekChar(n) == 'i' || Window.PeekChar(n) == 'j')
|
if (Window.PeekChar(n) == 'i' || Window.PeekChar(n) == 'j')
|
||||||
{
|
{
|
||||||
|
tokenInfo.ImaginaryFlag = true;
|
||||||
n++;
|
n++;
|
||||||
|
rangeToParse = ..^1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rangeToParse = ..;
|
||||||
}
|
}
|
||||||
var s = Window.GetAndConsumeChars(n);
|
|
||||||
|
|
||||||
tokenInfo.Kind = TokenKind.NumberLiteralToken;
|
var s = Window.GetAndConsumeChars(n);
|
||||||
tokenInfo.Text = s;
|
tokenInfo.Text = s;
|
||||||
return true;
|
var maybeValue = ParseDoubleValue(s[rangeToParse]);
|
||||||
|
if (maybeValue is double value)
|
||||||
|
{
|
||||||
|
tokenInfo.DoubleValue = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tokenInfo.DoubleValue = double.NaN;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private double? ParseDoubleValue(string s)
|
||||||
|
{
|
||||||
|
if (double.TryParse(s, out var doubleValue))
|
||||||
|
{
|
||||||
|
return doubleValue;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private bool ContinueLexingGeneralStringLiteral(ref TokenInfo tokenInfo, char quote)
|
private bool ContinueLexingGeneralStringLiteral(ref TokenInfo tokenInfo, char quote)
|
||||||
{
|
{
|
||||||
var status = 0; // no errors
|
var status = 0; // no errors
|
||||||
|
@ -116,6 +116,7 @@ namespace Parser.Internal
|
|||||||
_fullWidth = text?.Length ?? 0;
|
_fullWidth = text?.Length ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing)
|
public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing)
|
||||||
{
|
{
|
||||||
writer.Write(_text);
|
writer.Write(_text);
|
||||||
@ -126,7 +127,9 @@ namespace Parser.Internal
|
|||||||
return new SyntaxTokenWithValue<T>(Kind, _text, _value, diagnostics);
|
return new SyntaxTokenWithValue<T>(Kind, _text, _value, diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
public T Value => _value;
|
public T TypedValue => _value;
|
||||||
|
|
||||||
|
public override object? Value => TypedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class SyntaxTokenWithValueAndTrivia<T> : SyntaxTokenWithValue<T>
|
internal class SyntaxTokenWithValueAndTrivia<T> : SyntaxTokenWithValue<T>
|
||||||
@ -181,7 +184,7 @@ namespace Parser.Internal
|
|||||||
|
|
||||||
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||||
{
|
{
|
||||||
return new SyntaxTokenWithValueAndTrivia<T>(Kind, _text, Value, LeadingTrivia, TrailingTrivia, diagnostics);
|
return new SyntaxTokenWithValueAndTrivia<T>(Kind, _text, TypedValue, LeadingTrivia, TrailingTrivia, diagnostics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,6 +314,10 @@ namespace Parser.Internal
|
|||||||
|
|
||||||
internal static SyntaxToken NoneToken => new MissingTokenWithTrivia(TokenKind.None, s_EmptySyntaxTriviaList, s_EmptySyntaxTriviaList);
|
internal static SyntaxToken NoneToken => new MissingTokenWithTrivia(TokenKind.None, s_EmptySyntaxTriviaList, s_EmptySyntaxTriviaList);
|
||||||
|
|
||||||
|
public virtual object? Value => null;
|
||||||
|
|
||||||
|
public override object? GetValue() => Value;
|
||||||
|
|
||||||
public virtual int Width => Text.Length;
|
public virtual int Width => Text.Length;
|
||||||
|
|
||||||
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore => s_EmptySyntaxTriviaList;
|
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore => s_EmptySyntaxTriviaList;
|
||||||
|
50
Parser/MFunctions/MOperations.cs
Normal file
50
Parser/MFunctions/MOperations.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
using Parser.Objects;
|
||||||
|
|
||||||
|
namespace Parser.MFunctions
|
||||||
|
{
|
||||||
|
public static class MOperations
|
||||||
|
{
|
||||||
|
public static MObject? Plus(MObject left, MObject right)
|
||||||
|
{
|
||||||
|
if (left is MDoubleNumber { Value: var lValue }
|
||||||
|
&& right is MDoubleNumber { Value: var rValue })
|
||||||
|
{
|
||||||
|
return MObject.CreateDoubleNumber(lValue + rValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MObject? Minus(MObject left, MObject right)
|
||||||
|
{
|
||||||
|
if (left is MDoubleNumber { Value: var lValue }
|
||||||
|
&& right is MDoubleNumber { Value: var rValue })
|
||||||
|
{
|
||||||
|
return MObject.CreateDoubleNumber(lValue - rValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MObject? Star(MObject left, MObject right)
|
||||||
|
{
|
||||||
|
if (left is MDoubleNumber { Value: var lValue }
|
||||||
|
&& right is MDoubleNumber { Value: var rValue })
|
||||||
|
{
|
||||||
|
return MObject.CreateDoubleNumber(lValue * rValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public static MObject? Slash(MObject left, MObject right)
|
||||||
|
{
|
||||||
|
if (left is MDoubleNumber { Value: var lValue }
|
||||||
|
&& right is MDoubleNumber { Value: var rValue })
|
||||||
|
{
|
||||||
|
return MObject.CreateDoubleNumber(lValue / rValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,24 @@
|
|||||||
namespace Parser.Objects
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace Parser.Objects
|
||||||
{
|
{
|
||||||
public class MDoubleNumber : MObject
|
public class MDoubleNumber : MObject
|
||||||
{
|
{
|
||||||
|
private MDoubleNumber(double value)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Value { get; }
|
||||||
|
|
||||||
|
public static MDoubleNumber Create(double value)
|
||||||
|
{
|
||||||
|
return new MDoubleNumber(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Value.ToString(CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,5 +2,9 @@
|
|||||||
{
|
{
|
||||||
public abstract class MObject
|
public abstract class MObject
|
||||||
{
|
{
|
||||||
|
public static MDoubleNumber CreateDoubleNumber(double value)
|
||||||
|
{
|
||||||
|
return MDoubleNumber.Create(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -29,6 +29,8 @@ namespace Parser
|
|||||||
|
|
||||||
public int Position { get; }
|
public int Position { get; }
|
||||||
|
|
||||||
|
public object? Value => _token.GetValue();
|
||||||
|
|
||||||
public bool Equals(SyntaxToken other)
|
public bool Equals(SyntaxToken other)
|
||||||
{
|
{
|
||||||
return Equals(_parent, other._parent) && Equals(_token, other._token);
|
return Equals(_parent, other._parent) && Equals(_token, other._token);
|
||||||
|
@ -36,7 +36,9 @@ namespace Repl
|
|||||||
|
|
||||||
private void Print(string result)
|
private void Print(string result)
|
||||||
{
|
{
|
||||||
Console.Write(result);
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
|
Console.WriteLine(result);
|
||||||
|
Console.ResetColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string Read()
|
private string Read()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user