Implemented very basic stacktrace
This commit is contained in:
parent
668d60ce46
commit
834d65f38e
|
@ -6,8 +6,11 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
|||
{
|
||||
public abstract class ScriptFunction : ScriptType
|
||||
{
|
||||
protected ScriptFunction(bool isCoroutine)
|
||||
public string Name { get; protected set; }
|
||||
|
||||
protected ScriptFunction(string name, bool isCoroutine)
|
||||
{
|
||||
Name = name;
|
||||
IsCoroutine = isCoroutine;
|
||||
}
|
||||
|
||||
|
@ -24,7 +27,7 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
|||
|
||||
public bool IsCoroutine { get; }
|
||||
|
||||
public abstract ScriptType Run(Diagnostics diagnostics, ScriptType[] variables, Script script, EvaluationScope scope, TextSpan span);
|
||||
public abstract IEnumerator RunCoroutine(Diagnostics diagnostics, ScriptType[] variables, Script script, EvaluationScope scope, TextSpan span);
|
||||
public abstract ScriptType Run(Diagnostics diagnostics, ScriptType[] variables, EvaluationScope scope, TextSpan span, EvaluationState state);
|
||||
public abstract IEnumerator RunCoroutine(Diagnostics diagnostics, ScriptType[] variables, EvaluationScope scope, TextSpan span, EvaluationState state);
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
|||
public class ScriptMethodInfoFunction : ScriptFunction
|
||||
{
|
||||
public ScriptMethodInfoFunction(UserDataMethod method, object o, bool directTypeManipulation,
|
||||
bool isCoroutine, bool passScriptReference = false, bool passScopeReference = false) : base(isCoroutine)
|
||||
bool isCoroutine, bool passScriptReference = false, bool passScopeReference = false) : base(method.Name, isCoroutine)
|
||||
{
|
||||
Method = method;
|
||||
_object = o;
|
||||
|
@ -46,31 +46,36 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
|||
return Method.GetMethods().First().Parameters;
|
||||
}
|
||||
|
||||
public override ScriptType Run(Diagnostics diagnostics, ScriptType[] variables, Script script, EvaluationScope scope, TextSpan span)
|
||||
public override ScriptType Run(Diagnostics diagnostics, ScriptType[] variables, EvaluationScope scope, TextSpan span, EvaluationState state)
|
||||
{
|
||||
var result = Execute(diagnostics, variables, script, scope, span);
|
||||
state.Stacktrace.Push(this);
|
||||
var result = Execute(variables, state.Script, scope, span);
|
||||
state.Stacktrace.Pop();
|
||||
if (_directTypeManipulation)
|
||||
return (ScriptType)result;
|
||||
return result.ToScriptType();
|
||||
|
||||
}
|
||||
|
||||
public override IEnumerator RunCoroutine(Diagnostics diagnostics, ScriptType[] variables, Script script, EvaluationScope scope,
|
||||
TextSpan span)
|
||||
public override IEnumerator RunCoroutine(Diagnostics diagnostics, ScriptType[] variables, EvaluationScope scope,
|
||||
TextSpan span , EvaluationState state)
|
||||
{
|
||||
var result = Execute(diagnostics, variables, script, scope, span);
|
||||
state.Stacktrace.Push(this);
|
||||
var result = Execute(variables, state.Script, scope, span);
|
||||
if (result is IEnumerator enumerator)
|
||||
{
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
yield return enumerator.Current;
|
||||
}
|
||||
state.Stacktrace.Pop();
|
||||
yield break;
|
||||
}
|
||||
yield return result;
|
||||
state.Stacktrace.Pop();
|
||||
}
|
||||
|
||||
private object Execute(Diagnostics diagnostics, ScriptType[] variables, Script script, EvaluationScope scope, TextSpan span)
|
||||
private object Execute(IEnumerable<ScriptType> variables, Script script, EvaluationScope scope, TextSpan span)
|
||||
{
|
||||
var objects = new List<object>();
|
||||
if (_passScriptReference)
|
||||
|
@ -132,9 +137,9 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
|||
// if we haven't found a method, we throw an exception
|
||||
if (method == null)
|
||||
{
|
||||
throw new ScriptRuntimeException(script.FileName,
|
||||
throw new EvaluationException(script.FileName,
|
||||
$"Can't find method {Method.Name} with parameter types {string.Join(", ", convertedTypes.Select(x => x.Name))} on type {_object.GetType().Name}",
|
||||
span, diagnostics.ScriptString.GetSpan(span));
|
||||
span);
|
||||
}
|
||||
// get the method parameters
|
||||
var parameters = method.GetParameters();
|
||||
|
|
|
@ -16,37 +16,46 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
|||
{
|
||||
public List<ScriptRuntimeFunctionOption> Options { get; }
|
||||
|
||||
public ScriptRuntimeFunction(List<ScriptRuntimeFunctionOption> options, bool isCoroutine) : base(isCoroutine)
|
||||
public ScriptRuntimeFunction(string name, List<ScriptRuntimeFunctionOption> options, bool isCoroutine) : base(name, isCoroutine)
|
||||
{
|
||||
Options = options;
|
||||
}
|
||||
|
||||
public override ScriptType Run(Diagnostics diagnostics, ScriptType[] variables, Script script,
|
||||
EvaluationScope scope, TextSpan span)
|
||||
public void SetName(string name)
|
||||
{
|
||||
var option = GetValidOption(variables);
|
||||
if (option == null)
|
||||
{
|
||||
throw new EvaluationException(script.FileName,
|
||||
$"No valid function found", span);
|
||||
}
|
||||
return option.Run(diagnostics, variables, script, scope, span);
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public override IEnumerator RunCoroutine(Diagnostics diagnostics, ScriptType[] variables, Script script, EvaluationScope scope,
|
||||
TextSpan span)
|
||||
public override ScriptType Run(Diagnostics diagnostics, ScriptType[] variables, EvaluationScope scope, TextSpan span, EvaluationState state)
|
||||
{
|
||||
var option = GetValidOption(variables);
|
||||
if (option == null)
|
||||
{
|
||||
throw new EvaluationException(script.FileName,
|
||||
throw new EvaluationException(state.Script.FileName,
|
||||
$"No valid function found", span);
|
||||
}
|
||||
var coroutine = option.RunCoroutine(diagnostics, variables, script, scope, span);
|
||||
state.Stacktrace.Push(this);
|
||||
var result = option.Run(diagnostics, variables, state.Script, scope, span);
|
||||
state.Stacktrace.Pop();
|
||||
return result;
|
||||
}
|
||||
|
||||
public override IEnumerator RunCoroutine(Diagnostics diagnostics, ScriptType[] variables, EvaluationScope scope,
|
||||
TextSpan span, EvaluationState state)
|
||||
{
|
||||
var option = GetValidOption(variables);
|
||||
if (option == null)
|
||||
{
|
||||
throw new EvaluationException(state.Script.FileName,
|
||||
$"No valid function found", span);
|
||||
}
|
||||
state.Stacktrace.Push(this);
|
||||
var coroutine = option.RunCoroutine(diagnostics, variables, state.Script, scope, span);
|
||||
while (coroutine.MoveNext())
|
||||
{
|
||||
yield return coroutine.Current;
|
||||
}
|
||||
state.Stacktrace.Pop();
|
||||
}
|
||||
|
||||
public ScriptRuntimeFunctionOption GetValidOption(object[] variables)
|
||||
|
|
|
@ -149,36 +149,32 @@ namespace Upsilon.Binder
|
|||
return ((ScriptNumber) left) < ((ScriptNumber) right);
|
||||
}
|
||||
|
||||
throw new ScriptRuntimeException(state.Script.FileName,
|
||||
$"Can't find operator '{Operator.Kind}' for types '{left.Type}' and '{right.Type}'", Span,
|
||||
diagnostics.ScriptString.GetSpan(Span));
|
||||
throw new EvaluationException(state.Script.FileName,
|
||||
$"Can't find operator '{Operator.Kind}' for types '{left.Type}' and '{right.Type}'", Span);
|
||||
case BoundBinaryOperator.OperatorKind.LessEquals:
|
||||
if (left.Type == Type.Number && right.Type == Type.Number)
|
||||
{
|
||||
return ((ScriptNumber) left) <= ((ScriptNumber) right);
|
||||
}
|
||||
|
||||
throw new ScriptRuntimeException(state.Script.FileName,
|
||||
$"Can't find operator '{Operator.Kind}' for types '{left.Type}' and '{right.Type}'", Span,
|
||||
diagnostics.ScriptString.GetSpan(Span));
|
||||
throw new EvaluationException(state.Script.FileName,
|
||||
$"Can't find operator '{Operator.Kind}' for types '{left.Type}' and '{right.Type}'", Span);
|
||||
case BoundBinaryOperator.OperatorKind.Greater:
|
||||
if (left.Type == Type.Number && right.Type == Type.Number)
|
||||
{
|
||||
return ((ScriptNumber) left) > ((ScriptNumber) right);
|
||||
}
|
||||
|
||||
throw new ScriptRuntimeException(state.Script.FileName,
|
||||
$"Can't find operator '{Operator.Kind}' for types '{left.Type}' and '{right.Type}'", Span,
|
||||
diagnostics.ScriptString.GetSpan(Span));
|
||||
throw new EvaluationException(state.Script.FileName,
|
||||
$"Can't find operator '{Operator.Kind}' for types '{left.Type}' and '{right.Type}'", Span);
|
||||
case BoundBinaryOperator.OperatorKind.GreaterEquals:
|
||||
if (left.Type == Type.Number && right.Type == Type.Number)
|
||||
{
|
||||
return ((ScriptNumber) left) >= ((ScriptNumber) right);
|
||||
}
|
||||
|
||||
throw new ScriptRuntimeException(state.Script.FileName,
|
||||
$"Can't find operator '{Operator.Kind}' for types '{left.Type}' and '{right.Type}'", Span,
|
||||
diagnostics.ScriptString.GetSpan(Span));
|
||||
throw new EvaluationException(state.Script.FileName,
|
||||
$"Can't find operator '{Operator.Kind}' for types '{left.Type}' and '{right.Type}'", Span);
|
||||
default:
|
||||
throw new Exception("Invalid Binary Operator: " + Operator.Kind);
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace Upsilon.Binder
|
|||
ls.Add(evaluate);
|
||||
}
|
||||
|
||||
var val = function.Run(diagnostics, ls.ToArray(), state.Script, scope, Span);
|
||||
var val = function.Run(diagnostics, ls.ToArray(), scope, Span, state);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace Upsilon.Binder
|
|||
internal override ScriptType Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||
{
|
||||
var option = new ScriptRuntimeFunction.ScriptRuntimeFunctionOption(Parameters, Block, scope);
|
||||
var func = new ScriptRuntimeFunction(new List<ScriptRuntimeFunction.ScriptRuntimeFunctionOption>() {option},
|
||||
var func = new ScriptRuntimeFunction("<anonymous>", new List<ScriptRuntimeFunction.ScriptRuntimeFunctionOption>() {option},
|
||||
IsCoroutine);
|
||||
return func;
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ namespace Upsilon.Binder
|
|||
internal override void Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||
{
|
||||
var func = (ScriptRuntimeFunction)Func.Evaluate(scope, diagnostics, ref state);
|
||||
func.SetName(Variable.Name);
|
||||
if (Variable.Local)
|
||||
{
|
||||
if (scope.Variables.TryGetValue(Variable.Name, out var f) && f is ScriptRuntimeFunction scriptRuntimeFunction)
|
||||
|
|
|
@ -27,9 +27,8 @@ namespace Upsilon.Binder
|
|||
|
||||
internal override void Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||
{
|
||||
throw new ScriptRuntimeException(state.Script.FileName,
|
||||
"Yielding in a function that's not executed as a coroutine is not possible.", Span,
|
||||
diagnostics.ScriptString.GetLine(Span.StartLine));
|
||||
throw new EvaluationException(state.Script.FileName,
|
||||
"Yielding in a function that's not executed as a coroutine is not possible.", Span);
|
||||
}
|
||||
|
||||
internal override IEnumerator EvaluateCoroutine(EvaluationScope scope, Diagnostics diagnostics, EvaluationState state)
|
||||
|
@ -51,7 +50,7 @@ namespace Upsilon.Binder
|
|||
var evaluate = t.Evaluate(scope, diagnostics, ref state);
|
||||
ls.Add(evaluate);
|
||||
}
|
||||
var coroutine = function.RunCoroutine(diagnostics, ls.ToArray(), state.Script, scope, Span);
|
||||
var coroutine = function.RunCoroutine(diagnostics, ls.ToArray(), scope, Span, state);
|
||||
while (coroutine.MoveNext())
|
||||
{
|
||||
yield return coroutine.Current;
|
||||
|
|
|
@ -2,12 +2,13 @@ using Upsilon.BaseTypes;
|
|||
|
||||
namespace Upsilon.Evaluator
|
||||
{
|
||||
internal class EvaluationState
|
||||
public class EvaluationState
|
||||
{
|
||||
public Script Script;
|
||||
public bool Returned;
|
||||
public bool HasBroken;
|
||||
public ScriptType ReturnValue;
|
||||
public Stacktrace Stacktrace = new Stacktrace();
|
||||
public ScriptType LastValue;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Upsilon.BaseTypes.ScriptFunction;
|
||||
|
||||
namespace Upsilon.Evaluator
|
||||
{
|
||||
public class Stacktrace
|
||||
{
|
||||
private readonly Stack<ScriptFunction> _stack = new Stack<ScriptFunction>();
|
||||
|
||||
public void Push(ScriptFunction statement)
|
||||
{
|
||||
_stack.Push(statement);
|
||||
}
|
||||
|
||||
public ScriptFunction Pop()
|
||||
{
|
||||
return _stack.Pop();
|
||||
}
|
||||
|
||||
public IEnumerable<ScriptFunction> GetTopStack(int i)
|
||||
{
|
||||
return _stack.Take(i);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +1,20 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using Upsilon.Evaluator;
|
||||
using Upsilon.Text;
|
||||
|
||||
namespace Upsilon.Exceptions
|
||||
{
|
||||
public class EvaluationException : Exception
|
||||
{
|
||||
private readonly Stacktrace _stacktrace;
|
||||
public string FileName { get; }
|
||||
public string ErrorMessage { get; }
|
||||
public TextSpan Span { get; }
|
||||
|
||||
public EvaluationException(string fileName, string message, TextSpan span)
|
||||
public EvaluationException(string fileName, string message, TextSpan span, Stacktrace stacktrace = null)
|
||||
{
|
||||
_stacktrace = stacktrace;
|
||||
FileName = fileName;
|
||||
ErrorMessage = message;
|
||||
Span = span;
|
||||
|
@ -18,7 +22,15 @@ namespace Upsilon.Exceptions
|
|||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"[{FileName}] ({Span.StartLine},{Span.StartPosition}) {ErrorMessage}";
|
||||
var err = new StringBuilder($"[{FileName}] ({Span.StartLine},{Span.StartPosition}) {ErrorMessage}");
|
||||
if (_stacktrace != null)
|
||||
{
|
||||
foreach (var statement in _stacktrace.GetTopStack(10))
|
||||
{
|
||||
err.Append($"\n{statement.Name}");
|
||||
}
|
||||
}
|
||||
return err.ToString();
|
||||
}
|
||||
|
||||
public override string Message => ToString();
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
using System;
|
||||
using Upsilon.Text;
|
||||
|
||||
namespace Upsilon.Exceptions
|
||||
{
|
||||
public class ScriptRuntimeException : Exception
|
||||
{
|
||||
public string FileName { get; }
|
||||
public string ErrorMessage { get; }
|
||||
public int Line { get; }
|
||||
public int Character { get; }
|
||||
public string ErrorLine { get; }
|
||||
|
||||
public ScriptRuntimeException(string fileName, string errorMessage, TextSpan position, string errorLine)
|
||||
{
|
||||
FileName = fileName;
|
||||
ErrorMessage = errorMessage;
|
||||
Line = position.StartLine;
|
||||
Character = position.StartPosition;
|
||||
ErrorLine = errorLine;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"[{FileName}] {ErrorMessage} at ({Line}, {Character})\n{ErrorLine}";
|
||||
}
|
||||
|
||||
public override string Message => ToString();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue