Skip to content

Commit

Permalink
Add native-specific type checks.
Browse files Browse the repository at this point in the history
  • Loading branch information
vddCore committed Nov 5, 2024
1 parent 153ab96 commit 5deead4
Show file tree
Hide file tree
Showing 13 changed files with 135 additions and 10 deletions.
8 changes: 6 additions & 2 deletions Core/EVIL.Grammar/AST/Expressions/IsExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@ public sealed class IsExpression : Expression
{
public Expression Target { get; }
public TypeCodeConstant Type { get; }
public StringConstant? ManagedTypeName { get; }
public bool Invert { get; }

public bool IsManagedTypeCheck => ManagedTypeName is not null;

public IsExpression(Expression target, TypeCodeConstant type, bool invert)
public IsExpression(Expression target, TypeCodeConstant type, StringConstant? managedTypeName, bool invert)
{
Target = target;
Type = type;
ManagedTypeName = managedTypeName;
Invert = invert;

Reparent(Target, Type);
Reparent(Target, Type, ManagedTypeName);
}
}
5 changes: 4 additions & 1 deletion Core/EVIL.Grammar/AST/Expressions/TypeOfExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
public sealed class TypeOfExpression : Expression
{
public Expression Target { get; }
public bool IsNative { get; }

public TypeOfExpression(Expression target)
public TypeOfExpression(Expression target, bool isNative)
{
Target = target;
IsNative = isNative;

Reparent(Target);
}
}
2 changes: 1 addition & 1 deletion Core/EVIL.Grammar/EVIL.Grammar.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>

<Version>4.5.0</Version>
<Version>5.0.0</Version>

<IsPackable>false</IsPackable>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace EVIL.Grammar.Parsing;

using System.Linq;
using EVIL.CommonTypes.TypeSystem;
using EVIL.Grammar.AST.Base;
using EVIL.Grammar.AST.Constants;
using EVIL.Grammar.AST.Expressions;
Expand Down Expand Up @@ -95,9 +96,29 @@ private Expression RelationalExpression()
);
}

node = new IsExpression(node, typeCodeConstant, invert)
StringConstant? nativeTypeConstant = null;
if (typeCodeConstant.Value == DynamicValueType.NativeObject)
{
if (CurrentToken.Type == TokenType.PlainString || CurrentToken.Type == TokenType.InterpolatedString)
{
var constant = ConstantExpression();

if (constant is not StringConstant stringConstant)
{
throw new ParserException(
"Expected a string or an interpolated string.",
(constant.Line, constant.Column)
);
}

nativeTypeConstant = stringConstant;
}
}

node = new IsExpression(node, typeCodeConstant, nativeTypeConstant, invert)
{ Line = line, Column = col };
}

token = CurrentToken;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,19 @@ private TypeOfExpression TypeOfExpression()
{
var (line, col) = Match(Token.TypeOf);

var isNative = false;

if (CurrentToken.Type == TokenType.LogicalNot)
{
Match(Token.LogicalNot);
isNative = true;
}

Match(Token.LParenthesis);
var target = AssignmentExpression();
Match(Token.RParenthesis);

return new TypeOfExpression(target)
return new TypeOfExpression(target, isNative)
{ Line = line, Column = col };
}

Expand Down
2 changes: 1 addition & 1 deletion VirtualMachine/EVIL.Ceres/EVIL.Ceres.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>

<Version>7.9.0</Version>
<Version>8.0.0</Version>

<IsPackable>false</IsPackable>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public enum OpCode : byte
TONUMBER,
TOSTRING,
TYPE,
NTYPE,
LNOT,
LAND,
LOR,
Expand Down
16 changes: 16 additions & 0 deletions VirtualMachine/EVIL.Ceres/ExecutionEngine/ExecutionUnit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,22 @@ public void Step()
break;
}

case OpCode.NTYPE:
{
a = PopValue();

if (a.Type != DynamicValueType.NativeObject)
{
PushValue(DynamicValue.Nil);
}
else
{
PushValue(a.NativeObject!.GetType().FullName!);
}

break;
}

case OpCode.FJMP:
{
var labelId = frame.FetchInt32();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,18 @@ public partial class Compiler
public override void Visit(IsExpression isExpression)
{
Visit(isExpression.Target);
Chunk.CodeGenerator.Emit(OpCode.TYPE);
Chunk.CodeGenerator.Emit(OpCode.LDTYPE, (int)isExpression.Type.Value);

if (isExpression.IsManagedTypeCheck)
{
Chunk.CodeGenerator.Emit(OpCode.NTYPE);
Visit(isExpression.ManagedTypeName!);
}
else
{
Chunk.CodeGenerator.Emit(OpCode.TYPE);
Chunk.CodeGenerator.Emit(OpCode.LDTYPE, (int)isExpression.Type.Value);
}

Chunk.CodeGenerator.Emit(isExpression.Invert ? OpCode.CNE : OpCode.CEQ);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ public partial class Compiler
public override void Visit(TypeOfExpression typeOfExpression)
{
Visit(typeOfExpression.Target);
Chunk.CodeGenerator.Emit(OpCode.TYPE);

if (typeOfExpression.IsNative)
{
Chunk.CodeGenerator.Emit(OpCode.NTYPE);
}
else
{
Chunk.CodeGenerator.Emit(OpCode.TYPE);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace EVIL.Ceres.LanguageTests;

public class DummyNativeClass
{
/* Used for testing, see TestRunner.Execute for details. */
}
6 changes: 6 additions & 0 deletions VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,12 @@ private async Task<int> Execute(TestSet testSet)

VM.Global.Set("__native_object", DynamicValue.FromObject(new object()));
VM.Global.Set("__tricky", new TrickyTable());
VM.Global.Set("__new_dummy_object", new(
(_, _) => DynamicValue.FromObject(new DummyNativeClass()))
);
VM.Global.Set("__new_dummy_object_2", new(
(_, _) => DynamicValue.FromObject(new DummyNativeClass()))
);

VM.Global.Set("__throw_test", new((fiber, args) =>
{
Expand Down
42 changes: 42 additions & 0 deletions VirtualMachine/Tests/EVIL.Ceres.LanguageTests/tests/011_type.vil
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,46 @@ fn value_is_not_number {
fn value_is_not_string {
val testval = 21.37;
assert(testval !is String);
}

#[test]
fn value_is_native_type_via_plain_string {
val testval = __new_dummy_object();
assert(testval is NativeObject 'EVIL.Ceres.LanguageTests.DummyNativeClass');
}

#[test]
fn value_is_not_native_type_via_plain_string {
val testval = __new_dummy_object();
assert(testval !is NativeObject 'EVIL.Ceres.LanguageTests.DummyNativeClass2');
}

#[test]
fn value_is_native_type_via_interpolated_string {
val testval = __new_dummy_object();
val injected_string = "EVIL.Ceres.LanguageTests.DummyNativeClass";

assert(testval is NativeObject "$injected_string");
}

#[test]
fn value_is_native_type_via_interpolated_string {
val testval = __new_dummy_object();
val injected_string = "EVIL.Ceres.LanguageTests.DummyNativeClass2";

assert(testval !is NativeObject "$injected_string");
}

#[test]
fn value_native_type_get_when_native_object() {
val testval = __new_dummy_object();
val type = typeof!(testval);

assert.equal(type, "EVIL.Ceres.LanguageTests.DummyNativeClass");
}

#[test]
fn value_native_type_get_when_not_native_object() {
val type = typeof!(21.37);
assert.equal(type, nil);
}

0 comments on commit 5deead4

Please sign in to comment.