Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add user code exceptions support. #8

Merged
merged 12 commits into from
Apr 1, 2024
15 changes: 15 additions & 0 deletions Core/EVIL.Grammar/AST/Statements/ThrowStatement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using EVIL.Grammar.AST.Base;

namespace EVIL.Grammar.AST.Statements
{
public class ThrowStatement : Statement
{
public Expression ThrownExpression { get; }

public ThrowStatement(Expression thrownExpression)
{
ThrownExpression = thrownExpression;
Reparent(ThrownExpression);
}
}
}
22 changes: 22 additions & 0 deletions Core/EVIL.Grammar/AST/Statements/TryStatement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using EVIL.Grammar.AST.Base;
using EVIL.Grammar.AST.Miscellaneous;

namespace EVIL.Grammar.AST.Statements
{
public class TryStatement : Statement
{
public Statement InnerStatement { get; }

public IdentifierNode HandlerExceptionLocal { get; }
public Statement HandlerStatement { get; }

public TryStatement(Statement innerStatement, IdentifierNode handlerExceptionLocal, Statement handlerStatement)
{
InnerStatement = innerStatement;
HandlerExceptionLocal = handlerExceptionLocal;
HandlerStatement = handlerStatement;

Reparent(InnerStatement, HandlerExceptionLocal, HandlerStatement);
}
}
}
2 changes: 1 addition & 1 deletion Core/EVIL.Grammar/EVIL.Grammar.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<Nullable>enable</Nullable>
<LangVersion>11.0</LangVersion>

<Version>2.4.0</Version>
<Version>3.0.0</Version>
<AssemblyName>EVIL.Grammar</AssemblyName>
<AssemblyTitle>EVIL.Grammar</AssemblyTitle>
</PropertyGroup>
Expand Down
9 changes: 9 additions & 0 deletions Core/EVIL.Grammar/Parsing/Base/Parser.Statement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ private Statement Statement()
node = ValStatement(false);
Match(Token.Semicolon);
break;

case TokenType.Try:
node = TryStatement();
break;

case TokenType.Throw:
node = ThrowStatement();
Match(Token.Semicolon);
break;

case TokenType.Increment:
case TokenType.Decrement:
Expand Down
17 changes: 17 additions & 0 deletions Core/EVIL.Grammar/Parsing/Statements/Parser.ThrowStatement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using EVIL.Grammar.AST.Statements;
using EVIL.Lexical;

namespace EVIL.Grammar.Parsing
{
public partial class Parser
{
private ThrowStatement ThrowStatement()
{
var (line, col) = Match(Token.Throw);
var expression = AssignmentExpression();

return new ThrowStatement(expression)
{ Line = line, Column = col };
}
}
}
25 changes: 25 additions & 0 deletions Core/EVIL.Grammar/Parsing/Statements/Parser.TryStatement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using EVIL.Grammar.AST.Statements;
using EVIL.Lexical;

namespace EVIL.Grammar.Parsing
{
public partial class Parser
{
private TryStatement TryStatement()
{
var (line, col) = Match(Token.Try);
var protectedStatement = BlockStatement();
Match(Token.Catch);
Match(Token.LParenthesis);
var exceptionObjectIdentifier = Identifier();
Match(Token.RParenthesis);
var handlerStatement = BlockStatement();

return new TryStatement(
protectedStatement,
exceptionObjectIdentifier,
handlerStatement
) { Line = line, Column = col };
}
}
}
4 changes: 4 additions & 0 deletions Core/EVIL.Grammar/Traversal/AstVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ protected AstVisitor()
{ typeof(BreakStatement), (n) => Visit((BreakStatement)n) },
{ typeof(SkipStatement), (n) => Visit((SkipStatement)n) },
{ typeof(OverrideStatement), (n) => Visit((OverrideStatement)n) },
{ typeof(TryStatement), (n) => Visit((TryStatement)n) },
{ typeof(ThrowStatement), (n) => Visit((ThrowStatement)n) },
{ typeof(TableExpression), (n) => Visit((TableExpression)n) },
{ typeof(ArrayExpression), (n) => Visit((ArrayExpression)n) },
{ typeof(SelfExpression), (n) => Visit((SelfExpression)n) },
Expand Down Expand Up @@ -109,6 +111,8 @@ public virtual void Visit(AstNode node)
public abstract void Visit(BreakStatement breakStatement);
public abstract void Visit(SkipStatement skipStatement);
public abstract void Visit(OverrideStatement overrideStatement);
public abstract void Visit(TryStatement tryStatement);
public abstract void Visit(ThrowStatement throwStatement);
public abstract void Visit(TableExpression tableExpression);
public abstract void Visit(ArrayExpression arrayExpression);
public abstract void Visit(SelfExpression selfExpression);
Expand Down
2 changes: 1 addition & 1 deletion Core/EVIL.Lexical/EVIL.Lexical.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<Nullable>enable</Nullable>
<LangVersion>11.0</LangVersion>

<Version>2.3.0</Version>
<Version>3.0.0</Version>
<AssemblyName>EVIL.Lexical</AssemblyName>
<AssemblyTitle>EVIL.Lexical</AssemblyTitle>
</PropertyGroup>
Expand Down
3 changes: 3 additions & 0 deletions Core/EVIL.Lexical/Lexer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,9 @@ private Token GetIdentifierOrKeyword()
"false" => Token.False,
"nil" => Token.Nil,
"typeof" => Token.TypeOf,
"try" => Token.Try,
"catch" => Token.Catch,
"throw" => Token.Throw,
"yield" => Token.Yield,
"each" => Token.Each,
"array" => Token.Array,
Expand Down
3 changes: 3 additions & 0 deletions Core/EVIL.Lexical/Token.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ public override int GetHashCode()
public static readonly Token Is = new(TokenType.Is, TokenClass.Operator, "is");
public static readonly Token IsNot = new(TokenType.IsNot, TokenClass.Operator, "!is");
public static readonly Token TypeOf = new(TokenType.TypeOf, TokenClass.Operator, "typeof");
public static readonly Token Try = new(TokenType.Try, TokenClass.Keyword, "try");
public static readonly Token Catch = new(TokenType.Catch, TokenClass.Keyword, "catch");
public static readonly Token Throw = new(TokenType.Throw, TokenClass.Keyword, "throw");

public static readonly Token Val = new(TokenType.Val, TokenClass.Keyword, "val");
public static readonly Token If = new(TokenType.If, TokenClass.Keyword, "if");
Expand Down
3 changes: 3 additions & 0 deletions Core/EVIL.Lexical/TokenType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ public enum TokenType
IsNot,
Nil,
TypeOf,
Try,
Catch,
Throw,
Yield,
Rw,
NaN,
Expand Down
8 changes: 7 additions & 1 deletion VirtualMachine/Ceres/Ceres.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<Nullable>enable</Nullable>
<LangVersion>11.0</LangVersion>

<Version>3.3.0</Version>
<Version>4.0.0</Version>
<AssemblyName>Ceres</AssemblyName>
<AssemblyTitle>Ceres</AssemblyTitle>

Expand Down Expand Up @@ -164,5 +164,11 @@
<Compile Update="TranslationEngine\Compiler.Expression.By.cs">
<DependentUpon>Compiler.cs</DependentUpon>
</Compile>
<Compile Update="TranslationEngine\Compiler.Statement.Throw.cs">
<DependentUpon>Compiler.cs</DependentUpon>
</Compile>
<Compile Update="TranslationEngine\Compiler.Statement.Try.cs">
<DependentUpon>Compiler.cs</DependentUpon>
</Compile>
</ItemGroup>
</Project>
51 changes: 51 additions & 0 deletions VirtualMachine/Ceres/ExecutionEngine/Concurrency/Fiber.cs
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,57 @@ public void SetOnNativeFunctionInvoke(NativeFunctionInvokeHandler? handler)
OnNativeFunctionInvoke = handler;
}

public DynamicValue ThrowFromNative(DynamicValue value)
{
lock (_callStack)
lock (_evaluationStack)
{
var callStackCopy = _callStack.ToArray();

var frame = _callStack.Peek();
if (frame is NativeStackFrame nsf)
{
nsf.HasThrown = true;
_callStack.Pop();
}

_evaluationStack.Push(value);
UnwindTryHandle(callStackCopy);
}

return DynamicValue.Nil;
}

internal void UnwindTryHandle(StackFrame[] callStackCopy)
{
lock (_callStack)
{
var scriptFrame = _callStack.Peek().As<ScriptStackFrame>();

while (_callStack.Count > 1 && !scriptFrame.IsProtectedState)
{
_callStack.Pop();
scriptFrame = _callStack.Peek().As<ScriptStackFrame>();
}

if (scriptFrame.IsProtectedState)
{
var info = scriptFrame.BlockProtectorStack.Peek();
scriptFrame.JumpAbsolute(info.HandlerAddress);
}
else
{
var exceptionObject = PopValue();

throw new UserUnhandledExceptionException(
"A user-unhandled exception has been thrown.",
exceptionObject,
callStackCopy
);
}
}
}

internal void RemoveFinishedAwaitees()
{
_waitingFor.RemoveWhere(x => x.State == FiberState.Finished);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Ceres.ExecutionEngine.Diagnostics
{
public class BlockProtectionInfo
{
public int StartAddress { get; internal set; }
public int Length { get; internal set; }
public int HandlerAddress { get; internal set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,16 @@ private static ChunkAttribute ReadAttribute(BinaryReader br)
return attribute;
}

private static BlockProtectionInfo ReadProtectedBlock(BinaryReader br)
{
return new BlockProtectionInfo
{
StartAddress = br.ReadInt32(),
Length = br.ReadInt32(),
HandlerAddress = br.ReadInt32()
};
}

private static string ReadName(BinaryReader br)
{
return br.ReadString();
Expand Down Expand Up @@ -184,6 +194,16 @@ public static Chunk Deserialize(Stream stream, out byte version, out long timest
}
}

if (flags.HasFlag(ChunkFlags.HasProtectedBlocks))
{
var blockCount = br.ReadInt32();

for (var i = 0; i < blockCount; i++)
{
chunk._protectedBlocks.Add(ReadProtectedBlock(br));
}
}

if (flags.HasFlag(ChunkFlags.HasDebugInfo))
{
chunk.DebugDatabase.Deserialize(br);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,21 @@ private void WriteChunkAttributes(BinaryWriter bw)
}
}

private void WriteProtectionInformation(BinaryWriter bw)
{
if (_chunk.Flags.HasFlag(ChunkFlags.HasProtectedBlocks))
{
bw.Write(_chunk.ProtectedBlocks.Count);

foreach (var block in _chunk.ProtectedBlocks)
{
bw.Write(block.StartAddress);
bw.Write(block.Length);
bw.Write(block.HandlerAddress);
}
}
}

private void WriteDebugDatabase(BinaryWriter bw)
{
if (_chunk.Flags.HasFlag(ChunkFlags.HasDebugInfo))
Expand Down Expand Up @@ -214,6 +229,7 @@ public void Write(Stream stream)
WriteLocalInfo(bw);
WriteLabelInfo(bw);
WriteChunkAttributes(bw);
WriteProtectionInformation(bw);
WriteDebugDatabase(bw);
WriteStringPool(bw);
WriteCodeArea(bw);
Expand Down
Loading
Loading