diff --git a/Core/EVIL.CommonTypes/TypeSystem/DynamicValueType.cs b/Core/EVIL.CommonTypes/TypeSystem/DynamicValueType.cs index 87f26a07..8627da93 100644 --- a/Core/EVIL.CommonTypes/TypeSystem/DynamicValueType.cs +++ b/Core/EVIL.CommonTypes/TypeSystem/DynamicValueType.cs @@ -1,18 +1,17 @@ -namespace EVIL.CommonTypes.TypeSystem +namespace EVIL.CommonTypes.TypeSystem; + +public enum DynamicValueType { - public enum DynamicValueType - { - Nil, - Number, - String, - Boolean, - Table, - Array, - Fiber, - Chunk, - Error, - TypeCode, - NativeFunction, - NativeObject - } + Nil, + Number, + String, + Boolean, + Table, + Array, + Fiber, + Chunk, + Error, + TypeCode, + NativeFunction, + NativeObject } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Base/AstNode.cs b/Core/EVIL.Grammar/AST/Base/AstNode.cs index ffdd0128..6d8bf201 100644 --- a/Core/EVIL.Grammar/AST/Base/AstNode.cs +++ b/Core/EVIL.Grammar/AST/Base/AstNode.cs @@ -1,38 +1,37 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.AST.Base; + +using System.Collections.Generic; using System.Linq; -namespace EVIL.Grammar.AST.Base +public abstract class AstNode { - public abstract class AstNode - { - public int Line { get; set; } - public int Column { get; set; } + public int Line { get; set; } + public int Column { get; set; } - public AstNode? Parent { get; set; } + public AstNode? Parent { get; set; } - public bool IsConstant => this is ConstantExpression; + public bool IsConstant => this is ConstantExpression; - internal T CopyMetadata(AstNode from) where T : AstNode - { - Line = from.Line; - Column = from.Column; - Parent = from.Parent; + internal T CopyMetadata(AstNode from) where T : AstNode + { + Line = from.Line; + Column = from.Column; + Parent = from.Parent; - return (this as T)!; - } + return (this as T)!; + } - protected void Reparent(params AstNode?[] nodes) + protected void Reparent(params AstNode?[] nodes) + { + for (var i = 0; i < nodes.Length; i++) { - for (var i = 0; i < nodes.Length; i++) + if (nodes[i] != null) { - if (nodes[i] != null) - { - nodes[i]!.Parent = this; - } + nodes[i]!.Parent = this; } } - - protected void Reparent(IEnumerable nodes) - => Reparent(nodes.ToArray()); } + + protected void Reparent(IEnumerable nodes) + => Reparent(nodes.ToArray()); } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Base/ConstantExpression.cs b/Core/EVIL.Grammar/AST/Base/ConstantExpression.cs index e1548f68..f32b82be 100644 --- a/Core/EVIL.Grammar/AST/Base/ConstantExpression.cs +++ b/Core/EVIL.Grammar/AST/Base/ConstantExpression.cs @@ -1,6 +1,5 @@ -namespace EVIL.Grammar.AST.Base +namespace EVIL.Grammar.AST.Base; + +public abstract class ConstantExpression : Expression { - public abstract class ConstantExpression : Expression - { - } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Base/Expression.cs b/Core/EVIL.Grammar/AST/Base/Expression.cs index 12a68336..118adc18 100644 --- a/Core/EVIL.Grammar/AST/Base/Expression.cs +++ b/Core/EVIL.Grammar/AST/Base/Expression.cs @@ -1,17 +1,16 @@ +namespace EVIL.Grammar.AST.Base; + using EVIL.Grammar.AST.Expressions; -namespace EVIL.Grammar.AST.Base +public abstract class Expression : AstNode { - public abstract class Expression : AstNode - { - public bool IsValidExpressionStatement - => this is AssignmentExpression - or InvocationExpression - or SelfInvocationExpression - or IncrementationExpression - or DecrementationExpression - or YieldExpression; + public bool IsValidExpressionStatement + => this is AssignmentExpression + or InvocationExpression + or SelfInvocationExpression + or IncrementationExpression + or DecrementationExpression + or YieldExpression; - public virtual Expression Reduce() => this; - } + public virtual Expression Reduce() => this; } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Base/Statement.cs b/Core/EVIL.Grammar/AST/Base/Statement.cs index 1ee0892b..cf5864c5 100644 --- a/Core/EVIL.Grammar/AST/Base/Statement.cs +++ b/Core/EVIL.Grammar/AST/Base/Statement.cs @@ -1,6 +1,5 @@ -namespace EVIL.Grammar.AST.Base +namespace EVIL.Grammar.AST.Base; + +public abstract class Statement : AstNode { - public abstract class Statement : AstNode - { - } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Constants/BooleanConstant.cs b/Core/EVIL.Grammar/AST/Constants/BooleanConstant.cs index c02edfda..f1ab3d4a 100644 --- a/Core/EVIL.Grammar/AST/Constants/BooleanConstant.cs +++ b/Core/EVIL.Grammar/AST/Constants/BooleanConstant.cs @@ -1,14 +1,13 @@ +namespace EVIL.Grammar.AST.Constants; + using EVIL.Grammar.AST.Base; -namespace EVIL.Grammar.AST.Constants +public sealed class BooleanConstant : ConstantExpression { - public sealed class BooleanConstant : ConstantExpression - { - public bool Value { get; } + public bool Value { get; } - public BooleanConstant(bool value) - { - Value = value; - } + public BooleanConstant(bool value) + { + Value = value; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Constants/NilConstant.cs b/Core/EVIL.Grammar/AST/Constants/NilConstant.cs index 2312914b..3a6f5c65 100644 --- a/Core/EVIL.Grammar/AST/Constants/NilConstant.cs +++ b/Core/EVIL.Grammar/AST/Constants/NilConstant.cs @@ -1,8 +1,7 @@ +namespace EVIL.Grammar.AST.Constants; + using EVIL.Grammar.AST.Base; -namespace EVIL.Grammar.AST.Constants +public sealed class NilConstant : ConstantExpression { - public sealed class NilConstant : ConstantExpression - { - } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Constants/NumberConstant.cs b/Core/EVIL.Grammar/AST/Constants/NumberConstant.cs index d5d58a28..5903b43f 100644 --- a/Core/EVIL.Grammar/AST/Constants/NumberConstant.cs +++ b/Core/EVIL.Grammar/AST/Constants/NumberConstant.cs @@ -1,14 +1,13 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Constants; -namespace EVIL.Grammar.AST.Constants +using EVIL.Grammar.AST.Base; + +public sealed class NumberConstant : ConstantExpression { - public sealed class NumberConstant : ConstantExpression - { - public double Value { get; } + public double Value { get; } - public NumberConstant(double value) - { - Value = value; - } + public NumberConstant(double value) + { + Value = value; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Constants/StringConstant.cs b/Core/EVIL.Grammar/AST/Constants/StringConstant.cs index 8648e49c..84e5a59f 100644 --- a/Core/EVIL.Grammar/AST/Constants/StringConstant.cs +++ b/Core/EVIL.Grammar/AST/Constants/StringConstant.cs @@ -1,16 +1,15 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Constants; -namespace EVIL.Grammar.AST.Constants +using EVIL.Grammar.AST.Base; + +public sealed class StringConstant : ConstantExpression { - public sealed class StringConstant : ConstantExpression - { - public string Value { get; } - public bool IsInterpolated { get; } + public string Value { get; } + public bool IsInterpolated { get; } - public StringConstant(string value, bool isInterpolated) - { - Value = value; - IsInterpolated = isInterpolated; - } + public StringConstant(string value, bool isInterpolated) + { + Value = value; + IsInterpolated = isInterpolated; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Constants/TypeCodeConstant.cs b/Core/EVIL.Grammar/AST/Constants/TypeCodeConstant.cs index 2528e1e2..63f7fe87 100644 --- a/Core/EVIL.Grammar/AST/Constants/TypeCodeConstant.cs +++ b/Core/EVIL.Grammar/AST/Constants/TypeCodeConstant.cs @@ -1,15 +1,14 @@ +namespace EVIL.Grammar.AST.Constants; + using EVIL.CommonTypes.TypeSystem; using EVIL.Grammar.AST.Base; -namespace EVIL.Grammar.AST.Constants +public class TypeCodeConstant : ConstantExpression { - public class TypeCodeConstant : ConstantExpression - { - public DynamicValueType Value { get; } + public DynamicValueType Value { get; } - public TypeCodeConstant(DynamicValueType value) - { - Value = value; - } + public TypeCodeConstant(DynamicValueType value) + { + Value = value; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/ArrayExpression.cs b/Core/EVIL.Grammar/AST/Expressions/ArrayExpression.cs index e1eae7e9..82858477 100644 --- a/Core/EVIL.Grammar/AST/Expressions/ArrayExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/ArrayExpression.cs @@ -1,20 +1,19 @@ +namespace EVIL.Grammar.AST.Expressions; + using System.Collections.Generic; using EVIL.Grammar.AST.Base; -namespace EVIL.Grammar.AST.Expressions +public sealed class ArrayExpression : Expression { - public class ArrayExpression : Expression - { - public Expression? SizeExpression { get; } - public List Initializers { get; } + public Expression? SizeExpression { get; } + public List Initializers { get; } - public ArrayExpression(Expression? sizeExpression, List initializers) - { - SizeExpression = sizeExpression; - Initializers = initializers; + public ArrayExpression(Expression? sizeExpression, List initializers) + { + SizeExpression = sizeExpression; + Initializers = initializers; - Reparent(SizeExpression); - Reparent(Initializers); - } + Reparent(SizeExpression); + Reparent(Initializers); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/AssignmentExpression.cs b/Core/EVIL.Grammar/AST/Expressions/AssignmentExpression.cs index ac02d302..300fcb42 100644 --- a/Core/EVIL.Grammar/AST/Expressions/AssignmentExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/AssignmentExpression.cs @@ -1,22 +1,21 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Expressions; -namespace EVIL.Grammar.AST.Expressions +using EVIL.Grammar.AST.Base; + +public sealed class AssignmentExpression : Expression { - public sealed class AssignmentExpression : Expression - { - public Expression Left { get; } - public Expression Right { get; } + public Expression Left { get; } + public Expression Right { get; } - public AssignmentOperationType OperationType { get; } + public AssignmentOperationType OperationType { get; } - public AssignmentExpression(Expression left, Expression right, AssignmentOperationType operationType) - { - Left = left; - Right = right; + public AssignmentExpression(Expression left, Expression right, AssignmentOperationType operationType) + { + Left = left; + Right = right; - OperationType = operationType; + OperationType = operationType; - Reparent(Left, Right); - } + Reparent(Left, Right); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/BinaryExpression.cs b/Core/EVIL.Grammar/AST/Expressions/BinaryExpression.cs index bd1e0321..648f7c7e 100644 --- a/Core/EVIL.Grammar/AST/Expressions/BinaryExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/BinaryExpression.cs @@ -1,157 +1,156 @@ -using System; +namespace EVIL.Grammar.AST.Expressions; + +using System; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Constants; -namespace EVIL.Grammar.AST.Expressions +public sealed class BinaryExpression : Expression { - public sealed class BinaryExpression : Expression - { - public Expression Left { get; } - public Expression Right { get; } + public Expression Left { get; } + public Expression Right { get; } - public BinaryOperationType Type { get; } + public BinaryOperationType Type { get; } - public BinaryExpression(Expression left, Expression right, BinaryOperationType type) - { - Left = left; - Right = right; + public BinaryExpression(Expression left, Expression right, BinaryOperationType type) + { + Left = left; + Right = right; - Type = type; + Type = type; - Reparent(Left, Right); - } + Reparent(Left, Right); + } - public override Expression Reduce() - { - Expression ret = this; + public override Expression Reduce() + { + Expression ret = this; - var left = Left.Reduce(); - var right = Right.Reduce(); + var left = Left.Reduce(); + var right = Right.Reduce(); - if (left is NumberConstant lnc) + if (left is NumberConstant lnc) + { + if (right is NumberConstant rnc) { - if (right is NumberConstant rnc) + switch (Type) { - switch (Type) - { - case BinaryOperationType.Divide when rnc.Value != 0: - return new NumberConstant(lnc.Value / rnc.Value) - .CopyMetadata(this); + case BinaryOperationType.Divide when rnc.Value != 0: + return new NumberConstant(lnc.Value / rnc.Value) + .CopyMetadata(this); - case BinaryOperationType.Modulo when rnc.Value != 0: - return new NumberConstant(lnc.Value - rnc.Value * Math.Floor(lnc.Value / rnc.Value)) - .CopyMetadata(this); + case BinaryOperationType.Modulo when rnc.Value != 0: + return new NumberConstant(lnc.Value - rnc.Value * Math.Floor(lnc.Value / rnc.Value)) + .CopyMetadata(this); - case BinaryOperationType.Equal: - return new NumberConstant(lnc.Value == rnc.Value ? 1 : 0) - .CopyMetadata(this); + case BinaryOperationType.Equal: + return new NumberConstant(lnc.Value == rnc.Value ? 1 : 0) + .CopyMetadata(this); - case BinaryOperationType.Greater: - return new NumberConstant(lnc.Value >= rnc.Value ? 1 : 0) - .CopyMetadata(this); + case BinaryOperationType.Greater: + return new NumberConstant(lnc.Value >= rnc.Value ? 1 : 0) + .CopyMetadata(this); - case BinaryOperationType.Less: - return new NumberConstant(lnc.Value < rnc.Value ? 1 : 0) - .CopyMetadata(this); + case BinaryOperationType.Less: + return new NumberConstant(lnc.Value < rnc.Value ? 1 : 0) + .CopyMetadata(this); - case BinaryOperationType.Subtract: - return new NumberConstant(lnc.Value - rnc.Value) - .CopyMetadata(this); + case BinaryOperationType.Subtract: + return new NumberConstant(lnc.Value - rnc.Value) + .CopyMetadata(this); - case BinaryOperationType.Multiply: - return new NumberConstant(lnc.Value * rnc.Value) - .CopyMetadata(this); + case BinaryOperationType.Multiply: + return new NumberConstant(lnc.Value * rnc.Value) + .CopyMetadata(this); - case BinaryOperationType.Add: - return new NumberConstant(lnc.Value + rnc.Value) - .CopyMetadata(this); + case BinaryOperationType.Add: + return new NumberConstant(lnc.Value + rnc.Value) + .CopyMetadata(this); - case BinaryOperationType.BitwiseAnd: - return new NumberConstant((long)lnc.Value & (long)rnc.Value) - .CopyMetadata(this); + case BinaryOperationType.BitwiseAnd: + return new NumberConstant((long)lnc.Value & (long)rnc.Value) + .CopyMetadata(this); - case BinaryOperationType.BitwiseOr: - return new NumberConstant((long)lnc.Value | (long)rnc.Value) - .CopyMetadata(this); + case BinaryOperationType.BitwiseOr: + return new NumberConstant((long)lnc.Value | (long)rnc.Value) + .CopyMetadata(this); - case BinaryOperationType.BitwiseXor: - return new NumberConstant((long)lnc.Value ^ (long)rnc.Value) - .CopyMetadata(this); + case BinaryOperationType.BitwiseXor: + return new NumberConstant((long)lnc.Value ^ (long)rnc.Value) + .CopyMetadata(this); - case BinaryOperationType.LogicalAnd: - return new NumberConstant(lnc.Value != 0 && rnc.Value != 0 ? 1 : 0) - .CopyMetadata(this); + case BinaryOperationType.LogicalAnd: + return new NumberConstant(lnc.Value != 0 && rnc.Value != 0 ? 1 : 0) + .CopyMetadata(this); - case BinaryOperationType.LogicalOr: - return new NumberConstant(lnc.Value != 0 || rnc.Value != 0 ? 1 : 0) - .CopyMetadata(this); + case BinaryOperationType.LogicalOr: + return new NumberConstant(lnc.Value != 0 || rnc.Value != 0 ? 1 : 0) + .CopyMetadata(this); - case BinaryOperationType.NotEqual: - return new NumberConstant(lnc.Value != rnc.Value ? 1 : 0) - .CopyMetadata(this); + case BinaryOperationType.NotEqual: + return new NumberConstant(lnc.Value != rnc.Value ? 1 : 0) + .CopyMetadata(this); - case BinaryOperationType.ShiftLeft: - return new NumberConstant((long)lnc.Value << (int)rnc.Value) - .CopyMetadata(this); + case BinaryOperationType.ShiftLeft: + return new NumberConstant((long)lnc.Value << (int)rnc.Value) + .CopyMetadata(this); - case BinaryOperationType.ShiftRight: - return new NumberConstant((long)lnc.Value >> (int)rnc.Value) - .CopyMetadata(this); + case BinaryOperationType.ShiftRight: + return new NumberConstant((long)lnc.Value >> (int)rnc.Value) + .CopyMetadata(this); - case BinaryOperationType.GreaterOrEqual: - return new NumberConstant(lnc.Value >= rnc.Value ? 1 : 0) - .CopyMetadata(this); + case BinaryOperationType.GreaterOrEqual: + return new NumberConstant(lnc.Value >= rnc.Value ? 1 : 0) + .CopyMetadata(this); - case BinaryOperationType.LessOrEqual: - return new NumberConstant(lnc.Value <= rnc.Value ? 1 : 0) - .CopyMetadata(this); - } + case BinaryOperationType.LessOrEqual: + return new NumberConstant(lnc.Value <= rnc.Value ? 1 : 0) + .CopyMetadata(this); } } - else if (left is StringConstant lsc) + } + else if (left is StringConstant lsc) + { + if (right is StringConstant rsc) { - if (right is StringConstant rsc) + if (Type == BinaryOperationType.Add) { - if (Type == BinaryOperationType.Add) - { - return new StringConstant(lsc.Value + rsc.Value, lsc.IsInterpolated || rsc.IsInterpolated) - .CopyMetadata(this); - } + return new StringConstant(lsc.Value + rsc.Value, lsc.IsInterpolated || rsc.IsInterpolated) + .CopyMetadata(this); } - else if (right is NumberConstant rnc) + } + else if (right is NumberConstant rnc) + { + if (Type == BinaryOperationType.ShiftLeft) { - if (Type == BinaryOperationType.ShiftLeft) - { - var str = lsc.Value; - var amount = (int)rnc.Value; - - if (amount >= str.Length) - { - return new StringConstant(string.Empty, false) - .CopyMetadata(this); - } + var str = lsc.Value; + var amount = (int)rnc.Value; - return new StringConstant(str.Substring(amount), false) + if (amount >= str.Length) + { + return new StringConstant(string.Empty, false) .CopyMetadata(this); } - else if (Type == BinaryOperationType.ShiftRight) - { - var str = lsc.Value; - var amount = str.Length - (int)rnc.Value; - if (amount <= 0) - { - return new StringConstant(string.Empty, false) - .CopyMetadata(this); - } + return new StringConstant(str.Substring(amount), false) + .CopyMetadata(this); + } + else if (Type == BinaryOperationType.ShiftRight) + { + var str = lsc.Value; + var amount = str.Length - (int)rnc.Value; - return new StringConstant(str.Substring(0, amount), false) + if (amount <= 0) + { + return new StringConstant(string.Empty, false) .CopyMetadata(this); } + + return new StringConstant(str.Substring(0, amount), false) + .CopyMetadata(this); } } - - return ret; } + + return ret; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/ByExpression.cs b/Core/EVIL.Grammar/AST/Expressions/ByExpression.cs index 348079b7..97c1bb8c 100644 --- a/Core/EVIL.Grammar/AST/Expressions/ByExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/ByExpression.cs @@ -1,24 +1,23 @@ +namespace EVIL.Grammar.AST.Expressions; + using System.Collections.Generic; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Miscellaneous; -namespace EVIL.Grammar.AST.Expressions +public sealed class ByExpression : Expression { - public class ByExpression : Expression - { - public Expression Qualifier { get; } - public List Arms { get; } - public AstNode? ElseArm { get; } + public Expression Qualifier { get; } + public List Arms { get; } + public AstNode? ElseArm { get; } - public ByExpression(Expression qualifier, List arms, AstNode? elseArm) - { - Qualifier = qualifier; - Arms = arms; - ElseArm = elseArm; + public ByExpression(Expression qualifier, List arms, AstNode? elseArm) + { + Qualifier = qualifier; + Arms = arms; + ElseArm = elseArm; - Reparent(Qualifier); - Reparent(Arms); - Reparent(ElseArm); - } + Reparent(Qualifier); + Reparent(Arms); + Reparent(ElseArm); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/CoalescingExpression.cs b/Core/EVIL.Grammar/AST/Expressions/CoalescingExpression.cs index 93543d89..094fd3d3 100644 --- a/Core/EVIL.Grammar/AST/Expressions/CoalescingExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/CoalescingExpression.cs @@ -1,18 +1,17 @@ +namespace EVIL.Grammar.AST.Expressions; + using EVIL.Grammar.AST.Base; -namespace EVIL.Grammar.AST.Expressions +public sealed class CoalescingExpression : Expression { - public class CoalescingExpression : Expression - { - public Expression Left { get; } - public Expression Right { get; } + public Expression Left { get; } + public Expression Right { get; } - public CoalescingExpression(Expression left, Expression right) - { - Left = left; - Right = right; + public CoalescingExpression(Expression left, Expression right) + { + Left = left; + Right = right; - Reparent(left, right); - } + Reparent(left, right); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/ConditionalExpression.cs b/Core/EVIL.Grammar/AST/Expressions/ConditionalExpression.cs index 6af78644..ba9e5598 100644 --- a/Core/EVIL.Grammar/AST/Expressions/ConditionalExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/ConditionalExpression.cs @@ -1,22 +1,21 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Expressions; -namespace EVIL.Grammar.AST.Expressions +using EVIL.Grammar.AST.Base; + +public sealed class ConditionalExpression : Expression { - public sealed class ConditionalExpression : Expression - { - public Expression Condition { get; } + public Expression Condition { get; } - public Expression TrueExpression { get; } - public Expression FalseExpression { get; } + public Expression TrueExpression { get; } + public Expression FalseExpression { get; } - public ConditionalExpression(Expression condition, Expression trueExpression, Expression falseExpression) - { - Condition = condition; + public ConditionalExpression(Expression condition, Expression trueExpression, Expression falseExpression) + { + Condition = condition; - TrueExpression = trueExpression; - FalseExpression = falseExpression; + TrueExpression = trueExpression; + FalseExpression = falseExpression; - Reparent(Condition, TrueExpression, FalseExpression); - } + Reparent(Condition, TrueExpression, FalseExpression); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/DecrementationExpression.cs b/Core/EVIL.Grammar/AST/Expressions/DecrementationExpression.cs index 71b6bdd6..191d80fc 100644 --- a/Core/EVIL.Grammar/AST/Expressions/DecrementationExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/DecrementationExpression.cs @@ -1,18 +1,17 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Expressions; -namespace EVIL.Grammar.AST.Expressions +using EVIL.Grammar.AST.Base; + +public sealed class DecrementationExpression : Expression { - public sealed class DecrementationExpression : Expression - { - public Expression Target { get; } - public bool IsPrefix { get; } + public Expression Target { get; } + public bool IsPrefix { get; } - public DecrementationExpression(Expression target, bool isPrefix) - { - target.Parent = this; + public DecrementationExpression(Expression target, bool isPrefix) + { + target.Parent = this; - Target = target; - IsPrefix = isPrefix; - } + Target = target; + IsPrefix = isPrefix; } -} +} \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/ErrorExpression.cs b/Core/EVIL.Grammar/AST/Expressions/ErrorExpression.cs index f1bcf58a..94df5400 100644 --- a/Core/EVIL.Grammar/AST/Expressions/ErrorExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/ErrorExpression.cs @@ -1,20 +1,19 @@ +namespace EVIL.Grammar.AST.Expressions; + using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Constants; -namespace EVIL.Grammar.AST.Expressions +public sealed class ErrorExpression : Expression { - public class ErrorExpression : Expression - { - public StringConstant? ImplicitMessageConstant { get; } - public TableExpression? UserDataTable { get; } + public StringConstant? ImplicitMessageConstant { get; } + public TableExpression? UserDataTable { get; } - public ErrorExpression(StringConstant? implicitMessageConstant, TableExpression? userDataTable) - { - ImplicitMessageConstant = implicitMessageConstant; - UserDataTable = userDataTable; + public ErrorExpression(StringConstant? implicitMessageConstant, TableExpression? userDataTable) + { + ImplicitMessageConstant = implicitMessageConstant; + UserDataTable = userDataTable; - Reparent(ImplicitMessageConstant); - Reparent(UserDataTable); - } + Reparent(ImplicitMessageConstant); + Reparent(UserDataTable); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/ExtraArgumentsExpression.cs b/Core/EVIL.Grammar/AST/Expressions/ExtraArgumentsExpression.cs index 566616dd..af0e5b6c 100644 --- a/Core/EVIL.Grammar/AST/Expressions/ExtraArgumentsExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/ExtraArgumentsExpression.cs @@ -1,14 +1,13 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Expressions; -namespace EVIL.Grammar.AST.Expressions +using EVIL.Grammar.AST.Base; + +public sealed class ExtraArgumentsExpression : Expression { - public class ExtraArgumentsExpression : Expression - { - public bool UnwrapOnStack { get; } + public bool UnwrapOnStack { get; } - public ExtraArgumentsExpression(bool unwrapOnStack) - { - UnwrapOnStack = unwrapOnStack; - } + public ExtraArgumentsExpression(bool unwrapOnStack) + { + UnwrapOnStack = unwrapOnStack; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/FnExpression.cs b/Core/EVIL.Grammar/AST/Expressions/FnExpression.cs index 7c165939..4b0cc7cd 100644 --- a/Core/EVIL.Grammar/AST/Expressions/FnExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/FnExpression.cs @@ -1,22 +1,21 @@ +namespace EVIL.Grammar.AST.Expressions; + using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Miscellaneous; -namespace EVIL.Grammar.AST.Expressions +public sealed class FnExpression : Expression { - public sealed class FnExpression : Expression - { - public ParameterList? ParameterList { get; } - public Statement Statement { get; } + public ParameterList? ParameterList { get; } + public Statement Statement { get; } - public FnExpression( - ParameterList? parameterList, - Statement statement) - { - ParameterList = parameterList; - Statement = statement; + public FnExpression( + ParameterList? parameterList, + Statement statement) + { + ParameterList = parameterList; + Statement = statement; - Reparent(ParameterList); - Reparent(Statement); - } + Reparent(ParameterList); + Reparent(Statement); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/IncrementationExpression.cs b/Core/EVIL.Grammar/AST/Expressions/IncrementationExpression.cs index 914843b3..dd5aecf2 100644 --- a/Core/EVIL.Grammar/AST/Expressions/IncrementationExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/IncrementationExpression.cs @@ -1,18 +1,17 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Expressions; -namespace EVIL.Grammar.AST.Expressions +using EVIL.Grammar.AST.Base; + +public sealed class IncrementationExpression : Expression { - public sealed class IncrementationExpression : Expression - { - public Expression Target { get; } - public bool IsPrefix { get; } + public Expression Target { get; } + public bool IsPrefix { get; } - public IncrementationExpression(Expression target, bool isPrefix) - { - Target = target; - IsPrefix = isPrefix; + public IncrementationExpression(Expression target, bool isPrefix) + { + Target = target; + IsPrefix = isPrefix; - Reparent(Target); - } + Reparent(Target); } -} +} \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/IndexerExpression.cs b/Core/EVIL.Grammar/AST/Expressions/IndexerExpression.cs index 47926d13..f9fedcb0 100644 --- a/Core/EVIL.Grammar/AST/Expressions/IndexerExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/IndexerExpression.cs @@ -1,58 +1,56 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.AST.Expressions; + +using System.Collections.Generic; using System.Globalization; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Constants; -namespace EVIL.Grammar.AST.Expressions +public sealed class IndexerExpression : Expression { - public sealed class IndexerExpression : Expression - { - public Expression Indexable { get; } - public Expression KeyExpression { get; } + public Expression Indexable { get; } + public Expression KeyExpression { get; } - public bool WillBeAssigned { get; } + public bool WillBeAssigned { get; } - public IndexerExpression(Expression indexable, Expression keyExpression, bool willBeAssigned) - { - Indexable = indexable; - KeyExpression = keyExpression; + public IndexerExpression(Expression indexable, Expression keyExpression, bool willBeAssigned) + { + Indexable = indexable; + KeyExpression = keyExpression; - WillBeAssigned = willBeAssigned; + WillBeAssigned = willBeAssigned; - Reparent(Indexable, KeyExpression); - } + Reparent(Indexable, KeyExpression); + } - public string BuildChainStringRepresentation() - { - var stack = new Stack(); - var current = Indexable; + public string BuildChainStringRepresentation() + { + var stack = new Stack(); + var current = Indexable; - stack.Push(GetKeyStringRepresentation()); + stack.Push(GetKeyStringRepresentation()); - while (current is IndexerExpression indexerExpression) - { - stack.Push(indexerExpression.GetKeyStringRepresentation()); - current = indexerExpression.Indexable; - } - - if (current is SymbolReferenceExpression symbolReferenceExpression) - { - stack.Push(symbolReferenceExpression.Identifier); - } - - return string.Join('.', stack); + while (current is IndexerExpression indexerExpression) + { + stack.Push(indexerExpression.GetKeyStringRepresentation()); + current = indexerExpression.Indexable; } - public string GetKeyStringRepresentation() + if (current is SymbolReferenceExpression symbolReferenceExpression) { - return KeyExpression switch - { - NumberConstant numberConstant => numberConstant.Value.ToString(CultureInfo.InvariantCulture), - StringConstant stringConstant => stringConstant.Value, - SymbolReferenceExpression symbolReferenceExpression => symbolReferenceExpression.Identifier, - _ => "???" - }; + stack.Push(symbolReferenceExpression.Identifier); } + + return string.Join('.', stack); } -} + public string GetKeyStringRepresentation() + { + return KeyExpression switch + { + NumberConstant numberConstant => numberConstant.Value.ToString(CultureInfo.InvariantCulture), + StringConstant stringConstant => stringConstant.Value, + SymbolReferenceExpression symbolReferenceExpression => symbolReferenceExpression.Identifier, + _ => "???" + }; + } +} \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/InvocationExpression.cs b/Core/EVIL.Grammar/AST/Expressions/InvocationExpression.cs index d4dccefc..1d539cb6 100644 --- a/Core/EVIL.Grammar/AST/Expressions/InvocationExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/InvocationExpression.cs @@ -1,20 +1,19 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Expressions; + +using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Miscellaneous; -namespace EVIL.Grammar.AST.Expressions +public sealed class InvocationExpression : Expression { - public sealed class InvocationExpression : Expression - { - public Expression Callee { get; } - public ArgumentList ArgumentList { get; } + public Expression Callee { get; } + public ArgumentList ArgumentList { get; } - public InvocationExpression(Expression callee, ArgumentList argumentList) - { - Callee = callee; - ArgumentList = argumentList; + public InvocationExpression(Expression callee, ArgumentList argumentList) + { + Callee = callee; + ArgumentList = argumentList; - Reparent(Callee); - Reparent(ArgumentList); - } + Reparent(Callee); + Reparent(ArgumentList); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/IsExpression.cs b/Core/EVIL.Grammar/AST/Expressions/IsExpression.cs index 019aeb82..dbba278c 100644 --- a/Core/EVIL.Grammar/AST/Expressions/IsExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/IsExpression.cs @@ -1,21 +1,20 @@ +namespace EVIL.Grammar.AST.Expressions; + using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Constants; -namespace EVIL.Grammar.AST.Expressions +public sealed class IsExpression : Expression { - public class IsExpression : Expression - { - public Expression Target { get; } - public TypeCodeConstant Type { get; } - public bool Invert { get; } + public Expression Target { get; } + public TypeCodeConstant Type { get; } + public bool Invert { get; } - public IsExpression(Expression target, TypeCodeConstant type, bool invert) - { - Target = target; - Type = type; - Invert = invert; + public IsExpression(Expression target, TypeCodeConstant type, bool invert) + { + Target = target; + Type = type; + Invert = invert; - Reparent(Target, Type); - } + Reparent(Target, Type); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/KeyValuePairExpression.cs b/Core/EVIL.Grammar/AST/Expressions/KeyValuePairExpression.cs index 8bcb0cff..bdb67fae 100644 --- a/Core/EVIL.Grammar/AST/Expressions/KeyValuePairExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/KeyValuePairExpression.cs @@ -1,18 +1,17 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Expressions; -namespace EVIL.Grammar.AST.Expressions +using EVIL.Grammar.AST.Base; + +public sealed class KeyValuePairExpression : Expression { - public sealed class KeyValuePairExpression : Expression - { - public Expression KeyNode { get; } - public Expression ValueNode { get; } + public Expression KeyNode { get; } + public Expression ValueNode { get; } - public KeyValuePairExpression(Expression keyNode, Expression valueNode) - { - KeyNode = keyNode; - ValueNode = valueNode; + public KeyValuePairExpression(Expression keyNode, Expression valueNode) + { + KeyNode = keyNode; + ValueNode = valueNode; - Reparent(KeyNode, ValueNode); - } + Reparent(KeyNode, ValueNode); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/SelfExpression.cs b/Core/EVIL.Grammar/AST/Expressions/SelfExpression.cs index 28e70649..cd443cd4 100644 --- a/Core/EVIL.Grammar/AST/Expressions/SelfExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/SelfExpression.cs @@ -1,8 +1,7 @@ +namespace EVIL.Grammar.AST.Expressions; + using EVIL.Grammar.AST.Base; -namespace EVIL.Grammar.AST.Expressions +public sealed class SelfExpression : Expression { - public class SelfExpression : Expression - { - } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/SelfFnExpression.cs b/Core/EVIL.Grammar/AST/Expressions/SelfFnExpression.cs index d9240755..f62cbb83 100644 --- a/Core/EVIL.Grammar/AST/Expressions/SelfFnExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/SelfFnExpression.cs @@ -1,23 +1,21 @@ +namespace EVIL.Grammar.AST.Expressions; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Miscellaneous; -namespace EVIL.Grammar.AST.Expressions +public sealed class SelfFnExpression : Expression { - public class SelfFnExpression : Expression - { - public ParameterList? ParameterList { get; } - public Statement Statement { get; } + public ParameterList? ParameterList { get; } + public Statement Statement { get; } - public SelfFnExpression( - ParameterList? parameterList, - Statement statement) - { - ParameterList = parameterList; - Statement = statement; + public SelfFnExpression( + ParameterList? parameterList, + Statement statement) + { + ParameterList = parameterList; + Statement = statement; - Reparent(ParameterList); - Reparent(Statement); - } + Reparent(ParameterList); + Reparent(Statement); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/SelfInvocationExpression.cs b/Core/EVIL.Grammar/AST/Expressions/SelfInvocationExpression.cs index e9a91855..01c0cc37 100644 --- a/Core/EVIL.Grammar/AST/Expressions/SelfInvocationExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/SelfInvocationExpression.cs @@ -1,24 +1,23 @@ +namespace EVIL.Grammar.AST.Expressions; + using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Miscellaneous; -namespace EVIL.Grammar.AST.Expressions +public sealed class SelfInvocationExpression : Expression { - public class SelfInvocationExpression : Expression - { - public Expression Indexable { get; } - public IdentifierNode Identifier { get; } - public ArgumentList ArgumentList { get; } + public Expression Indexable { get; } + public IdentifierNode Identifier { get; } + public ArgumentList ArgumentList { get; } - public SelfInvocationExpression( - Expression indexable, - IdentifierNode identifier, - ArgumentList argumentList) - { - Indexable = indexable; - Identifier = identifier; - ArgumentList = argumentList; + public SelfInvocationExpression( + Expression indexable, + IdentifierNode identifier, + ArgumentList argumentList) + { + Indexable = indexable; + Identifier = identifier; + ArgumentList = argumentList; - Reparent(Indexable, Identifier, ArgumentList); - } + Reparent(Indexable, Identifier, ArgumentList); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/SymbolReferenceExpression.cs b/Core/EVIL.Grammar/AST/Expressions/SymbolReferenceExpression.cs index 085ee7dd..5c03d7d2 100644 --- a/Core/EVIL.Grammar/AST/Expressions/SymbolReferenceExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/SymbolReferenceExpression.cs @@ -1,14 +1,13 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Expressions; -namespace EVIL.Grammar.AST.Expressions +using EVIL.Grammar.AST.Base; + +public sealed class SymbolReferenceExpression : Expression { - public sealed class SymbolReferenceExpression : Expression - { - public string Identifier { get; } + public string Identifier { get; } - public SymbolReferenceExpression(string identifier) - { - Identifier = identifier; - } + public SymbolReferenceExpression(string identifier) + { + Identifier = identifier; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/TableExpression.cs b/Core/EVIL.Grammar/AST/Expressions/TableExpression.cs index 2a5050c6..6f3679e3 100644 --- a/Core/EVIL.Grammar/AST/Expressions/TableExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/TableExpression.cs @@ -1,19 +1,18 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.AST.Expressions; + +using System.Collections.Generic; using EVIL.Grammar.AST.Base; -namespace EVIL.Grammar.AST.Expressions +public sealed class TableExpression : Expression { - public sealed class TableExpression : Expression - { - public List Initializers { get; } - public bool Keyed { get; } + public List Initializers { get; } + public bool Keyed { get; } - public TableExpression(List initializers, bool keyed) - { - Initializers = initializers; - Keyed = keyed; + public TableExpression(List initializers, bool keyed) + { + Initializers = initializers; + Keyed = keyed; - Reparent(Initializers); - } + Reparent(Initializers); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/TypeOfExpression.cs b/Core/EVIL.Grammar/AST/Expressions/TypeOfExpression.cs index 05361b8d..e55af3eb 100644 --- a/Core/EVIL.Grammar/AST/Expressions/TypeOfExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/TypeOfExpression.cs @@ -1,15 +1,14 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Expressions; -namespace EVIL.Grammar.AST.Expressions +using EVIL.Grammar.AST.Base; + +public sealed class TypeOfExpression : Expression { - public class TypeOfExpression : Expression - { - public Expression Target { get; } + public Expression Target { get; } - public TypeOfExpression(Expression target) - { - Target = target; - Reparent(Target); - } + public TypeOfExpression(Expression target) + { + Target = target; + Reparent(Target); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/UnaryExpression.cs b/Core/EVIL.Grammar/AST/Expressions/UnaryExpression.cs index f7f6eb57..3ae450de 100644 --- a/Core/EVIL.Grammar/AST/Expressions/UnaryExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/UnaryExpression.cs @@ -1,82 +1,81 @@ -using System.Globalization; +namespace EVIL.Grammar.AST.Expressions; + +using System.Globalization; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Constants; -namespace EVIL.Grammar.AST.Expressions +public sealed class UnaryExpression : Expression { - public class UnaryExpression : Expression + public Expression Right { get; } + public UnaryOperationType Type { get; } + + public UnaryExpression(Expression right, UnaryOperationType type) { - public Expression Right { get; } - public UnaryOperationType Type { get; } + Right = right; + Type = type; - public UnaryExpression(Expression right, UnaryOperationType type) - { - Right = right; - Type = type; + Reparent(Right); + } - Reparent(Right); - } + public override Expression Reduce() + { + var right = Right.Reduce(); - public override Expression Reduce() + if (right is NumberConstant numberConstant) { - var right = Right.Reduce(); - - if (right is NumberConstant numberConstant) + switch (Type) { - switch (Type) - { - case UnaryOperationType.Minus: - return new NumberConstant(-numberConstant.Value) - .CopyMetadata(this); + case UnaryOperationType.Minus: + return new NumberConstant(-numberConstant.Value) + .CopyMetadata(this); - case UnaryOperationType.Plus: - return new NumberConstant(numberConstant.Value) - .CopyMetadata(this); + case UnaryOperationType.Plus: + return new NumberConstant(numberConstant.Value) + .CopyMetadata(this); - case UnaryOperationType.LogicalNot: - return new BooleanConstant(numberConstant.Value != 0) - .CopyMetadata(this); + case UnaryOperationType.LogicalNot: + return new BooleanConstant(numberConstant.Value != 0) + .CopyMetadata(this); - case UnaryOperationType.BitwiseNot: - return new NumberConstant(~(long)numberConstant.Value) - .CopyMetadata(this); + case UnaryOperationType.BitwiseNot: + return new NumberConstant(~(long)numberConstant.Value) + .CopyMetadata(this); - case UnaryOperationType.ToNumber: - return new NumberConstant(numberConstant.Value) - .CopyMetadata(this); + case UnaryOperationType.ToNumber: + return new NumberConstant(numberConstant.Value) + .CopyMetadata(this); - case UnaryOperationType.ToString: - return new StringConstant(numberConstant.Value.ToString(CultureInfo.InvariantCulture), false) - .CopyMetadata(this); - } + case UnaryOperationType.ToString: + return new StringConstant(numberConstant.Value.ToString(CultureInfo.InvariantCulture), false) + .CopyMetadata(this); } + } - if (right is StringConstant stringConstant) + if (right is StringConstant stringConstant) + { + switch (Type) { - switch (Type) - { - case UnaryOperationType.Length: - return new NumberConstant(stringConstant.Value.Length) - .CopyMetadata(this); + case UnaryOperationType.Length: + return new NumberConstant(stringConstant.Value.Length) + .CopyMetadata(this); - case UnaryOperationType.ToNumber: + case UnaryOperationType.ToNumber: + { + if (double.TryParse(stringConstant.Value, out var value)) { - if (double.TryParse(stringConstant.Value, out var value)) - { - return new NumberConstant(value) - .CopyMetadata(this); - } - - break; + return new NumberConstant(value) + .CopyMetadata(this); } - case UnaryOperationType.ToString: - return new StringConstant(stringConstant.Value, stringConstant.IsInterpolated) - .CopyMetadata(this); + break; } - } - return this; + case UnaryOperationType.ToString: + return new StringConstant(stringConstant.Value, stringConstant.IsInterpolated) + .CopyMetadata(this); + } } + + return this; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/WithExpression.cs b/Core/EVIL.Grammar/AST/Expressions/WithExpression.cs index b960cfec..e908a0fa 100644 --- a/Core/EVIL.Grammar/AST/Expressions/WithExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/WithExpression.cs @@ -1,18 +1,17 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Expressions; -namespace EVIL.Grammar.AST.Expressions +using EVIL.Grammar.AST.Base; + +public sealed class WithExpression : Expression { - public class WithExpression : Expression - { - public Expression BaseExpression { get; } - public TableExpression TableExpansionExpression { get; } + public Expression BaseExpression { get; } + public TableExpression TableExpansionExpression { get; } - public WithExpression(Expression baseExpression, TableExpression tableExpansionExpression) - { - BaseExpression = baseExpression; - TableExpansionExpression = tableExpansionExpression; + public WithExpression(Expression baseExpression, TableExpression tableExpansionExpression) + { + BaseExpression = baseExpression; + TableExpansionExpression = tableExpansionExpression; - Reparent(BaseExpression, TableExpansionExpression); - } + Reparent(BaseExpression, TableExpansionExpression); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Expressions/YieldExpression.cs b/Core/EVIL.Grammar/AST/Expressions/YieldExpression.cs index c21df1b0..b0c9dd90 100644 --- a/Core/EVIL.Grammar/AST/Expressions/YieldExpression.cs +++ b/Core/EVIL.Grammar/AST/Expressions/YieldExpression.cs @@ -1,20 +1,19 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Expressions; + +using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Miscellaneous; -namespace EVIL.Grammar.AST.Expressions +public sealed class YieldExpression : Expression { - public class YieldExpression : Expression - { - public Expression Target { get; } - public ArgumentList ArgumentList { get; } + public Expression Target { get; } + public ArgumentList ArgumentList { get; } - public YieldExpression(Expression target, ArgumentList argumentList) - { - Target = target; - ArgumentList = argumentList; + public YieldExpression(Expression target, ArgumentList argumentList) + { + Target = target; + ArgumentList = argumentList; - Reparent(Target); - Reparent(ArgumentList); - } + Reparent(Target); + Reparent(ArgumentList); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Miscellaneous/ArgumentList.cs b/Core/EVIL.Grammar/AST/Miscellaneous/ArgumentList.cs index fbb1e412..dbd4b9ee 100644 --- a/Core/EVIL.Grammar/AST/Miscellaneous/ArgumentList.cs +++ b/Core/EVIL.Grammar/AST/Miscellaneous/ArgumentList.cs @@ -1,19 +1,18 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.AST.Miscellaneous; + +using System.Collections.Generic; using EVIL.Grammar.AST.Base; -namespace EVIL.Grammar.AST.Miscellaneous +public sealed class ArgumentList : AstNode { - public class ArgumentList : AstNode - { - public List Arguments { get; } - public bool IsVariadic { get; } + public List Arguments { get; } + public bool IsVariadic { get; } - public ArgumentList(List arguments, bool isVariadic) - { - Arguments = arguments; - IsVariadic = isVariadic; + public ArgumentList(List arguments, bool isVariadic) + { + Arguments = arguments; + IsVariadic = isVariadic; - Reparent(Arguments); - } + Reparent(Arguments); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Miscellaneous/AttributeList.cs b/Core/EVIL.Grammar/AST/Miscellaneous/AttributeList.cs index 2462be76..594b2c50 100644 --- a/Core/EVIL.Grammar/AST/Miscellaneous/AttributeList.cs +++ b/Core/EVIL.Grammar/AST/Miscellaneous/AttributeList.cs @@ -1,17 +1,16 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.AST.Statements.TopLevel; + +using System.Collections.Generic; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Miscellaneous; -namespace EVIL.Grammar.AST.Statements.TopLevel +public sealed class AttributeList : AstNode { - public class AttributeList : AstNode - { - public List Attributes { get; } + public List Attributes { get; } - public AttributeList(List attributes) - { - Attributes = attributes; - Reparent(Attributes); - } + public AttributeList(List attributes) + { + Attributes = attributes; + Reparent(Attributes); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Miscellaneous/AttributeNode.cs b/Core/EVIL.Grammar/AST/Miscellaneous/AttributeNode.cs index 9c888d16..3ddd7b89 100644 --- a/Core/EVIL.Grammar/AST/Miscellaneous/AttributeNode.cs +++ b/Core/EVIL.Grammar/AST/Miscellaneous/AttributeNode.cs @@ -1,28 +1,27 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.AST.Miscellaneous; + +using System.Collections.Generic; using EVIL.Grammar.AST.Base; -namespace EVIL.Grammar.AST.Miscellaneous +public sealed class AttributeNode : AstNode { - public class AttributeNode : AstNode - { - public IdentifierNode Identifier { get; } + public IdentifierNode Identifier { get; } - public List Values { get; } - public Dictionary Properties { get; } + public List Values { get; } + public Dictionary Properties { get; } - public AttributeNode( - IdentifierNode identifier, - List values, - Dictionary properties) - { - Identifier = identifier; - Values = values; - Properties = properties; + public AttributeNode( + IdentifierNode identifier, + List values, + Dictionary properties) + { + Identifier = identifier; + Values = values; + Properties = properties; - Reparent(Identifier); - Reparent(Values); - Reparent(Properties.Keys); - Reparent(Properties.Values); - } + Reparent(Identifier); + Reparent(Values); + Reparent(Properties.Keys); + Reparent(Properties.Values); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Miscellaneous/ByArmNode.cs b/Core/EVIL.Grammar/AST/Miscellaneous/ByArmNode.cs index 252e369b..05e6fa18 100644 --- a/Core/EVIL.Grammar/AST/Miscellaneous/ByArmNode.cs +++ b/Core/EVIL.Grammar/AST/Miscellaneous/ByArmNode.cs @@ -1,20 +1,19 @@ +namespace EVIL.Grammar.AST.Miscellaneous; + using EVIL.Grammar.AST.Base; -namespace EVIL.Grammar.AST.Miscellaneous +public sealed class ByArmNode : AstNode { - public class ByArmNode : AstNode - { - public Expression Selector { get; } - public AstNode ValueArm { get; } - public bool DeepEquality { get; } + public Expression Selector { get; } + public AstNode ValueArm { get; } + public bool DeepEquality { get; } - public ByArmNode(Expression selector, AstNode valueArm, bool deepEquality) - { - Selector = selector; - ValueArm = valueArm; - DeepEquality = deepEquality; + public ByArmNode(Expression selector, AstNode valueArm, bool deepEquality) + { + Selector = selector; + ValueArm = valueArm; + DeepEquality = deepEquality; - Reparent(Selector, valueArm); - } + Reparent(Selector, valueArm); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Miscellaneous/IdentifierNode.cs b/Core/EVIL.Grammar/AST/Miscellaneous/IdentifierNode.cs index f2dd5b9e..798df0a4 100644 --- a/Core/EVIL.Grammar/AST/Miscellaneous/IdentifierNode.cs +++ b/Core/EVIL.Grammar/AST/Miscellaneous/IdentifierNode.cs @@ -1,14 +1,13 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Miscellaneous; -namespace EVIL.Grammar.AST.Miscellaneous +using EVIL.Grammar.AST.Base; + +public sealed class IdentifierNode : AstNode { - public class IdentifierNode : AstNode - { - public string Name { get; } + public string Name { get; } - public IdentifierNode(string name) - { - Name = name; - } + public IdentifierNode(string name) + { + Name = name; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Miscellaneous/ParameterList.cs b/Core/EVIL.Grammar/AST/Miscellaneous/ParameterList.cs index f856f0a1..4632783d 100644 --- a/Core/EVIL.Grammar/AST/Miscellaneous/ParameterList.cs +++ b/Core/EVIL.Grammar/AST/Miscellaneous/ParameterList.cs @@ -1,16 +1,15 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.AST.Miscellaneous; + +using System.Collections.Generic; using EVIL.Grammar.AST.Base; -namespace EVIL.Grammar.AST.Miscellaneous +public sealed class ParameterList : AstNode { - public sealed class ParameterList : AstNode - { - public List Parameters { get; } + public List Parameters { get; } - public ParameterList(List parameters) - { - Parameters = parameters; - Reparent(Parameters); - } + public ParameterList(List parameters) + { + Parameters = parameters; + Reparent(Parameters); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Miscellaneous/ParameterNode.cs b/Core/EVIL.Grammar/AST/Miscellaneous/ParameterNode.cs index dfa945bc..e0f32d5c 100644 --- a/Core/EVIL.Grammar/AST/Miscellaneous/ParameterNode.cs +++ b/Core/EVIL.Grammar/AST/Miscellaneous/ParameterNode.cs @@ -1,22 +1,21 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Miscellaneous; -namespace EVIL.Grammar.AST.Miscellaneous +using EVIL.Grammar.AST.Base; + +public sealed class ParameterNode : AstNode { - public sealed class ParameterNode : AstNode - { - public IdentifierNode Identifier { get; } - public bool ReadWrite { get; } + public IdentifierNode Identifier { get; } + public bool ReadWrite { get; } - public ConstantExpression? Initializer { get; } + public ConstantExpression? Initializer { get; } - public ParameterNode(IdentifierNode identifier, bool readWrite, ConstantExpression? initializer) - { - Identifier = identifier; - ReadWrite = readWrite; - Initializer = initializer; + public ParameterNode(IdentifierNode identifier, bool readWrite, ConstantExpression? initializer) + { + Identifier = identifier; + ReadWrite = readWrite; + Initializer = initializer; - Reparent(Identifier); - Reparent(Initializer); - } + Reparent(Identifier); + Reparent(Initializer); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Miscellaneous/ProgramNode.cs b/Core/EVIL.Grammar/AST/Miscellaneous/ProgramNode.cs index 9a002c8a..4cbc8cfa 100644 --- a/Core/EVIL.Grammar/AST/Miscellaneous/ProgramNode.cs +++ b/Core/EVIL.Grammar/AST/Miscellaneous/ProgramNode.cs @@ -1,21 +1,20 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.AST.Miscellaneous; + +using System.Collections.Generic; using System.Linq; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Statements.TopLevel; -namespace EVIL.Grammar.AST.Miscellaneous +public sealed class ProgramNode : AstNode { - public sealed class ProgramNode : AstNode - { - public IEnumerable FnStatements => Statements.Where(x => x is FnStatement); - public IEnumerable AnythingButFnStatements => Statements.Where(x => x is not FnStatement); + public IEnumerable FnStatements => Statements.Where(x => x is FnStatement); + public IEnumerable AnythingButFnStatements => Statements.Where(x => x is not FnStatement); - public List Statements { get; } + public List Statements { get; } - public ProgramNode(List statements) - { - Statements = statements; - Reparent(Statements); - } + public ProgramNode(List statements) + { + Statements = statements; + Reparent(Statements); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Statements/BlockStatement.cs b/Core/EVIL.Grammar/AST/Statements/BlockStatement.cs index 755ffa36..e231ed2f 100644 --- a/Core/EVIL.Grammar/AST/Statements/BlockStatement.cs +++ b/Core/EVIL.Grammar/AST/Statements/BlockStatement.cs @@ -1,16 +1,15 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.AST.Statements; + +using System.Collections.Generic; using EVIL.Grammar.AST.Base; -namespace EVIL.Grammar.AST.Statements +public sealed class BlockStatement : Statement { - public sealed class BlockStatement : Statement - { - public List Statements { get; } + public List Statements { get; } - public BlockStatement(List statements) - { - Statements = statements; - Reparent(Statements); - } + public BlockStatement(List statements) + { + Statements = statements; + Reparent(Statements); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Statements/BreakStatement.cs b/Core/EVIL.Grammar/AST/Statements/BreakStatement.cs index 30d75adb..48a4482c 100644 --- a/Core/EVIL.Grammar/AST/Statements/BreakStatement.cs +++ b/Core/EVIL.Grammar/AST/Statements/BreakStatement.cs @@ -1,8 +1,7 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Statements; -namespace EVIL.Grammar.AST.Statements +using EVIL.Grammar.AST.Base; + +public sealed class BreakStatement : Statement { - public sealed class BreakStatement : Statement - { - } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Statements/DoWhileStatement.cs b/Core/EVIL.Grammar/AST/Statements/DoWhileStatement.cs index 6565d0c7..f76477b4 100644 --- a/Core/EVIL.Grammar/AST/Statements/DoWhileStatement.cs +++ b/Core/EVIL.Grammar/AST/Statements/DoWhileStatement.cs @@ -1,18 +1,17 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Statements; -namespace EVIL.Grammar.AST.Statements +using EVIL.Grammar.AST.Base; + +public sealed class DoWhileStatement : Statement { - public sealed class DoWhileStatement : Statement - { - public Expression Condition { get; } - public Statement Statement { get; } + public Expression Condition { get; } + public Statement Statement { get; } - public DoWhileStatement(Expression condition, Statement statement) - { - Condition = condition; - Statement = statement; + public DoWhileStatement(Expression condition, Statement statement) + { + Condition = condition; + Statement = statement; - Reparent(Condition, Statement); - } + Reparent(Condition, Statement); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Statements/EachStatement.cs b/Core/EVIL.Grammar/AST/Statements/EachStatement.cs index 8760b4e3..2991f673 100644 --- a/Core/EVIL.Grammar/AST/Statements/EachStatement.cs +++ b/Core/EVIL.Grammar/AST/Statements/EachStatement.cs @@ -1,30 +1,29 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Statements; + +using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Miscellaneous; -namespace EVIL.Grammar.AST.Statements +public sealed class EachStatement : Statement { - public class EachStatement : Statement - { - public IdentifierNode KeyIdentifier { get; } - public IdentifierNode? ValueIdentifier { get; } + public IdentifierNode KeyIdentifier { get; } + public IdentifierNode? ValueIdentifier { get; } - public Expression Iterable { get; } - public Statement Statement { get; } + public Expression Iterable { get; } + public Statement Statement { get; } - public EachStatement( - IdentifierNode keyIdentifier, - IdentifierNode? valueIdentifier, - Expression iterable, - Statement statement) - { - KeyIdentifier = keyIdentifier; - ValueIdentifier = valueIdentifier; - Iterable = iterable; - Statement = statement; + public EachStatement( + IdentifierNode keyIdentifier, + IdentifierNode? valueIdentifier, + Expression iterable, + Statement statement) + { + KeyIdentifier = keyIdentifier; + ValueIdentifier = valueIdentifier; + Iterable = iterable; + Statement = statement; - Reparent(KeyIdentifier); - Reparent(ValueIdentifier); - Reparent(Iterable, Statement); - } + Reparent(KeyIdentifier); + Reparent(ValueIdentifier); + Reparent(Iterable, Statement); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Statements/ExpressionBodyStatement.cs b/Core/EVIL.Grammar/AST/Statements/ExpressionBodyStatement.cs index 468481ab..e572d0f7 100644 --- a/Core/EVIL.Grammar/AST/Statements/ExpressionBodyStatement.cs +++ b/Core/EVIL.Grammar/AST/Statements/ExpressionBodyStatement.cs @@ -1,15 +1,14 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Statements; -namespace EVIL.Grammar.AST.Statements +using EVIL.Grammar.AST.Base; + +public sealed class ExpressionBodyStatement : Statement { - public class ExpressionBodyStatement : Statement - { - public Expression Expression { get; } + public Expression Expression { get; } - public ExpressionBodyStatement(Expression expression) - { - Expression = expression; - Reparent(Expression); - } + public ExpressionBodyStatement(Expression expression) + { + Expression = expression; + Reparent(Expression); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Statements/ExpressionStatement.cs b/Core/EVIL.Grammar/AST/Statements/ExpressionStatement.cs index bc03c8a8..45842d3b 100644 --- a/Core/EVIL.Grammar/AST/Statements/ExpressionStatement.cs +++ b/Core/EVIL.Grammar/AST/Statements/ExpressionStatement.cs @@ -1,18 +1,17 @@ +namespace EVIL.Grammar.AST.Statements; + using EVIL.Grammar.AST.Base; -namespace EVIL.Grammar.AST.Statements +public sealed class ExpressionStatement : Statement { - public sealed class ExpressionStatement : Statement - { - public readonly Expression Expression; + public readonly Expression Expression; - public ExpressionStatement(Expression expression) - { - Expression = expression; - Reparent(Expression); + public ExpressionStatement(Expression expression) + { + Expression = expression; + Reparent(Expression); - Line = Expression.Line; - Column = Expression.Column; - } + Line = Expression.Line; + Column = Expression.Column; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Statements/FnIndexedStatement.cs b/Core/EVIL.Grammar/AST/Statements/FnIndexedStatement.cs index 1880c8df..0ed2b951 100644 --- a/Core/EVIL.Grammar/AST/Statements/FnIndexedStatement.cs +++ b/Core/EVIL.Grammar/AST/Statements/FnIndexedStatement.cs @@ -1,32 +1,31 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Statements; + +using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Grammar.AST.Miscellaneous; using EVIL.Grammar.AST.Statements.TopLevel; -namespace EVIL.Grammar.AST.Statements +public sealed class FnIndexedStatement : Statement { - public class FnIndexedStatement : Statement - { - public IndexerExpression Indexer { get; } - public AttributeList? AttributeList { get; } - public ParameterList? ParameterList { get; } - public Statement InnerStatement { get; } + public IndexerExpression Indexer { get; } + public AttributeList? AttributeList { get; } + public ParameterList? ParameterList { get; } + public Statement InnerStatement { get; } - public FnIndexedStatement( - IndexerExpression indexer, - AttributeList? attributeList, - ParameterList? parameterList, - Statement innerStatement) - { - Indexer = indexer; - AttributeList = attributeList; - ParameterList = parameterList; - InnerStatement = innerStatement; + public FnIndexedStatement( + IndexerExpression indexer, + AttributeList? attributeList, + ParameterList? parameterList, + Statement innerStatement) + { + Indexer = indexer; + AttributeList = attributeList; + ParameterList = parameterList; + InnerStatement = innerStatement; - Reparent(Indexer); - Reparent(AttributeList); - Reparent(ParameterList); - Reparent(InnerStatement); - } + Reparent(Indexer); + Reparent(AttributeList); + Reparent(ParameterList); + Reparent(InnerStatement); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Statements/FnStatement.cs b/Core/EVIL.Grammar/AST/Statements/FnStatement.cs index 1393b49e..4fb95293 100644 --- a/Core/EVIL.Grammar/AST/Statements/FnStatement.cs +++ b/Core/EVIL.Grammar/AST/Statements/FnStatement.cs @@ -1,33 +1,32 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Statements.TopLevel; + +using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Miscellaneous; -namespace EVIL.Grammar.AST.Statements.TopLevel +public sealed class FnStatement : Statement { - public sealed class FnStatement : Statement - { - public IdentifierNode Identifier { get; } - public AttributeList? AttributeList { get; } - public ParameterList? ParameterList { get; } - public Statement Statement { get; } - public bool IsLocalDefinition { get; } + public IdentifierNode Identifier { get; } + public AttributeList? AttributeList { get; } + public ParameterList? ParameterList { get; } + public Statement Statement { get; } + public bool IsLocalDefinition { get; } - public FnStatement( - IdentifierNode identifier, - AttributeList? attributeList, - ParameterList? parameterList, - Statement statement, - bool isLocalDefinition) - { - Identifier = identifier; - AttributeList = attributeList; - ParameterList = parameterList; - Statement = statement; - IsLocalDefinition = isLocalDefinition; + public FnStatement( + IdentifierNode identifier, + AttributeList? attributeList, + ParameterList? parameterList, + Statement statement, + bool isLocalDefinition) + { + Identifier = identifier; + AttributeList = attributeList; + ParameterList = parameterList; + Statement = statement; + IsLocalDefinition = isLocalDefinition; - Reparent(Identifier); - Reparent(AttributeList); - Reparent(ParameterList); - Reparent(Statement); - } + Reparent(Identifier); + Reparent(AttributeList); + Reparent(ParameterList); + Reparent(Statement); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Statements/FnTargetedStatement.cs b/Core/EVIL.Grammar/AST/Statements/FnTargetedStatement.cs index 45931c0a..89d9d4b8 100644 --- a/Core/EVIL.Grammar/AST/Statements/FnTargetedStatement.cs +++ b/Core/EVIL.Grammar/AST/Statements/FnTargetedStatement.cs @@ -1,38 +1,37 @@ +namespace EVIL.Grammar.AST.Statements; + using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Grammar.AST.Miscellaneous; using EVIL.Grammar.AST.Statements.TopLevel; -namespace EVIL.Grammar.AST.Statements +public class FnTargetedStatement : Statement { - public class FnTargetedStatement : Statement - { - public AstNode PrimaryTarget { get; } - public IdentifierNode SecondaryIdentifier { get; } - public AttributeList? AttributeList { get; } - public ParameterList? ParameterList { get; } - public Statement InnerStatement { get; } + public AstNode PrimaryTarget { get; } + public IdentifierNode SecondaryIdentifier { get; } + public AttributeList? AttributeList { get; } + public ParameterList? ParameterList { get; } + public Statement InnerStatement { get; } - public bool IsSelfTargeting => PrimaryTarget is SelfExpression; + public bool IsSelfTargeting => PrimaryTarget is SelfExpression; - public FnTargetedStatement( - AstNode primaryTarget, - IdentifierNode secondaryIdentifier, - AttributeList? attributeList, - ParameterList? parameterList, - Statement innerStatement) - { - PrimaryTarget = primaryTarget; - SecondaryIdentifier = secondaryIdentifier; - AttributeList = attributeList; - ParameterList = parameterList; - InnerStatement = innerStatement; + public FnTargetedStatement( + AstNode primaryTarget, + IdentifierNode secondaryIdentifier, + AttributeList? attributeList, + ParameterList? parameterList, + Statement innerStatement) + { + PrimaryTarget = primaryTarget; + SecondaryIdentifier = secondaryIdentifier; + AttributeList = attributeList; + ParameterList = parameterList; + InnerStatement = innerStatement; - Reparent(PrimaryTarget); - Reparent(SecondaryIdentifier); - Reparent(AttributeList); - Reparent(ParameterList); - Reparent(InnerStatement); - } + Reparent(PrimaryTarget); + Reparent(SecondaryIdentifier); + Reparent(AttributeList); + Reparent(ParameterList); + Reparent(InnerStatement); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Statements/ForStatement.cs b/Core/EVIL.Grammar/AST/Statements/ForStatement.cs index c2443244..34dcf890 100644 --- a/Core/EVIL.Grammar/AST/Statements/ForStatement.cs +++ b/Core/EVIL.Grammar/AST/Statements/ForStatement.cs @@ -1,30 +1,29 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.AST.Statements; + +using System.Collections.Generic; using EVIL.Grammar.AST.Base; -namespace EVIL.Grammar.AST.Statements +public sealed class ForStatement : Statement { - public sealed class ForStatement : Statement - { - public List Assignments { get; } - public Expression Condition { get; } - public List IterationStatements { get; } - public Statement Statement { get; } + public List Assignments { get; } + public Expression Condition { get; } + public List IterationStatements { get; } + public Statement Statement { get; } - public ForStatement( - List assignments, - Expression condition, - List iterationStatements, - Statement statement) - { - Assignments = assignments; - Condition = condition; - IterationStatements = iterationStatements; - Statement = statement; + public ForStatement( + List assignments, + Expression condition, + List iterationStatements, + Statement statement) + { + Assignments = assignments; + Condition = condition; + IterationStatements = iterationStatements; + Statement = statement; - Reparent(Assignments); - Reparent(IterationStatements); - Reparent(Condition); - Reparent(Statement); - } + Reparent(Assignments); + Reparent(IterationStatements); + Reparent(Condition); + Reparent(Statement); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Statements/IfStatement.cs b/Core/EVIL.Grammar/AST/Statements/IfStatement.cs index 49d74900..b7f40d3f 100644 --- a/Core/EVIL.Grammar/AST/Statements/IfStatement.cs +++ b/Core/EVIL.Grammar/AST/Statements/IfStatement.cs @@ -1,34 +1,33 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.AST.Statements; + +using System.Collections.Generic; using EVIL.Grammar.AST.Base; -namespace EVIL.Grammar.AST.Statements +public sealed class IfStatement : Statement { - public sealed class IfStatement : Statement - { - private List _conditions = new(); - private List _statements = new(); + private List _conditions = new(); + private List _statements = new(); - public IReadOnlyList Conditions => _conditions; - public IReadOnlyList Statements => _statements; + public IReadOnlyList Conditions => _conditions; + public IReadOnlyList Statements => _statements; - public Statement? ElseBranch { get; private set; } + public Statement? ElseBranch { get; private set; } - public void AddCondition(Expression expr) - { - Reparent(expr); - _conditions.Add(expr); - } + public void AddCondition(Expression expr) + { + Reparent(expr); + _conditions.Add(expr); + } - public void AddStatement(Statement stmt) - { - Reparent(stmt); - _statements.Add(stmt); - } + public void AddStatement(Statement stmt) + { + Reparent(stmt); + _statements.Add(stmt); + } - public void SetElseBranch(Statement stmt) - { - Reparent(stmt); - ElseBranch = stmt; - } + public void SetElseBranch(Statement stmt) + { + Reparent(stmt); + ElseBranch = stmt; } -} +} \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Statements/RetStatement.cs b/Core/EVIL.Grammar/AST/Statements/RetStatement.cs index 203e9294..dc9d098b 100644 --- a/Core/EVIL.Grammar/AST/Statements/RetStatement.cs +++ b/Core/EVIL.Grammar/AST/Statements/RetStatement.cs @@ -1,15 +1,14 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Statements; -namespace EVIL.Grammar.AST.Statements +using EVIL.Grammar.AST.Base; + +public sealed class RetStatement : Statement { - public sealed class RetStatement : Statement - { - public Expression? Expression { get; } + public Expression? Expression { get; } - public RetStatement(Expression? expression) - { - Expression = expression; - Reparent(Expression); - } + public RetStatement(Expression? expression) + { + Expression = expression; + Reparent(Expression); } -} +} \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Statements/RetryStatement.cs b/Core/EVIL.Grammar/AST/Statements/RetryStatement.cs index 7d759447..5527e987 100644 --- a/Core/EVIL.Grammar/AST/Statements/RetryStatement.cs +++ b/Core/EVIL.Grammar/AST/Statements/RetryStatement.cs @@ -1,6 +1,6 @@ namespace EVIL.Grammar.AST.Statements; -using Base; +using EVIL.Grammar.AST.Base; public class RetryStatement : Statement { diff --git a/Core/EVIL.Grammar/AST/Statements/SkipStatement.cs b/Core/EVIL.Grammar/AST/Statements/SkipStatement.cs index 0269b022..2a7e1411 100644 --- a/Core/EVIL.Grammar/AST/Statements/SkipStatement.cs +++ b/Core/EVIL.Grammar/AST/Statements/SkipStatement.cs @@ -1,8 +1,7 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Statements; -namespace EVIL.Grammar.AST.Statements +using EVIL.Grammar.AST.Base; + +public sealed class SkipStatement : Statement { - public sealed class SkipStatement : Statement - { - } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Statements/ThrowStatement.cs b/Core/EVIL.Grammar/AST/Statements/ThrowStatement.cs index 3696b4a8..82a520fa 100644 --- a/Core/EVIL.Grammar/AST/Statements/ThrowStatement.cs +++ b/Core/EVIL.Grammar/AST/Statements/ThrowStatement.cs @@ -1,15 +1,14 @@ +namespace EVIL.Grammar.AST.Statements; + using EVIL.Grammar.AST.Base; -namespace EVIL.Grammar.AST.Statements +public sealed class ThrowStatement : Statement { - public class ThrowStatement : Statement - { - public Expression ThrownExpression { get; } + public Expression ThrownExpression { get; } - public ThrowStatement(Expression thrownExpression) - { - ThrownExpression = thrownExpression; - Reparent(ThrownExpression); - } + public ThrowStatement(Expression thrownExpression) + { + ThrownExpression = thrownExpression; + Reparent(ThrownExpression); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Statements/TryStatement.cs b/Core/EVIL.Grammar/AST/Statements/TryStatement.cs index 9bfe752f..b393b3c3 100644 --- a/Core/EVIL.Grammar/AST/Statements/TryStatement.cs +++ b/Core/EVIL.Grammar/AST/Statements/TryStatement.cs @@ -1,24 +1,23 @@ +namespace EVIL.Grammar.AST.Statements; + using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Miscellaneous; -namespace EVIL.Grammar.AST.Statements +public class TryStatement : Statement { - public class TryStatement : Statement - { - public Statement InnerStatement { get; } - public IdentifierNode? HandlerExceptionLocal { get; } - public Statement HandlerStatement { get; } + 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; + public TryStatement( + Statement innerStatement, + IdentifierNode? handlerExceptionLocal, + Statement handlerStatement) + { + InnerStatement = innerStatement; + HandlerExceptionLocal = handlerExceptionLocal; + HandlerStatement = handlerStatement; - Reparent(InnerStatement, HandlerExceptionLocal, HandlerStatement); - } + Reparent(InnerStatement, HandlerExceptionLocal, HandlerStatement); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Statements/ValStatement.cs b/Core/EVIL.Grammar/AST/Statements/ValStatement.cs index a1171203..257eee58 100644 --- a/Core/EVIL.Grammar/AST/Statements/ValStatement.cs +++ b/Core/EVIL.Grammar/AST/Statements/ValStatement.cs @@ -1,23 +1,22 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.AST.Statements; + +using System.Collections.Generic; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Miscellaneous; -namespace EVIL.Grammar.AST.Statements +public sealed class ValStatement : Statement { - public sealed class ValStatement : Statement - { - public Dictionary Definitions { get; } - public bool ReadWrite { get; } + public Dictionary Definitions { get; } + public bool ReadWrite { get; } - public ValStatement( - Dictionary definitions, - bool readWrite) - { - Definitions = definitions; - ReadWrite = readWrite; + public ValStatement( + Dictionary definitions, + bool readWrite) + { + Definitions = definitions; + ReadWrite = readWrite; - Reparent(Definitions.Keys); - Reparent(Definitions.Values); - } + Reparent(Definitions.Keys); + Reparent(Definitions.Values); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/AST/Statements/WhileStatement.cs b/Core/EVIL.Grammar/AST/Statements/WhileStatement.cs index 676f276c..4bf933ed 100644 --- a/Core/EVIL.Grammar/AST/Statements/WhileStatement.cs +++ b/Core/EVIL.Grammar/AST/Statements/WhileStatement.cs @@ -1,18 +1,17 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.AST.Statements; -namespace EVIL.Grammar.AST.Statements +using EVIL.Grammar.AST.Base; + +public sealed class WhileStatement : Statement { - public sealed class WhileStatement : Statement - { - public Expression Condition { get; } - public Statement Statement { get; } + public Expression Condition { get; } + public Statement Statement { get; } - public WhileStatement(Expression condition, Statement statement) - { - Condition = condition; - Statement = statement; + public WhileStatement(Expression condition, Statement statement) + { + Condition = condition; + Statement = statement; - Reparent(Condition, Statement); - } + Reparent(Condition, Statement); } -} +} \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Base/Parser.Statement.cs b/Core/EVIL.Grammar/Parsing/Base/Parser.Statement.cs index b0213f25..9ed7136d 100644 --- a/Core/EVIL.Grammar/Parsing/Base/Parser.Statement.cs +++ b/Core/EVIL.Grammar/Parsing/Base/Parser.Statement.cs @@ -1,102 +1,101 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Statements; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private Statement Statement() { - private Statement Statement() - { - var token = CurrentToken; - Statement node; + var token = CurrentToken; + Statement node; - switch (token.Type) - { - case TokenType.AttributeList: - case TokenType.Fn: - case TokenType.Loc: - return FnStatement(); + switch (token.Type) + { + case TokenType.AttributeList: + case TokenType.Fn: + case TokenType.Loc: + return FnStatement(); - case TokenType.If: - node = IfStatement(); - break; - - case TokenType.For: - node = ForStatement(); - break; - - case TokenType.While: - node = WhileStatement(); - break; - - case TokenType.Each: - node = EachStatement(); - break; - - case TokenType.LBrace: - node = BlockStatement(); - break; - - case TokenType.Do: - node = DoWhileStatement(); - Match(Token.Semicolon); - break; - - case TokenType.Rw: - node = ReadWriteValStatement(); - Match(Token.Semicolon); - break; - - case TokenType.Val: - node = ValStatement(false); - Match(Token.Semicolon); - break; + case TokenType.If: + node = IfStatement(); + break; + + case TokenType.For: + node = ForStatement(); + break; + + case TokenType.While: + node = WhileStatement(); + break; + + case TokenType.Each: + node = EachStatement(); + break; + + case TokenType.LBrace: + node = BlockStatement(); + break; + + case TokenType.Do: + node = DoWhileStatement(); + Match(Token.Semicolon); + break; + + case TokenType.Rw: + node = ReadWriteValStatement(); + Match(Token.Semicolon); + break; + + case TokenType.Val: + node = ValStatement(false); + Match(Token.Semicolon); + break; - case TokenType.Try: - node = TryStatement(); - break; + case TokenType.Try: + node = TryStatement(); + break; - case TokenType.Retry: - node = RetryStatement(); - break; + case TokenType.Retry: + node = RetryStatement(); + break; - case TokenType.Throw: - node = ThrowStatement(); - Match(Token.Semicolon); - break; - - case TokenType.Increment: - case TokenType.Decrement: - node = ExpressionStatement(PrefixExpression()); - Match(Token.Semicolon); - break; - - case TokenType.Ret: - node = Return(); - Match(Token.Semicolon); - break; - - case TokenType.Skip: - node = Skip(); - Match(Token.Semicolon); - break; - - case TokenType.Break: - node = Break(); - Match(Token.Semicolon); - break; - - default: - { - node = new ExpressionStatement(AssignmentExpression()); - Match(Token.Semicolon); + case TokenType.Throw: + node = ThrowStatement(); + Match(Token.Semicolon); + break; + + case TokenType.Increment: + case TokenType.Decrement: + node = ExpressionStatement(PrefixExpression()); + Match(Token.Semicolon); + break; + + case TokenType.Ret: + node = ReturnStatement(); + Match(Token.Semicolon); + break; + + case TokenType.Skip: + node = SkipStatement(); + Match(Token.Semicolon); + break; + + case TokenType.Break: + node = BreakStatement(); + Match(Token.Semicolon); + break; + + default: + { + node = new ExpressionStatement(AssignmentExpression()); + Match(Token.Semicolon); - break; - } + break; } - - return node; } + + return node; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.AdditiveExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.AdditiveExpression.cs index ee109f34..e649a795 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.AdditiveExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.AdditiveExpression.cs @@ -1,42 +1,41 @@ -using System.Linq; +namespace EVIL.Grammar.Parsing; + +using System.Linq; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private static readonly TokenType[] _additiveOperators = new[] { - private static readonly TokenType[] _additiveOperators = new[] - { - TokenType.Plus, - TokenType.Minus, - }; + TokenType.Plus, + TokenType.Minus, + }; - private Expression AdditiveExpression() - { - var node = MultiplicativeExpression(); - var token = CurrentToken; + private Expression AdditiveExpression() + { + var node = MultiplicativeExpression(); + var token = CurrentToken; - while (_additiveOperators.Contains(token.Type)) + while (_additiveOperators.Contains(token.Type)) + { + if (token.Type == TokenType.Plus) { - if (token.Type == TokenType.Plus) - { - var (line, col) = Match(Token.Plus); - node = new BinaryExpression(node, MultiplicativeExpression(), BinaryOperationType.Add) - { Line = line, Column = col }; - } - else if (token.Type == TokenType.Minus) - { - var (line, col) = Match(Token.Minus); - node = new BinaryExpression(node, MultiplicativeExpression(), BinaryOperationType.Subtract) - { Line = line, Column = col }; - } - - token = CurrentToken; + var (line, col) = Match(Token.Plus); + node = new BinaryExpression(node, MultiplicativeExpression(), BinaryOperationType.Add) + { Line = line, Column = col }; + } + else if (token.Type == TokenType.Minus) + { + var (line, col) = Match(Token.Minus); + node = new BinaryExpression(node, MultiplicativeExpression(), BinaryOperationType.Subtract) + { Line = line, Column = col }; } - return node; + token = CurrentToken; } + + return node; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.AndExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.AndExpression.cs index f34f119d..a2f62a24 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.AndExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.AndExpression.cs @@ -1,26 +1,25 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private Expression AndExpression() { - private Expression AndExpression() - { - var node = EqualityExpression(); - var token = CurrentToken; - - while (token.Type == TokenType.BitwiseAnd) - { - var (line, col) = Match(Token.BitwiseAnd); - node = new BinaryExpression(node, EqualityExpression(), BinaryOperationType.BitwiseAnd) - { Line = line, Column = col }; + var node = EqualityExpression(); + var token = CurrentToken; - token = CurrentToken; - } + while (token.Type == TokenType.BitwiseAnd) + { + var (line, col) = Match(Token.BitwiseAnd); + node = new BinaryExpression(node, EqualityExpression(), BinaryOperationType.BitwiseAnd) + { Line = line, Column = col }; - return node; + token = CurrentToken; } + + return node; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.ArrayExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.ArrayExpression.cs index 3e2c4faf..48e41dcf 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.ArrayExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.ArrayExpression.cs @@ -1,61 +1,60 @@ +namespace EVIL.Grammar.Parsing; + using System.Collections.Generic; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private ArrayExpression ArrayExpression() { - private ArrayExpression ArrayExpression() - { - var (line, col) = Match(Token.Array); - - Expression? sizeExpression = null; + var (line, col) = Match(Token.Array); - if (CurrentToken == Token.LParenthesis) - { - Match(Token.LParenthesis); + Expression? sizeExpression = null; - if (CurrentToken != Token.RParenthesis) - { - sizeExpression = AssignmentExpression(); - } + if (CurrentToken == Token.LParenthesis) + { + Match(Token.LParenthesis); - Match(Token.RParenthesis); + if (CurrentToken != Token.RParenthesis) + { + sizeExpression = AssignmentExpression(); } + + Match(Token.RParenthesis); + } - var expressions = new List(); + var expressions = new List(); - if (CurrentToken == Token.LBrace) + if (CurrentToken == Token.LBrace) + { + Match(Token.LBrace); + while (CurrentToken != Token.RBrace) { - Match(Token.LBrace); - while (CurrentToken != Token.RBrace) - { - expressions.Add(AssignmentExpression()); - - if (CurrentToken == Token.RBrace) - { - break; - } + expressions.Add(AssignmentExpression()); - Match(Token.Comma); + if (CurrentToken == Token.RBrace) + { + break; } - Match(Token.RBrace); + + Match(Token.Comma); } - else + Match(Token.RBrace); + } + else + { + if (sizeExpression == null) { - if (sizeExpression == null) - { - throw new ParserException( - "Inferred array size requires an array initializer.", - (CurrentState.Line, CurrentState.Column) - ); - } + throw new ParserException( + "Inferred array size requires an array initializer.", + (CurrentState.Line, CurrentState.Column) + ); } - - return new ArrayExpression(sizeExpression, expressions) - { Line = line, Column = col }; } + + return new ArrayExpression(sizeExpression, expressions) + { Line = line, Column = col }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.AssignmentExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.AssignmentExpression.cs index 3700bed7..80bec95e 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.AssignmentExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.AssignmentExpression.cs @@ -1,147 +1,146 @@ +namespace EVIL.Grammar.Parsing; + using System.Collections.Generic; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private static readonly List _assignmentOperators = new() { - private static readonly List _assignmentOperators = new() - { - TokenType.Assign, - TokenType.AssignAdd, - TokenType.AssignSubtract, - TokenType.AssignMultiply, - TokenType.AssignDivide, - TokenType.AssignModulo, - TokenType.AssignBitwiseAnd, - TokenType.AssignBitwiseOr, - TokenType.AssignBitwiseXor, - TokenType.AssignShiftLeft, - TokenType.AssignShiftRight, - TokenType.AssignCoalesce - }; + TokenType.Assign, + TokenType.AssignAdd, + TokenType.AssignSubtract, + TokenType.AssignMultiply, + TokenType.AssignDivide, + TokenType.AssignModulo, + TokenType.AssignBitwiseAnd, + TokenType.AssignBitwiseOr, + TokenType.AssignBitwiseXor, + TokenType.AssignShiftLeft, + TokenType.AssignShiftRight, + TokenType.AssignCoalesce + }; - private Expression AssignmentExpression() - { - var node = ConditionalExpression(); - var token = CurrentToken; + private Expression AssignmentExpression() + { + var node = ConditionalExpression(); + var token = CurrentToken; - while (_assignmentOperators.Contains(token.Type)) + while (_assignmentOperators.Contains(token.Type)) + { + if (node.IsConstant) { - if (node.IsConstant) - { - throw new ParserException( - "Left-hand side of an assignment must be an assignable entity.", - (_lexer.State.Line, _lexer.State.Column) - ); - } + throw new ParserException( + "Left-hand side of an assignment must be an assignable entity.", + (_lexer.State.Line, _lexer.State.Column) + ); + } - switch (token.Type) + switch (token.Type) + { + case TokenType.Assign: { - case TokenType.Assign: - { - var (line, col) = Match(Token.Assign); + var (line, col) = Match(Token.Assign); - node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.Direct) - { Line = line, Column = col }; - break; - } - case TokenType.AssignAdd: - { - var (line, col) = Match(Token.AssignAdd); + node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.Direct) + { Line = line, Column = col }; + break; + } + case TokenType.AssignAdd: + { + var (line, col) = Match(Token.AssignAdd); - node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.Add) - { Line = line, Column = col }; - break; - } - case TokenType.AssignSubtract: - { - var (line, col) = Match(Token.AssignSubtract); + node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.Add) + { Line = line, Column = col }; + break; + } + case TokenType.AssignSubtract: + { + var (line, col) = Match(Token.AssignSubtract); - node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.Subtract) - { Line = line, Column = col }; - break; - } - case TokenType.AssignMultiply: - { - var (line, col) = Match(Token.AssignMultiply); + node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.Subtract) + { Line = line, Column = col }; + break; + } + case TokenType.AssignMultiply: + { + var (line, col) = Match(Token.AssignMultiply); - node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.Multiply) - { Line = line, Column = col }; - break; - } - case TokenType.AssignDivide: - { - var (line, col) = Match(Token.AssignDivide); + node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.Multiply) + { Line = line, Column = col }; + break; + } + case TokenType.AssignDivide: + { + var (line, col) = Match(Token.AssignDivide); - node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.Divide) - { Line = line, Column = col }; - break; - } - case TokenType.AssignModulo: - { - var (line, col) = Match(Token.AssignModulo); + node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.Divide) + { Line = line, Column = col }; + break; + } + case TokenType.AssignModulo: + { + var (line, col) = Match(Token.AssignModulo); - node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.Modulo) - { Line = line, Column = col }; - break; - } - case TokenType.AssignBitwiseAnd: - { - var (line, col) = Match(Token.AssignBitwiseAnd); + node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.Modulo) + { Line = line, Column = col }; + break; + } + case TokenType.AssignBitwiseAnd: + { + var (line, col) = Match(Token.AssignBitwiseAnd); - node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.BitwiseAnd) - { Line = line, Column = col }; - break; - } - case TokenType.AssignBitwiseOr: - { - var (line, col) = Match(Token.AssignBitwiseOr); + node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.BitwiseAnd) + { Line = line, Column = col }; + break; + } + case TokenType.AssignBitwiseOr: + { + var (line, col) = Match(Token.AssignBitwiseOr); - node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.BitwiseOr) - { Line = line, Column = col }; - break; - } - case TokenType.AssignBitwiseXor: - { - var (line, col) = Match(Token.AssignBitwiseXor); + node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.BitwiseOr) + { Line = line, Column = col }; + break; + } + case TokenType.AssignBitwiseXor: + { + var (line, col) = Match(Token.AssignBitwiseXor); - node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.BitwiseXor) - { Line = line, Column = col }; - break; - } - case TokenType.AssignShiftRight: - { - var (line, col) = Match(Token.AssignShiftRight); + node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.BitwiseXor) + { Line = line, Column = col }; + break; + } + case TokenType.AssignShiftRight: + { + var (line, col) = Match(Token.AssignShiftRight); - node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.ShiftRight) - { Line = line, Column = col }; - break; - } - case TokenType.AssignShiftLeft: - { - var (line, col) = Match(Token.AssignShiftLeft); + node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.ShiftRight) + { Line = line, Column = col }; + break; + } + case TokenType.AssignShiftLeft: + { + var (line, col) = Match(Token.AssignShiftLeft); - node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.ShiftLeft) - { Line = line, Column = col }; - break; - } - case TokenType.AssignCoalesce: - { - var (line, col) = Match(Token.AssignCoalesce); + node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.ShiftLeft) + { Line = line, Column = col }; + break; + } + case TokenType.AssignCoalesce: + { + var (line, col) = Match(Token.AssignCoalesce); - node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.Coalesce) - { Line = line, Column = col }; - break; - } + node = new AssignmentExpression(node, AssignmentExpression(), AssignmentOperationType.Coalesce) + { Line = line, Column = col }; + break; } - - token = CurrentToken; } - return node; + token = CurrentToken; } + + return node; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.CoalescingExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.CoalescingExpression.cs index b68bc7b2..c69a9e33 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.CoalescingExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.CoalescingExpression.cs @@ -1,23 +1,22 @@ +namespace EVIL.Grammar.Parsing; + using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private Expression CoalescingExpression() { - private Expression CoalescingExpression() - { - var node = LogicalOrExpression(); + var node = LogicalOrExpression(); - if (CurrentToken == Token.DoubleQuestionMark) - { - var (line, col) = Match(Token.DoubleQuestionMark); - return new CoalescingExpression(node, AssignmentExpression()) - { Line = line, Column = col }; - } - - return node; + if (CurrentToken == Token.DoubleQuestionMark) + { + var (line, col) = Match(Token.DoubleQuestionMark); + return new CoalescingExpression(node, AssignmentExpression()) + { Line = line, Column = col }; } + + return node; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.ConditionalExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.ConditionalExpression.cs index c8a7a7f2..6a6655dc 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.ConditionalExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.ConditionalExpression.cs @@ -1,27 +1,26 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private Expression ConditionalExpression() { - private Expression ConditionalExpression() - { - var node = CoalescingExpression(); - - if (CurrentToken.Type == TokenType.QuestionMark) - { - var (line, col) = Match(Token.QuestionMark); - var trueExpression = AssignmentExpression(); - Match(Token.Colon); - var falseExpression = ConditionalExpression(); + var node = CoalescingExpression(); - return new ConditionalExpression(node, trueExpression, falseExpression) - { Line = line, Column = col }; - } + if (CurrentToken.Type == TokenType.QuestionMark) + { + var (line, col) = Match(Token.QuestionMark); + var trueExpression = AssignmentExpression(); + Match(Token.Colon); + var falseExpression = ConditionalExpression(); - return node; + return new ConditionalExpression(node, trueExpression, falseExpression) + { Line = line, Column = col }; } + + return node; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.ConstantExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.ConstantExpression.cs index f480603a..e991742e 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.ConstantExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.ConstantExpression.cs @@ -1,186 +1,185 @@ -using System.Globalization; +namespace EVIL.Grammar.Parsing; + +using System.Globalization; using EVIL.CommonTypes.TypeSystem; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Constants; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private ConstantExpression ConstantExpression() { - private ConstantExpression ConstantExpression() - { - var token = CurrentToken; + var token = CurrentToken; - switch (token.Type) + switch (token.Type) + { + case TokenType.Minus: + case TokenType.Number: { - case TokenType.Minus: - case TokenType.Number: + var (line, col) = (0, 0); + var sign = 1; + if (token.Type == TokenType.Minus) { - var (line, col) = (0, 0); - var sign = 1; - if (token.Type == TokenType.Minus) - { - sign = -1; - (line, col) = Match(Token.Minus); - token = CurrentToken; - Match(Token.Number); - } - else - { - (line, col) = Match(Token.Number); - } - - return new NumberConstant(sign * double.Parse(token.Value)) - { Line = line, Column = col }; + sign = -1; + (line, col) = Match(Token.Minus); + token = CurrentToken; + Match(Token.Number); } - case TokenType.NaN: + else { - var (line, col) = Match(Token.NaN); - - return new NumberConstant(double.NaN) - { Line = line, Column = col }; + (line, col) = Match(Token.Number); } - case TokenType.Infinity: - { - var (line, col) = Match(Token.Infinity); - return new NumberConstant(double.PositiveInfinity) - { Line = line, Column = col }; - } - case TokenType.HexInteger: - { - var (line, col) = Match(Token.HexInteger); + return new NumberConstant(sign * double.Parse(token.Value)) + { Line = line, Column = col }; + } + case TokenType.NaN: + { + var (line, col) = Match(Token.NaN); - return new NumberConstant(long.Parse(token.Value, NumberStyles.HexNumber)) - { Line = line, Column = col }; - } - case TokenType.True: - { - var (line, col) = Match(Token.True); + return new NumberConstant(double.NaN) + { Line = line, Column = col }; + } + case TokenType.Infinity: + { + var (line, col) = Match(Token.Infinity); - return new BooleanConstant(true) - { Line = line, Column = col }; - } - case TokenType.False: - { - var (line, col) = Match(Token.False); + return new NumberConstant(double.PositiveInfinity) + { Line = line, Column = col }; + } + case TokenType.HexInteger: + { + var (line, col) = Match(Token.HexInteger); - return new BooleanConstant(false) - { Line = line, Column = col }; - } - case TokenType.PlainString: - { - var (line, col) = Match(Token.PlainString); + return new NumberConstant(long.Parse(token.Value, NumberStyles.HexNumber)) + { Line = line, Column = col }; + } + case TokenType.True: + { + var (line, col) = Match(Token.True); - return new StringConstant(token.Value, false) - { Line = line, Column = col }; - } - case TokenType.InterpolatedString: - { - var (line, col) = Match(Token.InterpolatedString); + return new BooleanConstant(true) + { Line = line, Column = col }; + } + case TokenType.False: + { + var (line, col) = Match(Token.False); - return new StringConstant(token.Value, true) - { Line = line, Column = col }; - } - case TokenType.Nil: - { - var (line, col) = Match(Token.Nil); + return new BooleanConstant(false) + { Line = line, Column = col }; + } + case TokenType.PlainString: + { + var (line, col) = Match(Token.PlainString); - return new NilConstant - { Line = line, Column = col }; - } - case TokenType.NilTypeCode: - { - var (line, col) = Match(Token.NilTypeCode); + return new StringConstant(token.Value, false) + { Line = line, Column = col }; + } + case TokenType.InterpolatedString: + { + var (line, col) = Match(Token.InterpolatedString); + + return new StringConstant(token.Value, true) + { Line = line, Column = col }; + } + case TokenType.Nil: + { + var (line, col) = Match(Token.Nil); + + return new NilConstant + { Line = line, Column = col }; + } + case TokenType.NilTypeCode: + { + var (line, col) = Match(Token.NilTypeCode); - return new TypeCodeConstant(DynamicValueType.Nil) - { Line = line, Column = col }; - } - case TokenType.NumberTypeCode: - { - var (line, col) = Match(Token.NumberTypeCode); + return new TypeCodeConstant(DynamicValueType.Nil) + { Line = line, Column = col }; + } + case TokenType.NumberTypeCode: + { + var (line, col) = Match(Token.NumberTypeCode); - return new TypeCodeConstant(DynamicValueType.Number) - { Line = line, Column = col }; - } - case TokenType.StringTypeCode: - { - var (line, col) = Match(Token.StringTypeCode); + return new TypeCodeConstant(DynamicValueType.Number) + { Line = line, Column = col }; + } + case TokenType.StringTypeCode: + { + var (line, col) = Match(Token.StringTypeCode); - return new TypeCodeConstant(DynamicValueType.String) - { Line = line, Column = col }; - } - case TokenType.BooleanTypeCode: - { - var (line, col) = Match(Token.BooleanTypeCode); + return new TypeCodeConstant(DynamicValueType.String) + { Line = line, Column = col }; + } + case TokenType.BooleanTypeCode: + { + var (line, col) = Match(Token.BooleanTypeCode); - return new TypeCodeConstant(DynamicValueType.Boolean) - { Line = line, Column = col }; - } - case TokenType.TableTypeCode: - { - var (line, col) = Match(Token.TableTypeCode); + return new TypeCodeConstant(DynamicValueType.Boolean) + { Line = line, Column = col }; + } + case TokenType.TableTypeCode: + { + var (line, col) = Match(Token.TableTypeCode); - return new TypeCodeConstant(DynamicValueType.Table) - { Line = line, Column = col }; - } - case TokenType.ArrayTypeCode: - { - var (line, col) = Match(Token.ArrayTypeCode); + return new TypeCodeConstant(DynamicValueType.Table) + { Line = line, Column = col }; + } + case TokenType.ArrayTypeCode: + { + var (line, col) = Match(Token.ArrayTypeCode); - return new TypeCodeConstant(DynamicValueType.Array) - { Line = line, Column = col }; - } - case TokenType.FiberTypeCode: - { - var (line, col) = Match(Token.FiberTypeCode); + return new TypeCodeConstant(DynamicValueType.Array) + { Line = line, Column = col }; + } + case TokenType.FiberTypeCode: + { + var (line, col) = Match(Token.FiberTypeCode); - return new TypeCodeConstant(DynamicValueType.Fiber) - { Line = line, Column = col }; - } - case TokenType.ChunkTypeCode: - { - var (line, col) = Match(Token.ChunkTypeCode); + return new TypeCodeConstant(DynamicValueType.Fiber) + { Line = line, Column = col }; + } + case TokenType.ChunkTypeCode: + { + var (line, col) = Match(Token.ChunkTypeCode); - return new TypeCodeConstant(DynamicValueType.Chunk) - { Line = line, Column = col }; - } - case TokenType.ErrorTypeCode: - { - var (line, col) = Match(Token.ErrorTypeCode); + return new TypeCodeConstant(DynamicValueType.Chunk) + { Line = line, Column = col }; + } + case TokenType.ErrorTypeCode: + { + var (line, col) = Match(Token.ErrorTypeCode); - return new TypeCodeConstant(DynamicValueType.Error) - { Line = line, Column = col }; - } - case TokenType.TypeCodeTypeCode: - { - var (line, col) = Match(Token.TypeCodeTypeCode); + return new TypeCodeConstant(DynamicValueType.Error) + { Line = line, Column = col }; + } + case TokenType.TypeCodeTypeCode: + { + var (line, col) = Match(Token.TypeCodeTypeCode); - return new TypeCodeConstant(DynamicValueType.TypeCode) - { Line = line, Column = col }; - } - case TokenType.NativeFunctionTypeCode: - { - var (line, col) = Match(Token.NativeFunctionTypeCode); + return new TypeCodeConstant(DynamicValueType.TypeCode) + { Line = line, Column = col }; + } + case TokenType.NativeFunctionTypeCode: + { + var (line, col) = Match(Token.NativeFunctionTypeCode); - return new TypeCodeConstant(DynamicValueType.NativeFunction) - { Line = line, Column = col }; - } - case TokenType.NativeObjectTypeCode: - { - var (line, col) = Match(Token.NativeObjectTypeCode); + return new TypeCodeConstant(DynamicValueType.NativeFunction) + { Line = line, Column = col }; + } + case TokenType.NativeObjectTypeCode: + { + var (line, col) = Match(Token.NativeObjectTypeCode); - return new TypeCodeConstant(DynamicValueType.NativeObject) - { Line = line, Column = col }; - } - default: - { - throw new ParserException( - $"Unexpected token {token}", - (_lexer.State.Line, _lexer.State.Column) - ); - } + return new TypeCodeConstant(DynamicValueType.NativeObject) + { Line = line, Column = col }; + } + default: + { + throw new ParserException( + $"Unexpected token {token}", + (_lexer.State.Line, _lexer.State.Column) + ); } } } diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.EqualityExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.EqualityExpression.cs index bc29f92f..3312e792 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.EqualityExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.EqualityExpression.cs @@ -1,60 +1,59 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.Parsing; + +using System.Collections.Generic; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private List _equalityOperators = new() { - private List _equalityOperators = new() - { - TokenType.Equal, - TokenType.NotEqual, - TokenType.DeepEqual, - TokenType.DeepNotEqual - }; + TokenType.Equal, + TokenType.NotEqual, + TokenType.DeepEqual, + TokenType.DeepNotEqual + }; + + private Expression EqualityExpression() + { + var node = RelationalExpression(); + var token = CurrentToken; - private Expression EqualityExpression() + while (_equalityOperators.Contains(token.Type)) { - var node = RelationalExpression(); - var token = CurrentToken; + if (token.Type == TokenType.Equal) + { + var (line, col) = Match(Token.Equal); + + node = new BinaryExpression(node, RelationalExpression(), BinaryOperationType.Equal) + { Line = line, Column = col }; + } + else if (token.Type == TokenType.NotEqual) + { + var (line, col) = Match(Token.NotEqual); - while (_equalityOperators.Contains(token.Type)) + node = new BinaryExpression(node, RelationalExpression(), BinaryOperationType.NotEqual) + { Line = line, Column = col }; + } + else if (token.Type == TokenType.DeepEqual) { - if (token.Type == TokenType.Equal) - { - var (line, col) = Match(Token.Equal); - - node = new BinaryExpression(node, RelationalExpression(), BinaryOperationType.Equal) - { Line = line, Column = col }; - } - else if (token.Type == TokenType.NotEqual) - { - var (line, col) = Match(Token.NotEqual); - - node = new BinaryExpression(node, RelationalExpression(), BinaryOperationType.NotEqual) - { Line = line, Column = col }; - } - else if (token.Type == TokenType.DeepEqual) - { - var (line, col) = Match(Token.DeepEqual); - - node = new BinaryExpression(node, RelationalExpression(), BinaryOperationType.DeepEqual) - { Line = line, Column = col }; - } - else if (token.Type == TokenType.DeepNotEqual) - { - var (line, col) = Match(Token.DeepNotEqual); - - node = new BinaryExpression(node, RelationalExpression(), BinaryOperationType.DeepNotEqual) - { Line = line, Column = col }; - } - - token = CurrentToken; + var (line, col) = Match(Token.DeepEqual); + + node = new BinaryExpression(node, RelationalExpression(), BinaryOperationType.DeepEqual) + { Line = line, Column = col }; } + else if (token.Type == TokenType.DeepNotEqual) + { + var (line, col) = Match(Token.DeepNotEqual); - return node; + node = new BinaryExpression(node, RelationalExpression(), BinaryOperationType.DeepNotEqual) + { Line = line, Column = col }; + } + + token = CurrentToken; } + + return node; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.ErrorExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.ErrorExpression.cs index 55632105..191e1261 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.ErrorExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.ErrorExpression.cs @@ -1,50 +1,49 @@ +namespace EVIL.Grammar.Parsing; + using EVIL.Grammar.AST.Constants; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private ErrorExpression ErrorExpression() { - private ErrorExpression ErrorExpression() - { - var (line, col) = Match(Token.Error); + var (line, col) = Match(Token.Error); - StringConstant? implicitMessage = null; + StringConstant? implicitMessage = null; + + if (CurrentToken.Type == TokenType.LParenthesis) + { + Match(Token.LParenthesis); + var constant = ConstantExpression(); - if (CurrentToken.Type == TokenType.LParenthesis) + if (constant is not StringConstant stringConstant) { - Match(Token.LParenthesis); - var constant = ConstantExpression(); - - if (constant is not StringConstant stringConstant) - { - throw new ParserException( - "Expected a string for the implicit error message.", - (constant.Line, constant.Column) - ); - } - - implicitMessage = stringConstant; - Match(Token.RParenthesis); + throw new ParserException( + "Expected a string for the implicit error message.", + (constant.Line, constant.Column) + ); } - TableExpression? userData = null; + implicitMessage = stringConstant; + Match(Token.RParenthesis); + } - if (implicitMessage != null) - { - if (CurrentToken.Type == TokenType.LBrace) - { - userData = TableExpression(); - } - } - else + TableExpression? userData = null; + + if (implicitMessage != null) + { + if (CurrentToken.Type == TokenType.LBrace) { userData = TableExpression(); } - - return new ErrorExpression(implicitMessage, userData) - { Line = line, Column = col }; } + else + { + userData = TableExpression(); + } + + return new ErrorExpression(implicitMessage, userData) + { Line = line, Column = col }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.ExclusiveOrExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.ExclusiveOrExpression.cs index 510066df..203b8288 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.ExclusiveOrExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.ExclusiveOrExpression.cs @@ -1,27 +1,26 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private Expression ExclusiveOrExpression() { - private Expression ExclusiveOrExpression() - { - var node = AndExpression(); - var token = CurrentToken; - - while (token.Type == TokenType.BitwiseXor) - { - var (line, col) = Match(Token.BitwiseXor); + var node = AndExpression(); + var token = CurrentToken; - node = new BinaryExpression(node, AndExpression(), BinaryOperationType.BitwiseXor) - { Line = line, Column = col }; + while (token.Type == TokenType.BitwiseXor) + { + var (line, col) = Match(Token.BitwiseXor); - token = CurrentToken; - } + node = new BinaryExpression(node, AndExpression(), BinaryOperationType.BitwiseXor) + { Line = line, Column = col }; - return node; + token = CurrentToken; } + + return node; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.FnExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.FnExpression.cs index cdff7421..0cbd0a9b 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.FnExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.FnExpression.cs @@ -1,43 +1,42 @@ +namespace EVIL.Grammar.Parsing; + using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Grammar.AST.Miscellaneous; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private FnExpression FnExpression() { - private FnExpression FnExpression() - { - var (line, col) = Match(Token.Fn); + var (line, col) = Match(Token.Fn); - ParameterList? parameterList = null; - if (CurrentToken == Token.LParenthesis) - { - parameterList = ParameterList(); - } - - Statement statement; - if (CurrentToken == Token.LBrace) - { - statement = FunctionDescent(BlockStatement); - } - else if (CurrentToken == Token.RightArrow) - { - statement = FunctionDescent(ExpressionBodyStatement); - } - else - { - throw new ParserException( - $"Expected '{{' or '->', found '{CurrentToken.Value}',", - (_lexer.State.Line, _lexer.State.Column) - ); - } + ParameterList? parameterList = null; + if (CurrentToken == Token.LParenthesis) + { + parameterList = ParameterList(); + } - return new FnExpression( - parameterList, - statement - ) { Line = line, Column = col }; + Statement statement; + if (CurrentToken == Token.LBrace) + { + statement = FunctionDescent(BlockStatement); } + else if (CurrentToken == Token.RightArrow) + { + statement = FunctionDescent(ExpressionBodyStatement); + } + else + { + throw new ParserException( + $"Expected '{{' or '->', found '{CurrentToken.Value}',", + (_lexer.State.Line, _lexer.State.Column) + ); + } + + return new FnExpression( + parameterList, + statement + ) { Line = line, Column = col }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.InclusiveOrExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.InclusiveOrExpression.cs index 7f0aed94..5965909f 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.InclusiveOrExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.InclusiveOrExpression.cs @@ -1,27 +1,26 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private Expression InclusiveOrExpression() { - private Expression InclusiveOrExpression() - { - var node = ExclusiveOrExpression(); - var token = CurrentToken; - - while (token.Type == TokenType.BitwiseOr) - { - var (line, col) = Match(Token.BitwiseOr); + var node = ExclusiveOrExpression(); + var token = CurrentToken; - node = new BinaryExpression(node, ExclusiveOrExpression(), BinaryOperationType.BitwiseOr) - { Line = line, Column = col }; + while (token.Type == TokenType.BitwiseOr) + { + var (line, col) = Match(Token.BitwiseOr); - token = CurrentToken; - } + node = new BinaryExpression(node, ExclusiveOrExpression(), BinaryOperationType.BitwiseOr) + { Line = line, Column = col }; - return node; + token = CurrentToken; } + + return node; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.IndexerExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.IndexerExpression.cs index e3fd640d..f59d53c9 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.IndexerExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.IndexerExpression.cs @@ -1,47 +1,46 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Constants; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private IndexerExpression IndexerExpression(Expression indexable) { - private IndexerExpression IndexerExpression(Expression indexable) - { - int line, col; - Expression indexer; + int line, col; + Expression indexer; - if (CurrentToken.Type == TokenType.Dot) - { - (line, col) = Match(Token.Dot); + if (CurrentToken.Type == TokenType.Dot) + { + (line, col) = Match(Token.Dot); - var identifier = Identifier(); - indexer = new StringConstant(identifier.Name, false) - { - Line = identifier.Line, - Column = identifier.Column - }; - } - else // must be bracket then + var identifier = Identifier(); + indexer = new StringConstant(identifier.Name, false) { - (line, col) = Match(Token.LBracket); + Line = identifier.Line, + Column = identifier.Column + }; + } + else // must be bracket then + { + (line, col) = Match(Token.LBracket); - indexer = AssignmentExpression(); + indexer = AssignmentExpression(); - if (indexer is NilConstant) - { - throw new ParserException( - "'nil' is not a valid indexer expression.", - (indexer.Line, indexer.Column) - ); - } - - Match(Token.RBracket); + if (indexer is NilConstant) + { + throw new ParserException( + "'nil' is not a valid indexer expression.", + (indexer.Line, indexer.Column) + ); } - - return new IndexerExpression(indexable, indexer, CurrentToken.Type == TokenType.Assign) - { Line = line, Column = col }; + + Match(Token.RBracket); } + + return new IndexerExpression(indexable, indexer, CurrentToken.Type == TokenType.Assign) + { Line = line, Column = col }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.InvocationExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.InvocationExpression.cs index c1bc0334..ba9977e9 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.InvocationExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.InvocationExpression.cs @@ -1,28 +1,27 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Constants; using EVIL.Grammar.AST.Expressions; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private InvocationExpression InvocationExpression(Expression callee) { - private InvocationExpression InvocationExpression(Expression callee) - { - var (line, col) = (_lexer.State.Line, _lexer.State.Column); + var (line, col) = (_lexer.State.Line, _lexer.State.Column); - if (callee is NilConstant) - { - throw new ParserException( - "'nil' is not a valid invocation target.", - (callee.Line, callee.Column) - ); - } + if (callee is NilConstant) + { + throw new ParserException( + "'nil' is not a valid invocation target.", + (callee.Line, callee.Column) + ); + } - var argumentList = ArgumentList(); - var expr = new InvocationExpression(callee, argumentList) - { Line = line, Column = col }; + var argumentList = ArgumentList(); + var expr = new InvocationExpression(callee, argumentList) + { Line = line, Column = col }; - return expr; - } + return expr; } -} +} \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.LogicalAndExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.LogicalAndExpression.cs index f7d12fab..3cd82019 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.LogicalAndExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.LogicalAndExpression.cs @@ -1,27 +1,26 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private Expression LogicalAndExpression() { - private Expression LogicalAndExpression() - { - var node = InclusiveOrExpression(); - var token = CurrentToken; + var node = InclusiveOrExpression(); + var token = CurrentToken; - while (token.Type == TokenType.LogicalAnd) - { - var (line, col) = Match(Token.LogicalAnd); + while (token.Type == TokenType.LogicalAnd) + { + var (line, col) = Match(Token.LogicalAnd); - node = new BinaryExpression(node, InclusiveOrExpression(), BinaryOperationType.LogicalAnd) - { Line = line, Column = col }; + node = new BinaryExpression(node, InclusiveOrExpression(), BinaryOperationType.LogicalAnd) + { Line = line, Column = col }; - token = CurrentToken; - } - - return node; + token = CurrentToken; } + + return node; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.LogicalOrExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.LogicalOrExpression.cs index 7a93a1f1..62b29349 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.LogicalOrExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.LogicalOrExpression.cs @@ -1,27 +1,26 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private Expression LogicalOrExpression() { - private Expression LogicalOrExpression() - { - var node = LogicalAndExpression(); - var token = CurrentToken; + var node = LogicalAndExpression(); + var token = CurrentToken; - while (token.Type == TokenType.LogicalOr) - { - var (line, col) = Match(Token.LogicalOr); + while (token.Type == TokenType.LogicalOr) + { + var (line, col) = Match(Token.LogicalOr); - node = new BinaryExpression(node, LogicalAndExpression(), BinaryOperationType.LogicalOr) - { Line = line, Column = col }; + node = new BinaryExpression(node, LogicalAndExpression(), BinaryOperationType.LogicalOr) + { Line = line, Column = col }; - token = CurrentToken; - } - - return node; + token = CurrentToken; } + + return node; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.MultiplicativeExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.MultiplicativeExpression.cs index 21ee5fe0..96f708ce 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.MultiplicativeExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.MultiplicativeExpression.cs @@ -1,52 +1,51 @@ -using System.Linq; +namespace EVIL.Grammar.Parsing; + +using System.Linq; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private static readonly TokenType[] _multiplicativeOperators = new[] { - private static readonly TokenType[] _multiplicativeOperators = new[] - { - TokenType.Multiply, - TokenType.Divide, - TokenType.Modulo - }; + TokenType.Multiply, + TokenType.Divide, + TokenType.Modulo + }; + + private Expression MultiplicativeExpression() + { + var node = PatternExpression(); + var token = CurrentToken; - private Expression MultiplicativeExpression() + while (_multiplicativeOperators.Contains(token.Type)) { - var node = PatternExpression(); - var token = CurrentToken; + if (token.Type == TokenType.Multiply) + { + var (line, col) = Match(Token.Multiply); - while (_multiplicativeOperators.Contains(token.Type)) + node = new BinaryExpression(node, PatternExpression(), BinaryOperationType.Multiply) + { Line = line, Column = col }; + } + else if (token.Type == TokenType.Divide) { - if (token.Type == TokenType.Multiply) - { - var (line, col) = Match(Token.Multiply); - - node = new BinaryExpression(node, PatternExpression(), BinaryOperationType.Multiply) - { Line = line, Column = col }; - } - else if (token.Type == TokenType.Divide) - { - var (line, col) = Match(Token.Divide); - - node = new BinaryExpression(node, PatternExpression(), BinaryOperationType.Divide) - { Line = line, Column = col }; - } - else if (token.Type == TokenType.Modulo) - { - var (line, col) = Match(Token.Modulo); - - node = new BinaryExpression(node, PatternExpression(), BinaryOperationType.Modulo) - { Line = line, Column = col }; - } - - token = CurrentToken; + var (line, col) = Match(Token.Divide); + + node = new BinaryExpression(node, PatternExpression(), BinaryOperationType.Divide) + { Line = line, Column = col }; } + else if (token.Type == TokenType.Modulo) + { + var (line, col) = Match(Token.Modulo); - return node; + node = new BinaryExpression(node, PatternExpression(), BinaryOperationType.Modulo) + { Line = line, Column = col }; + } + + token = CurrentToken; } + + return node; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.PatternExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.PatternExpression.cs index 2fa55f45..73fe11ce 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.PatternExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.PatternExpression.cs @@ -1,29 +1,28 @@ +namespace EVIL.Grammar.Parsing; + using EVIL.Grammar.AST.Base; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private Expression PatternExpression() { - private Expression PatternExpression() + if (CurrentToken.Type == TokenType.By) + { + return ByExpression(); + } + else { - if (CurrentToken.Type == TokenType.By) + var node = PrefixExpression(); + var token = CurrentToken; + + while (token.Type == TokenType.With) { - return ByExpression(); + node = WithExpression(node); + token = CurrentToken; } - else - { - var node = PrefixExpression(); - var token = CurrentToken; - - while (token.Type == TokenType.With) - { - node = WithExpression(node); - token = CurrentToken; - } - return node; - } + return node; } } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.PostfixExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.PostfixExpression.cs index 7210f060..20b6335e 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.PostfixExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.PostfixExpression.cs @@ -1,65 +1,64 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.Parsing; + +using System.Collections.Generic; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private List _postfixOperators = new() + { + TokenType.LParenthesis, + TokenType.LBracket, + TokenType.Dot, + TokenType.DoubleColon, + TokenType.Increment, + TokenType.Decrement, + }; + + private Expression PostfixExpression() { - private List _postfixOperators = new() + var node = PrimaryExpression(); + var token = CurrentToken; + + __incdec: + if (token.Type == TokenType.Increment) { - TokenType.LParenthesis, - TokenType.LBracket, - TokenType.Dot, - TokenType.DoubleColon, - TokenType.Increment, - TokenType.Decrement, - }; + var (line, col) = Match(Token.Increment); + + return new IncrementationExpression(node, false) + { Line = line, Column = col }; + } + else if (token.Type == TokenType.Decrement) + { + var (line, col) = Match(Token.Decrement); + + return new DecrementationExpression(node, false) + { Line = line, Column = col}; + } - private Expression PostfixExpression() + while (_postfixOperators.Contains(token.Type)) { - var node = PrimaryExpression(); - var token = CurrentToken; - - __incdec: - if (token.Type == TokenType.Increment) + if (token.Type == TokenType.Increment || token.Type == TokenType.Decrement) + goto __incdec; + + if (token.Type == TokenType.LParenthesis) { - var (line, col) = Match(Token.Increment); - - return new IncrementationExpression(node, false) - { Line = line, Column = col }; + node = InvocationExpression(node); } - else if (token.Type == TokenType.Decrement) + else if (token.Type == TokenType.LBracket || token.Type == TokenType.Dot) { - var (line, col) = Match(Token.Decrement); - - return new DecrementationExpression(node, false) - { Line = line, Column = col}; + node = IndexerExpression(node); } - - while (_postfixOperators.Contains(token.Type)) + else if (token.Type == TokenType.DoubleColon) { - if (token.Type == TokenType.Increment || token.Type == TokenType.Decrement) - goto __incdec; - - if (token.Type == TokenType.LParenthesis) - { - node = InvocationExpression(node); - } - else if (token.Type == TokenType.LBracket || token.Type == TokenType.Dot) - { - node = IndexerExpression(node); - } - else if (token.Type == TokenType.DoubleColon) - { - node = SelfInvocationExpression(node); - } - - token = CurrentToken; + node = SelfInvocationExpression(node); } - return node; + token = CurrentToken; } + + return node; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.PrefixExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.PrefixExpression.cs index 1afbcd98..270492ca 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.PrefixExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.PrefixExpression.cs @@ -1,31 +1,30 @@ +namespace EVIL.Grammar.Parsing; + using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private Expression PrefixExpression() { - private Expression PrefixExpression() - { - var token = CurrentToken; + var token = CurrentToken; - if (token.Type == TokenType.Increment) - { - var (line, col) = Match(Token.Increment); + if (token.Type == TokenType.Increment) + { + var (line, col) = Match(Token.Increment); - return new IncrementationExpression(RuntimeExpression(), true) - { Line = line, Column = col }; - } - else if (token.Type == TokenType.Decrement) - { - var (line, col) = Match(Token.Decrement); + return new IncrementationExpression(RuntimeExpression(), true) + { Line = line, Column = col }; + } + else if (token.Type == TokenType.Decrement) + { + var (line, col) = Match(Token.Decrement); - return new DecrementationExpression(RuntimeExpression(), true) - { Line = line, Column = col }; - } - - return RuntimeExpression(); + return new DecrementationExpression(RuntimeExpression(), true) + { Line = line, Column = col }; } + + return RuntimeExpression(); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.PrimaryExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.PrimaryExpression.cs index 9ea760c2..f53a7b49 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.PrimaryExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.PrimaryExpression.cs @@ -1,60 +1,59 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private Expression PrimaryExpression() { - private Expression PrimaryExpression() - { - var token = CurrentToken; + var token = CurrentToken; - if (token.Type == TokenType.LParenthesis) - { - var (line, col) = Match(Token.LParenthesis); + if (token.Type == TokenType.LParenthesis) + { + var (line, col) = Match(Token.LParenthesis); - var node = AssignmentExpression(); - node.Line = line; - node.Column = col; + var node = AssignmentExpression(); + node.Line = line; + node.Column = col; - Match(Token.RParenthesis); + Match(Token.RParenthesis); - return node; - } - else if (token.Type == TokenType.LBrace) - { - return TableExpression(); - } - else if (token.Type == TokenType.Array) - { - return ArrayExpression(); - } - else if (token.Type == TokenType.Error) - { - return ErrorExpression(); - } - else if (token.Type == TokenType.Ellipsis) - { - var (line, col) = Match(Token.Ellipsis); + return node; + } + else if (token.Type == TokenType.LBrace) + { + return TableExpression(); + } + else if (token.Type == TokenType.Array) + { + return ArrayExpression(); + } + else if (token.Type == TokenType.Error) + { + return ErrorExpression(); + } + else if (token.Type == TokenType.Ellipsis) + { + var (line, col) = Match(Token.Ellipsis); - return new ExtraArgumentsExpression(false) - { Line = line, Column = col }; - } - else if (token.Type == TokenType.Fn) - { - return FnExpression(); - } - else if (token.Type == TokenType.Identifier) - { - return SymbolReferenceExpression(); - } - else if (token.Type == TokenType.Self) - { - return SelfExpression(); - } - - return ConstantExpression(); + return new ExtraArgumentsExpression(false) + { Line = line, Column = col }; } + else if (token.Type == TokenType.Fn) + { + return FnExpression(); + } + else if (token.Type == TokenType.Identifier) + { + return SymbolReferenceExpression(); + } + else if (token.Type == TokenType.Self) + { + return SelfExpression(); + } + + return ConstantExpression(); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.RelationalExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.RelationalExpression.cs index 51535680..65dac2a1 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.RelationalExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.RelationalExpression.cs @@ -1,107 +1,106 @@ -using System.Linq; +namespace EVIL.Grammar.Parsing; + +using System.Linq; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Constants; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private static readonly TokenType[] _comparisonOperators = new[] { - private static readonly TokenType[] _comparisonOperators = new[] - { - TokenType.LessThan, - TokenType.GreaterThan, - TokenType.LessThanOrEqual, - TokenType.GreaterThanOrEqual, - TokenType.In, - TokenType.NotIn, - TokenType.Is, - TokenType.IsNot - }; + TokenType.LessThan, + TokenType.GreaterThan, + TokenType.LessThanOrEqual, + TokenType.GreaterThanOrEqual, + TokenType.In, + TokenType.NotIn, + TokenType.Is, + TokenType.IsNot + }; - private Expression RelationalExpression() + private Expression RelationalExpression() + { + var node = ShiftExpression(); + var token = CurrentToken; + + while (_comparisonOperators.Contains(token.Type)) { - var node = ShiftExpression(); - var token = CurrentToken; + if (token.Type == TokenType.LessThan) + { + var (line, col) = Match(Token.LessThan); - while (_comparisonOperators.Contains(token.Type)) + node = new BinaryExpression(node, ShiftExpression(), BinaryOperationType.Less) + { Line = line, Column = col }; + } + else if (token.Type == TokenType.GreaterThan) { - if (token.Type == TokenType.LessThan) - { - var (line, col) = Match(Token.LessThan); + var (line, col) = Match(Token.GreaterThan); - node = new BinaryExpression(node, ShiftExpression(), BinaryOperationType.Less) - { Line = line, Column = col }; - } - else if (token.Type == TokenType.GreaterThan) - { - var (line, col) = Match(Token.GreaterThan); + node = new BinaryExpression(node, ShiftExpression(), BinaryOperationType.Greater) + { Line = line, Column = col }; + } + else if (token.Type == TokenType.LessThanOrEqual) + { + var (line, col) = Match(Token.LessThanOrEqual); - node = new BinaryExpression(node, ShiftExpression(), BinaryOperationType.Greater) - { Line = line, Column = col }; - } - else if (token.Type == TokenType.LessThanOrEqual) - { - var (line, col) = Match(Token.LessThanOrEqual); + node = new BinaryExpression(node, ShiftExpression(), BinaryOperationType.LessOrEqual) + { Line = line, Column = col }; + } + else if (token.Type == TokenType.GreaterThanOrEqual) + { + var (line, col) = Match(Token.GreaterThanOrEqual); - node = new BinaryExpression(node, ShiftExpression(), BinaryOperationType.LessOrEqual) - { Line = line, Column = col }; - } - else if (token.Type == TokenType.GreaterThanOrEqual) - { - var (line, col) = Match(Token.GreaterThanOrEqual); + node = new BinaryExpression(node, ShiftExpression(), BinaryOperationType.GreaterOrEqual) + { Line = line, Column = col }; + } + else if (token.Type == TokenType.In) + { + var (line, col) = Match(Token.In); - node = new BinaryExpression(node, ShiftExpression(), BinaryOperationType.GreaterOrEqual) - { Line = line, Column = col }; - } - else if (token.Type == TokenType.In) - { - var (line, col) = Match(Token.In); + node = new BinaryExpression(node, ShiftExpression(), BinaryOperationType.ExistsIn) + { Line = line, Column = col }; + } + else if (token.Type == TokenType.NotIn) + { + var (line, col) = Match(Token.NotIn); + + node = new BinaryExpression(node, ShiftExpression(), BinaryOperationType.DoesNotExistIn) + { Line = line, Column = col } ; + } + else if (token.Type == TokenType.Is || token.Type == TokenType.IsNot) + { + var (line, col) = (-1, -1); - node = new BinaryExpression(node, ShiftExpression(), BinaryOperationType.ExistsIn) - { Line = line, Column = col }; - } - else if (token.Type == TokenType.NotIn) + var invert = false; + + if (token.Type == TokenType.Is) { - var (line, col) = Match(Token.NotIn); - - node = new BinaryExpression(node, ShiftExpression(), BinaryOperationType.DoesNotExistIn) - { Line = line, Column = col } ; + (line, col) = Match(Token.Is); } - else if (token.Type == TokenType.Is || token.Type == TokenType.IsNot) + else { - var (line, col) = (-1, -1); - - var invert = false; - - if (token.Type == TokenType.Is) - { - (line, col) = Match(Token.Is); - } - else - { - (line, col) = Match(Token.IsNot); - invert = true; - } - - var right = ConstantExpression(); + (line, col) = Match(Token.IsNot); + invert = true; + } - if (right is not TypeCodeConstant typeCodeConstant) - { - throw new ParserException( - "Expected a type code constant.", - (right.Line, right.Column) - ); - } + var right = ConstantExpression(); - node = new IsExpression(node, typeCodeConstant, invert) - { Line = line, Column = col }; + if (right is not TypeCodeConstant typeCodeConstant) + { + throw new ParserException( + "Expected a type code constant.", + (right.Line, right.Column) + ); } - token = CurrentToken; - } - return node; + node = new IsExpression(node, typeCodeConstant, invert) + { Line = line, Column = col }; + } + token = CurrentToken; } + + return node; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.RuntimeExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.RuntimeExpression.cs index 210fb190..9df95da6 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.RuntimeExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.RuntimeExpression.cs @@ -1,62 +1,61 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private Expression RuntimeExpression() { - private Expression RuntimeExpression() + var token = CurrentToken; + + if (token.Type == TokenType.TypeOf) { - var token = CurrentToken; - - if (token.Type == TokenType.TypeOf) - { - return TypeOfExpression(); - } - else if (token.Type == TokenType.Yield) - { - return YieldExpression(); - } - - return UnaryExpression(); + return TypeOfExpression(); } - - private TypeOfExpression TypeOfExpression() + else if (token.Type == TokenType.Yield) { - var (line, col) = Match(Token.TypeOf); + return YieldExpression(); + } - Match(Token.LParenthesis); - var target = AssignmentExpression(); - Match(Token.RParenthesis); + return UnaryExpression(); + } - return new TypeOfExpression(target) - { Line = line, Column = col }; - } + private TypeOfExpression TypeOfExpression() + { + var (line, col) = Match(Token.TypeOf); - private YieldExpression YieldExpression() + Match(Token.LParenthesis); + var target = AssignmentExpression(); + Match(Token.RParenthesis); + + return new TypeOfExpression(target) + { Line = line, Column = col }; + } + + private YieldExpression YieldExpression() + { + var (line, col) = Match(Token.Yield); + + Match(Token.LessThan); + + Expression target; + if (CurrentToken == Token.LBracket) { - var (line, col) = Match(Token.Yield); - - Match(Token.LessThan); - - Expression target; - if (CurrentToken == Token.LBracket) - { - Match(Token.LBracket); - target = AssignmentExpression(); - Match(Token.RBracket); - } - else - { - target = SymbolReferenceExpression(); - } - Match(Token.GreaterThan); + Match(Token.LBracket); + target = AssignmentExpression(); + Match(Token.RBracket); + } + else + { + target = SymbolReferenceExpression(); + } + Match(Token.GreaterThan); - var argumentList = ArgumentList(); + var argumentList = ArgumentList(); - return new YieldExpression(target, argumentList) - { Line = line, Column = col }; - } + return new YieldExpression(target, argumentList) + { Line = line, Column = col }; } -} +} \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.SelfExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.SelfExpression.cs index 4f824035..59a1dcf8 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.SelfExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.SelfExpression.cs @@ -1,14 +1,13 @@ -using EVIL.Grammar.AST.Expressions; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private SelfExpression SelfExpression() { - private SelfExpression SelfExpression() - { - var (line, col) = Match(Token.Self); - return new SelfExpression { Line = line, Column = col }; - } + var (line, col) = Match(Token.Self); + return new SelfExpression { Line = line, Column = col }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.SelfFnExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.SelfFnExpression.cs index ccf818d1..aec1cc4b 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.SelfFnExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.SelfFnExpression.cs @@ -1,43 +1,42 @@ +namespace EVIL.Grammar.Parsing; + using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Grammar.AST.Miscellaneous; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private SelfFnExpression SelfFnExpression() { - private SelfFnExpression SelfFnExpression() - { - var (line, col) = Match(Token.Self); - Match(Token.DoubleColon); - Match(Token.Fn); - - ParameterList? parameterList = null; - if (CurrentToken == Token.LParenthesis) - { - parameterList = ParameterList(); - } + var (line, col) = Match(Token.Self); + Match(Token.DoubleColon); + Match(Token.Fn); - Statement statement; - if (CurrentToken == Token.LBrace) - { - statement = FunctionDescent(BlockStatement); - } - else if (CurrentToken == Token.RightArrow) - { - statement = FunctionDescent(ExpressionBodyStatement); - } - else - { - throw new ParserException( - $"Expected '{{' or '->', found '{CurrentToken.Value}',", - (_lexer.State.Line, _lexer.State.Column) - ); - } + ParameterList? parameterList = null; + if (CurrentToken == Token.LParenthesis) + { + parameterList = ParameterList(); + } - return new SelfFnExpression(parameterList, statement) - { Line = line, Column = col }; + Statement statement; + if (CurrentToken == Token.LBrace) + { + statement = FunctionDescent(BlockStatement); } + else if (CurrentToken == Token.RightArrow) + { + statement = FunctionDescent(ExpressionBodyStatement); + } + else + { + throw new ParserException( + $"Expected '{{' or '->', found '{CurrentToken.Value}',", + (_lexer.State.Line, _lexer.State.Column) + ); + } + + return new SelfFnExpression(parameterList, statement) + { Line = line, Column = col }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.SelfInvocationExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.SelfInvocationExpression.cs index f0f11af3..ffbf5ffb 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.SelfInvocationExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.SelfInvocationExpression.cs @@ -1,19 +1,18 @@ +namespace EVIL.Grammar.Parsing; + using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private SelfInvocationExpression SelfInvocationExpression(Expression indexable) { - private SelfInvocationExpression SelfInvocationExpression(Expression indexable) - { - var (line, col) = Match(Token.DoubleColon); - var identifier = Identifier(); - var argumentList = ArgumentList(); + var (line, col) = Match(Token.DoubleColon); + var identifier = Identifier(); + var argumentList = ArgumentList(); - return new SelfInvocationExpression(indexable, identifier, argumentList) - { Line = line, Column = col }; - } + return new SelfInvocationExpression(indexable, identifier, argumentList) + { Line = line, Column = col }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.ShiftExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.ShiftExpression.cs index 47285c9d..e1bca242 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.ShiftExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.ShiftExpression.cs @@ -1,43 +1,42 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.Parsing; + +using System.Collections.Generic; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private List _shiftOperators = new() { - private List _shiftOperators = new() - { - TokenType.ShiftLeft, - TokenType.ShiftRight - }; + TokenType.ShiftLeft, + TokenType.ShiftRight + }; - private Expression ShiftExpression() - { - var node = AdditiveExpression(); - var token = CurrentToken; + private Expression ShiftExpression() + { + var node = AdditiveExpression(); + var token = CurrentToken; - while (_shiftOperators.Contains(token.Type)) + while (_shiftOperators.Contains(token.Type)) + { + if (token.Type == TokenType.ShiftLeft) { - if (token.Type == TokenType.ShiftLeft) - { - var (line, col) = Match(Token.ShiftLeft); + var (line, col) = Match(Token.ShiftLeft); - node = new BinaryExpression(node, AdditiveExpression(), BinaryOperationType.ShiftLeft) - { Line = line, Column = col }; - } - else if (token.Type == TokenType.ShiftRight) - { - var (line, col) = Match(Token.ShiftRight); - node = new BinaryExpression(node, AdditiveExpression(), BinaryOperationType.ShiftRight) - { Line = line, Column = col }; - } - - token = CurrentToken; + node = new BinaryExpression(node, AdditiveExpression(), BinaryOperationType.ShiftLeft) + { Line = line, Column = col }; + } + else if (token.Type == TokenType.ShiftRight) + { + var (line, col) = Match(Token.ShiftRight); + node = new BinaryExpression(node, AdditiveExpression(), BinaryOperationType.ShiftRight) + { Line = line, Column = col }; } - return node; + token = CurrentToken; } + + return node; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.SymbolReferenceExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.SymbolReferenceExpression.cs index ebf88b9d..0eeb3046 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.SymbolReferenceExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.SymbolReferenceExpression.cs @@ -1,15 +1,14 @@ -using EVIL.Grammar.AST.Expressions; +namespace EVIL.Grammar.Parsing; -namespace EVIL.Grammar.Parsing +using EVIL.Grammar.AST.Expressions; + +public partial class Parser { - public partial class Parser + private SymbolReferenceExpression SymbolReferenceExpression() { - private SymbolReferenceExpression SymbolReferenceExpression() - { - var identifier = Identifier(); + var identifier = Identifier(); - return new SymbolReferenceExpression(identifier.Name) - { Line = identifier.Line, Column = identifier.Column }; - } + return new SymbolReferenceExpression(identifier.Name) + { Line = identifier.Line, Column = identifier.Column }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.TableExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.TableExpression.cs index 97b94d63..616cd14b 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.TableExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.TableExpression.cs @@ -1,127 +1,126 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.Parsing; + +using System.Collections.Generic; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Constants; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private TableExpression TableExpression() { - private TableExpression TableExpression() - { - var (line, col) = Match(Token.LBrace); - var initializers = new List(); + var (line, col) = Match(Token.LBrace); + var initializers = new List(); - var keyed = false; + var keyed = false; - while (CurrentToken.Type != TokenType.RBrace) + while (CurrentToken.Type != TokenType.RBrace) + { + if (initializers.Count == 0) { - if (initializers.Count == 0) + if (CurrentToken.Type == TokenType.LBracket) { - if (CurrentToken.Type == TokenType.LBracket) - { - keyed = true; - } - else if (_lexer.PeekToken(1) == Token.Associate) - { - keyed = true; - } - else if (CurrentToken.Type == TokenType.Identifier && _lexer.PeekToken(1) == Token.Colon) - { - keyed = true; - } + keyed = true; + } + else if (_lexer.PeekToken(1) == Token.Associate) + { + keyed = true; + } + else if (CurrentToken.Type == TokenType.Identifier && _lexer.PeekToken(1) == Token.Colon) + { + keyed = true; } + } + + if (keyed) + { + Expression key, value; - if (keyed) + if (CurrentToken.Type == TokenType.LBracket) { - Expression key, value; + key = ComputedKeyExpression(); - if (CurrentToken.Type == TokenType.LBracket) + if (key is NilConstant) { - key = ComputedKeyExpression(); - - if (key is NilConstant) - { - throw new ParserException( - "'nil' is not a valid key expression.", - (key.Line, key.Column) - ); - } + throw new ParserException( + "'nil' is not a valid key expression.", + (key.Line, key.Column) + ); + } - Match(Token.Associate); - value = AssignmentExpression(); + Match(Token.Associate); + value = AssignmentExpression(); - initializers.Add(new KeyValuePairExpression(key, value)); - } - else + initializers.Add(new KeyValuePairExpression(key, value)); + } + else + { + if (CurrentToken.Type == TokenType.Identifier) { - if (CurrentToken.Type == TokenType.Identifier) - { - var keyIdentifier = Identifier(); - - if (CurrentToken == Token.Colon) - { - Match(Token.Colon); - key = new StringConstant(keyIdentifier.Name, false) - { Line = keyIdentifier.Line, Column = keyIdentifier.Column }; - } - else - { - throw new ParserException( - "Identifier-style keys must be followed by a colon.", - (CurrentToken.Line, CurrentToken.Column) - ); - } - } - else - { - key = ConstantExpression(); - Match(Token.Associate); - } + var keyIdentifier = Identifier(); - if (CurrentToken == Token.Self && _lexer.PeekToken(1) == Token.DoubleColon) + if (CurrentToken == Token.Colon) { - value = SelfFnExpression(); + Match(Token.Colon); + key = new StringConstant(keyIdentifier.Name, false) + { Line = keyIdentifier.Line, Column = keyIdentifier.Column }; } else { - value = AssignmentExpression(); + throw new ParserException( + "Identifier-style keys must be followed by a colon.", + (CurrentToken.Line, CurrentToken.Column) + ); } - - initializers.Add(new KeyValuePairExpression(key, value)); } - } - else - { - if (CurrentToken == Token.Self) + else + { + key = ConstantExpression(); + Match(Token.Associate); + } + + if (CurrentToken == Token.Self && _lexer.PeekToken(1) == Token.DoubleColon) { - initializers.Add(SelfFnExpression()); + value = SelfFnExpression(); } else { - initializers.Add(AssignmentExpression()); + value = AssignmentExpression(); } - } - if (CurrentToken.Type == TokenType.RBrace) - break; - - Match(Token.Comma); + initializers.Add(new KeyValuePairExpression(key, value)); + } } + else + { + if (CurrentToken == Token.Self) + { + initializers.Add(SelfFnExpression()); + } + else + { + initializers.Add(AssignmentExpression()); + } + } + + if (CurrentToken.Type == TokenType.RBrace) + break; - Match(Token.RBrace); - return new TableExpression(initializers, keyed) - { Line = line, Column = col }; + Match(Token.Comma); } - private Expression ComputedKeyExpression() - { - Match(Token.LBracket); - var computedKey = AssignmentExpression(); - Match(Token.RBracket); + Match(Token.RBrace); + return new TableExpression(initializers, keyed) + { Line = line, Column = col }; + } - return computedKey; - } + private Expression ComputedKeyExpression() + { + Match(Token.LBracket); + var computedKey = AssignmentExpression(); + Match(Token.RBracket); + + return computedKey; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Expressions/Parser.UnaryExpression.cs b/Core/EVIL.Grammar/Parsing/Expressions/Parser.UnaryExpression.cs index 3f5c4394..b1dbab37 100644 --- a/Core/EVIL.Grammar/Parsing/Expressions/Parser.UnaryExpression.cs +++ b/Core/EVIL.Grammar/Parsing/Expressions/Parser.UnaryExpression.cs @@ -1,78 +1,77 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.Parsing; + +using System.Collections.Generic; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private List _unaryOperators = new() { - private List _unaryOperators = new() - { - TokenType.Plus, - TokenType.Minus, - TokenType.LogicalNot, - TokenType.BitwiseNot, - TokenType.Length, - TokenType.AsNumber, - TokenType.AsString - }; + TokenType.Plus, + TokenType.Minus, + TokenType.LogicalNot, + TokenType.BitwiseNot, + TokenType.Length, + TokenType.AsNumber, + TokenType.AsString + }; - private Expression UnaryExpression() - { - var token = CurrentToken; + private Expression UnaryExpression() + { + var token = CurrentToken; - if (token.Type == TokenType.AsString) - { - var (line, col) = Match(Token.AsString); + if (token.Type == TokenType.AsString) + { + var (line, col) = Match(Token.AsString); - return new UnaryExpression(MultiplicativeExpression(), UnaryOperationType.ToString) - { Line = line, Column = col }; - } - else if (token.Type == TokenType.Plus) - { - var (line, col) = Match(Token.Plus); + return new UnaryExpression(MultiplicativeExpression(), UnaryOperationType.ToString) + { Line = line, Column = col }; + } + else if (token.Type == TokenType.Plus) + { + var (line, col) = Match(Token.Plus); - return new UnaryExpression(MultiplicativeExpression(), UnaryOperationType.Plus) - { Line = line, Column = col }; - } - else if (token.Type == TokenType.Minus) - { - var (line, col) = Match(Token.Minus); + return new UnaryExpression(MultiplicativeExpression(), UnaryOperationType.Plus) + { Line = line, Column = col }; + } + else if (token.Type == TokenType.Minus) + { + var (line, col) = Match(Token.Minus); - return new UnaryExpression(MultiplicativeExpression(), UnaryOperationType.Minus) - { Line = line, Column = col }; - } - else if (token.Type == TokenType.LogicalNot) - { - var (line, col) = Match(Token.LogicalNot); + return new UnaryExpression(MultiplicativeExpression(), UnaryOperationType.Minus) + { Line = line, Column = col }; + } + else if (token.Type == TokenType.LogicalNot) + { + var (line, col) = Match(Token.LogicalNot); - return new UnaryExpression(MultiplicativeExpression(), UnaryOperationType.LogicalNot) - { Line = line, Column = col }; - } - else if (token.Type == TokenType.BitwiseNot) - { - var (line, col) = Match(Token.BitwiseNot); + return new UnaryExpression(MultiplicativeExpression(), UnaryOperationType.LogicalNot) + { Line = line, Column = col }; + } + else if (token.Type == TokenType.BitwiseNot) + { + var (line, col) = Match(Token.BitwiseNot); - return new UnaryExpression(MultiplicativeExpression(), UnaryOperationType.BitwiseNot) - { Line = line, Column = col }; - } - else if (token.Type == TokenType.AsNumber) - { - var (line, col) = Match(Token.AsNumber); + return new UnaryExpression(MultiplicativeExpression(), UnaryOperationType.BitwiseNot) + { Line = line, Column = col }; + } + else if (token.Type == TokenType.AsNumber) + { + var (line, col) = Match(Token.AsNumber); - return new UnaryExpression(MultiplicativeExpression(), UnaryOperationType.ToNumber) - { Line = line, Column = col }; - } - else if (token.Type == TokenType.Length) - { - var (line, col) = Match(Token.Length); + return new UnaryExpression(MultiplicativeExpression(), UnaryOperationType.ToNumber) + { Line = line, Column = col }; + } + else if (token.Type == TokenType.Length) + { + var (line, col) = Match(Token.Length); - return new UnaryExpression(PostfixExpression(), UnaryOperationType.Length) - { Line = line, Column = col }; - } - - return PostfixExpression(); + return new UnaryExpression(PostfixExpression(), UnaryOperationType.Length) + { Line = line, Column = col }; } + + return PostfixExpression(); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.ArgumentList.cs b/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.ArgumentList.cs index 28fdb082..42e1b329 100644 --- a/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.ArgumentList.cs +++ b/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.ArgumentList.cs @@ -1,62 +1,61 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.Parsing; + +using System.Collections.Generic; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; using EVIL.Grammar.AST.Miscellaneous; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private ArgumentList ArgumentList() { - private ArgumentList ArgumentList() + var arguments = new List(); + var isVariadic = false; + + var (line, col) = Match(Token.LParenthesis); + while (CurrentToken.Type != TokenType.RParenthesis) { - var arguments = new List(); - var isVariadic = false; + if (CurrentToken.Type == TokenType.EOF) + { + throw new ParserException( + $"Unexpected EOF in argument list.", + (line, col) + ); + } - var (line, col) = Match(Token.LParenthesis); - while (CurrentToken.Type != TokenType.RParenthesis) + if (CurrentToken.Type == TokenType.Multiply) { - if (CurrentToken.Type == TokenType.EOF) + var (xline, xcol) = Match(Token.Multiply); + + if (CurrentToken.Type != TokenType.RParenthesis) { throw new ParserException( - $"Unexpected EOF in argument list.", - (line, col) + "Variadic parameter specifier must reside at the end of the parameter list.", + (xline, xcol) ); } - if (CurrentToken.Type == TokenType.Multiply) - { - var (xline, xcol) = Match(Token.Multiply); - - if (CurrentToken.Type != TokenType.RParenthesis) - { - throw new ParserException( - "Variadic parameter specifier must reside at the end of the parameter list.", - (xline, xcol) - ); - } - - isVariadic = true; + isVariadic = true; - arguments.Add( - new ExtraArgumentsExpression(true) - { Line = xline, Column = xcol } - ); - } - else - { - arguments.Add(AssignmentExpression()); - } - - if (CurrentToken.Type == TokenType.RParenthesis) - break; - - Match(Token.Comma, "Expected $expected or ')', got $actual"); + arguments.Add( + new ExtraArgumentsExpression(true) + { Line = xline, Column = xcol } + ); + } + else + { + arguments.Add(AssignmentExpression()); } - Match(Token.RParenthesis); - return new ArgumentList(arguments, isVariadic) - { Line = line, Column = col }; + if (CurrentToken.Type == TokenType.RParenthesis) + break; + + Match(Token.Comma, "Expected $expected or ')', got $actual"); } + Match(Token.RParenthesis); + + return new ArgumentList(arguments, isVariadic) + { Line = line, Column = col }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.AttributeList.cs b/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.AttributeList.cs index 927113b7..d98756bc 100644 --- a/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.AttributeList.cs +++ b/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.AttributeList.cs @@ -1,39 +1,38 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.Parsing; + +using System.Collections.Generic; using EVIL.Grammar.AST.Miscellaneous; using EVIL.Grammar.AST.Statements.TopLevel; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private AttributeList AttributeList() { - private AttributeList AttributeList() + if (_functionDescent > 0) { - if (_functionDescent > 0) - { - throw new ParserException( - "Attributes are only valid for top-level functions.", - (_lexer.State.Line, _lexer.State.Column) - ); - } + throw new ParserException( + "Attributes are only valid for top-level functions.", + (_lexer.State.Line, _lexer.State.Column) + ); + } - var attributes = new List(); - var (line, col) = Match(Token.AttributeList); + var attributes = new List(); + var (line, col) = Match(Token.AttributeList); - while (true) - { - attributes.Add(Attribute()); + while (true) + { + attributes.Add(Attribute()); - if (CurrentToken != Token.Semicolon) - break; + if (CurrentToken != Token.Semicolon) + break; - Match(Token.Semicolon); - } + Match(Token.Semicolon); + } - Match(Token.RBracket); + Match(Token.RBracket); - return new AttributeList(attributes) - { Line = line, Column = col }; - } + return new AttributeList(attributes) + { Line = line, Column = col }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.AttributeStatement.cs b/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.AttributeStatement.cs index 0c9bb1c8..126f1ed9 100644 --- a/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.AttributeStatement.cs +++ b/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.AttributeStatement.cs @@ -1,55 +1,54 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.Parsing; + +using System.Collections.Generic; using System.Linq; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Miscellaneous; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private AttributeNode Attribute() { - private AttributeNode Attribute() - { - var attributeIdentifier = Identifier(); - var attributeValues = new List(); - var properties = new Dictionary(); + var attributeIdentifier = Identifier(); + var attributeValues = new List(); + var properties = new Dictionary(); - if (CurrentToken == Token.LParenthesis) + if (CurrentToken == Token.LParenthesis) + { + Match(Token.LParenthesis); + while (CurrentToken != Token.RParenthesis) { - Match(Token.LParenthesis); - while (CurrentToken != Token.RParenthesis) + if (CurrentToken == Token.Identifier) { - if (CurrentToken == Token.Identifier) - { - var attributePropertyIdentifier = Identifier(); + var attributePropertyIdentifier = Identifier(); - Match(Token.Assign); - properties.Add(attributePropertyIdentifier, ConstantExpression()); - } - else + Match(Token.Assign); + properties.Add(attributePropertyIdentifier, ConstantExpression()); + } + else + { + if (properties.Any()) { - if (properties.Any()) - { - throw new ParserException( - $"Attribute values must appear before any properties.", - (_lexer.State.Line, _lexer.State.Column) - ); - } - - attributeValues.Add(ConstantExpression()); + throw new ParserException( + $"Attribute values must appear before any properties.", + (_lexer.State.Line, _lexer.State.Column) + ); } - if (CurrentToken != Token.RParenthesis) - { - Match(Token.Comma); - } + attributeValues.Add(ConstantExpression()); } - Match(Token.RParenthesis); + if (CurrentToken != Token.RParenthesis) + { + Match(Token.Comma); + } } - return new AttributeNode(attributeIdentifier, attributeValues, properties) - { Line = attributeIdentifier.Line, Column = attributeIdentifier.Column }; + Match(Token.RParenthesis); } + + return new AttributeNode(attributeIdentifier, attributeValues, properties) + { Line = attributeIdentifier.Line, Column = attributeIdentifier.Column }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.Identifier.cs b/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.Identifier.cs index 2cea44ed..8fabbd70 100644 --- a/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.Identifier.cs +++ b/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.Identifier.cs @@ -1,17 +1,16 @@ -using EVIL.Grammar.AST.Miscellaneous; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Miscellaneous; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private IdentifierNode Identifier(string? customErrorMessage = null) { - private IdentifierNode Identifier(string? customErrorMessage = null) - { - var name = CurrentToken.Value; - var (line, col) = Match(Token.Identifier, customErrorMessage); + var name = CurrentToken.Value; + var (line, col) = Match(Token.Identifier, customErrorMessage); - return new IdentifierNode(name) - { Line = line, Column = col }; - } + return new IdentifierNode(name) + { Line = line, Column = col }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.ParameterList.cs b/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.ParameterList.cs index 2af5ec89..c145e3e6 100644 --- a/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.ParameterList.cs +++ b/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.ParameterList.cs @@ -1,68 +1,67 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.Parsing; + +using System.Collections.Generic; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Miscellaneous; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private ParameterList ParameterList() { - private ParameterList ParameterList() - { - var (line, col) = Match(Token.LParenthesis); - var parameters = new List(); - var hasInitializers = false; - var preceedingComma = false; + var (line, col) = Match(Token.LParenthesis); + var parameters = new List(); + var hasInitializers = false; + var preceedingComma = false; - while (CurrentToken.Type != TokenType.RParenthesis) + while (CurrentToken.Type != TokenType.RParenthesis) + { + var rw = false; + if (CurrentToken.Type == TokenType.Rw) { - var rw = false; - if (CurrentToken.Type == TokenType.Rw) - { - rw = true; - Match(Token.Rw); - } + rw = true; + Match(Token.Rw); + } - ConstantExpression? initializer = null; + ConstantExpression? initializer = null; - var parameterIdentifier = Identifier( - preceedingComma - ? "Expected $expected, got $actual." - : "Expected $expected or ')', got $actual." - ); + var parameterIdentifier = Identifier( + preceedingComma + ? "Expected $expected, got $actual." + : "Expected $expected or ')', got $actual." + ); - if (CurrentToken == Token.Assign) - { - Match(Token.Assign); - initializer = ConstantExpression(); - hasInitializers = true; - } - else + if (CurrentToken == Token.Assign) + { + Match(Token.Assign); + initializer = ConstantExpression(); + hasInitializers = true; + } + else + { + if (hasInitializers) { - if (hasInitializers) - { - throw new ParserException( - "Uninitialized parameters must precede default parameters.", - (parameterIdentifier.Line, parameterIdentifier.Column) - ); - } + throw new ParserException( + "Uninitialized parameters must precede default parameters.", + (parameterIdentifier.Line, parameterIdentifier.Column) + ); } + } - parameters.Add( - new ParameterNode(parameterIdentifier, rw, initializer) - { Line = parameterIdentifier.Line, Column = parameterIdentifier.Column } - ); - - if (CurrentToken == Token.RParenthesis) - break; + parameters.Add( + new ParameterNode(parameterIdentifier, rw, initializer) + { Line = parameterIdentifier.Line, Column = parameterIdentifier.Column } + ); - Match(Token.Comma, "Expected $expected or ')', got $actual"); - preceedingComma = true; - } - Match(Token.RParenthesis); + if (CurrentToken == Token.RParenthesis) + break; - return new ParameterList(parameters) - { Line = line, Column = col }; + Match(Token.Comma, "Expected $expected or ')', got $actual"); + preceedingComma = true; } + Match(Token.RParenthesis); + + return new ParameterList(parameters) + { Line = line, Column = col }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.Program.cs b/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.Program.cs index 3b5f4409..4e520048 100644 --- a/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.Program.cs +++ b/Core/EVIL.Grammar/Parsing/Miscellaneous/Parser.Program.cs @@ -1,32 +1,31 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.Parsing; + +using System.Collections.Generic; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Miscellaneous; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private ProgramNode Program() { - private ProgramNode Program() - { - var statementList = new List(); + var statementList = new List(); - if (CurrentToken == Token.Empty) - { - throw new ParserException( - "Internal error: lexer is in an invalid state (current token is empty?).", - (-1, -1) - ); - } - - while (CurrentToken.Type != TokenType.EOF) - { - statementList.Add( - Statement() - ); - } + if (CurrentToken == Token.Empty) + { + throw new ParserException( + "Internal error: lexer is in an invalid state (current token is empty?).", + (-1, -1) + ); + } - return new ProgramNode(statementList); + while (CurrentToken.Type != TokenType.EOF) + { + statementList.Add( + Statement() + ); } + + return new ProgramNode(statementList); } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Parser.cs b/Core/EVIL.Grammar/Parsing/Parser.cs index fbd35b64..b5d77664 100644 --- a/Core/EVIL.Grammar/Parsing/Parser.cs +++ b/Core/EVIL.Grammar/Parsing/Parser.cs @@ -1,97 +1,96 @@ -using System; +namespace EVIL.Grammar.Parsing; + +using System; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Miscellaneous; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser - { - private readonly Lexer _lexer = new(); + private readonly Lexer _lexer = new(); - private uint _functionDescent; - private uint _loopDescent; + private uint _functionDescent; + private uint _loopDescent; - public LexerState CurrentState => _lexer.State; - public Token CurrentToken => CurrentState.CurrentToken; + public LexerState CurrentState => _lexer.State; + public Token CurrentToken => CurrentState.CurrentToken; - public ProgramNode Parse(string source) - { - _functionDescent = 0; - _loopDescent = 0; - _lexer.LoadSource(source); + public ProgramNode Parse(string source) + { + _functionDescent = 0; + _loopDescent = 0; + _lexer.LoadSource(source); - var programNode = Program(); - Match(Token.EOF); + var programNode = Program(); + Match(Token.EOF); - return programNode; - } + return programNode; + } - private T FunctionDescent(Func func) where T : AstNode - { - _functionDescent++; - var ret = func(); - _functionDescent--; + private T FunctionDescent(Func func) where T : AstNode + { + _functionDescent++; + var ret = func(); + _functionDescent--; - return ret; - } + return ret; + } - private T LoopDescent(Func func) where T : AstNode - { - _loopDescent++; - var ret = func(); - _loopDescent--; + private T LoopDescent(Func func) where T : AstNode + { + _loopDescent++; + var ret = func(); + _loopDescent--; - return ret; - } + return ret; + } - private (int, int) Match(Token token, string? customErrorMessage = null) + private (int, int) Match(Token token, string? customErrorMessage = null) + { + var line = CurrentToken.Line; + var column = CurrentToken.Column; + + if (CurrentToken.Type != token.Type) { - var line = CurrentToken.Line; - var column = CurrentToken.Column; + var expected = $"'{token.Value}'"; + if (string.IsNullOrEmpty(token.Value)) + { + expected = WithArticle(token.Type.ToString()); + } - if (CurrentToken.Type != token.Type) + var actual = $"'{CurrentToken.Value}'"; + if (string.IsNullOrEmpty(CurrentToken.Value)) { - var expected = $"'{token.Value}'"; - if (string.IsNullOrEmpty(token.Value)) - { - expected = WithArticle(token.Type.ToString()); - } - - var actual = $"'{CurrentToken.Value}'"; - if (string.IsNullOrEmpty(CurrentToken.Value)) - { - actual = WithArticle(CurrentToken.Type.ToString()); - } - - if (customErrorMessage != null) - { - customErrorMessage = customErrorMessage - .Replace("$expected", expected) - .Replace("$actual", actual); - } - else - { - customErrorMessage = $"Expected {expected}, got {actual}."; - } - - throw new ParserException( - customErrorMessage, - (line, column) - ); + actual = WithArticle(CurrentToken.Type.ToString()); } - _lexer.NextToken(); - return (line, column); + if (customErrorMessage != null) + { + customErrorMessage = customErrorMessage + .Replace("$expected", expected) + .Replace("$actual", actual); + } + else + { + customErrorMessage = $"Expected {expected}, got {actual}."; + } + + throw new ParserException( + customErrorMessage, + (line, column) + ); } - private string WithArticle(string word) - { - var result = word.ToLower(); + _lexer.NextToken(); + return (line, column); + } - return "aeiou".Contains(result[0]) - ? $"an {result}" - : $"a {result}"; - } + private string WithArticle(string word) + { + var result = word.ToLower(); + + return "aeiou".Contains(result[0]) + ? $"an {result}" + : $"a {result}"; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Statements/Parser.BlockStatement.cs b/Core/EVIL.Grammar/Parsing/Statements/Parser.BlockStatement.cs index 3970219e..38fdaa04 100644 --- a/Core/EVIL.Grammar/Parsing/Statements/Parser.BlockStatement.cs +++ b/Core/EVIL.Grammar/Parsing/Statements/Parser.BlockStatement.cs @@ -1,33 +1,32 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.Parsing; + +using System.Collections.Generic; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Statements; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private BlockStatement BlockStatement() { - private BlockStatement BlockStatement() - { - var (line, col) = Match(Token.LBrace); + var (line, col) = Match(Token.LBrace); - var statements = new List(); - while (CurrentToken.Type != TokenType.RBrace) + var statements = new List(); + while (CurrentToken.Type != TokenType.RBrace) + { + if (CurrentToken.Type == TokenType.EOF) { - if (CurrentToken.Type == TokenType.EOF) - { - throw new ParserException( - $"Unexpected EOF in a block statement. Unmatched '{{' on line {line}, column {col}.", - (_lexer.State.Column, _lexer.State.Line) - ); - } - - statements.Add(Statement()); + throw new ParserException( + $"Unexpected EOF in a block statement. Unmatched '{{' on line {line}, column {col}.", + (_lexer.State.Column, _lexer.State.Line) + ); } - Match(Token.RBrace); - return new BlockStatement(statements) - { Line = line, Column = col }; + statements.Add(Statement()); } + Match(Token.RBrace); + + return new BlockStatement(statements) + { Line = line, Column = col }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Statements/Parser.BreakStatement.cs b/Core/EVIL.Grammar/Parsing/Statements/Parser.BreakStatement.cs index beac558b..c05c15cd 100644 --- a/Core/EVIL.Grammar/Parsing/Statements/Parser.BreakStatement.cs +++ b/Core/EVIL.Grammar/Parsing/Statements/Parser.BreakStatement.cs @@ -1,24 +1,23 @@ -using EVIL.Grammar.AST.Statements; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Statements; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private BreakStatement BreakStatement() { - private BreakStatement Break() + if (_loopDescent == 0) { - if (_loopDescent == 0) - { - throw new ParserException( - "Unexpected 'break' outside of a loop.", - (_lexer.State.Column, _lexer.State.Line) - ); - } + throw new ParserException( + "Unexpected 'break' outside of a loop.", + (_lexer.State.Column, _lexer.State.Line) + ); + } - var (line, col) = Match(Token.Break); + var (line, col) = Match(Token.Break); - return new BreakStatement - { Line = line, Column = col }; - } + return new BreakStatement + { Line = line, Column = col }; } -} +} \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Statements/Parser.DoWhileStatement.cs b/Core/EVIL.Grammar/Parsing/Statements/Parser.DoWhileStatement.cs index c3dfc309..9ffc2042 100644 --- a/Core/EVIL.Grammar/Parsing/Statements/Parser.DoWhileStatement.cs +++ b/Core/EVIL.Grammar/Parsing/Statements/Parser.DoWhileStatement.cs @@ -1,23 +1,22 @@ -using EVIL.Grammar.AST.Statements; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Statements; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private DoWhileStatement DoWhileStatement() { - private DoWhileStatement DoWhileStatement() - { - var (line, col) = Match(Token.Do); + var (line, col) = Match(Token.Do); - var statements = LoopDescent(() => Statement()); + var statements = LoopDescent(() => Statement()); - Match(Token.While); - Match(Token.LParenthesis); - var conditionExpression = AssignmentExpression(); - Match(Token.RParenthesis); + Match(Token.While); + Match(Token.LParenthesis); + var conditionExpression = AssignmentExpression(); + Match(Token.RParenthesis); - return new DoWhileStatement(conditionExpression, statements) - { Line = line, Column = col }; - } + return new DoWhileStatement(conditionExpression, statements) + { Line = line, Column = col }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Statements/Parser.EachStatement.cs b/Core/EVIL.Grammar/Parsing/Statements/Parser.EachStatement.cs index e17d182c..769227bf 100644 --- a/Core/EVIL.Grammar/Parsing/Statements/Parser.EachStatement.cs +++ b/Core/EVIL.Grammar/Parsing/Statements/Parser.EachStatement.cs @@ -1,49 +1,48 @@ -using EVIL.Grammar.AST.Miscellaneous; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Miscellaneous; using EVIL.Grammar.AST.Statements; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private EachStatement EachStatement() { - private EachStatement EachStatement() - { - var (line, col) = Match(Token.Each); - Match(Token.LParenthesis); + var (line, col) = Match(Token.Each); + Match(Token.LParenthesis); - if (CurrentToken == Token.Val) - { - throw new ParserException( - "Each-loop variables must be 'rw'.", - (_lexer.State.Line, _lexer.State.Column) - ); - } + if (CurrentToken == Token.Val) + { + throw new ParserException( + "Each-loop variables must be 'rw'.", + (_lexer.State.Line, _lexer.State.Column) + ); + } - Match(Token.Rw); - Match(Token.Val); - var keyIdentifier = Identifier(); - IdentifierNode? valueIdentifier = null; + Match(Token.Rw); + Match(Token.Val); + var keyIdentifier = Identifier(); + IdentifierNode? valueIdentifier = null; - if (CurrentToken == Token.Comma) - { - Match(Token.Comma); - valueIdentifier = Identifier(); - } + if (CurrentToken == Token.Comma) + { + Match(Token.Comma); + valueIdentifier = Identifier(); + } - Match(Token.Colon); + Match(Token.Colon); - var iterable = AssignmentExpression(); + var iterable = AssignmentExpression(); - Match(Token.RParenthesis); + Match(Token.RParenthesis); - var statement = LoopDescent(() => Statement()); + var statement = LoopDescent(() => Statement()); - return new EachStatement( - keyIdentifier, - valueIdentifier, - iterable, - statement - ) { Line = line, Column = col }; - } + return new EachStatement( + keyIdentifier, + valueIdentifier, + iterable, + statement + ) { Line = line, Column = col }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Statements/Parser.ForStatement.cs b/Core/EVIL.Grammar/Parsing/Statements/Parser.ForStatement.cs index 97508c06..69cf9113 100644 --- a/Core/EVIL.Grammar/Parsing/Statements/Parser.ForStatement.cs +++ b/Core/EVIL.Grammar/Parsing/Statements/Parser.ForStatement.cs @@ -1,94 +1,93 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.Parsing; + +using System.Collections.Generic; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Statements; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private ForStatement ForStatement() { - private ForStatement ForStatement() - { - var (line, col) = Match(Token.For); + var (line, col) = Match(Token.For); - List assignments; - Expression condition; - List iterationStatements; + List assignments; + Expression condition; + List iterationStatements; - Match(Token.LParenthesis); - { - assignments = ForDeclarationList(); + Match(Token.LParenthesis); + { + assignments = ForDeclarationList(); - Match(Token.Semicolon); + Match(Token.Semicolon); - condition = AssignmentExpression(); + condition = AssignmentExpression(); - Match(Token.Semicolon); + Match(Token.Semicolon); - iterationStatements = ForStatementList(); - } - Match(Token.RParenthesis); + iterationStatements = ForStatementList(); + } + Match(Token.RParenthesis); - var statements = LoopDescent(() => Statement()); + var statements = LoopDescent(() => Statement()); - return new ForStatement( - assignments, - condition, - iterationStatements, - statements - ) { Line = line, Column = col }; - } + return new ForStatement( + assignments, + condition, + iterationStatements, + statements + ) { Line = line, Column = col }; + } - private List ForDeclarationList() + private List ForDeclarationList() + { + var nodes = new List { ForDeclaration() }; + + while (CurrentToken.Type == TokenType.Comma) { - var nodes = new List { ForDeclaration() }; + Match(Token.Comma); + nodes.Add(ForDeclaration()); + } - while (CurrentToken.Type == TokenType.Comma) - { - Match(Token.Comma); - nodes.Add(ForDeclaration()); - } + return nodes; + } - return nodes; - } + private Statement ForDeclaration() + { + var token = CurrentToken; - private Statement ForDeclaration() + if (token.Type == TokenType.Val) { - var token = CurrentToken; - - if (token.Type == TokenType.Val) - { - throw new ParserException( - "For-loop `val' declarators must be `rw'.", - (_lexer.State.Line, _lexer.State.Column) - ); - } - - if (token.Type == TokenType.Rw) - { - return ReadWriteValStatement(); - } - else if (token.Type == TokenType.Identifier) - { - return new ExpressionStatement(AssignmentExpression()); - } - else throw new ParserException( - "Expected a variable definition or an expression.", + throw new ParserException( + "For-loop `val' declarators must be `rw'.", (_lexer.State.Line, _lexer.State.Column) ); } - - private List ForStatementList() + + if (token.Type == TokenType.Rw) + { + return ReadWriteValStatement(); + } + else if (token.Type == TokenType.Identifier) { - var list = new List { new ExpressionStatement(AssignmentExpression()) }; + return new ExpressionStatement(AssignmentExpression()); + } + else throw new ParserException( + "Expected a variable definition or an expression.", + (_lexer.State.Line, _lexer.State.Column) + ); + } - while (CurrentToken.Type == TokenType.Comma) - { - Match(Token.Comma); - list.Add(new ExpressionStatement(AssignmentExpression())); - } + private List ForStatementList() + { + var list = new List { new ExpressionStatement(AssignmentExpression()) }; - return list; + while (CurrentToken.Type == TokenType.Comma) + { + Match(Token.Comma); + list.Add(new ExpressionStatement(AssignmentExpression())); } + + return list; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Statements/Parser.IfStatement.cs b/Core/EVIL.Grammar/Parsing/Statements/Parser.IfStatement.cs index 2b750c48..5ed18c53 100644 --- a/Core/EVIL.Grammar/Parsing/Statements/Parser.IfStatement.cs +++ b/Core/EVIL.Grammar/Parsing/Statements/Parser.IfStatement.cs @@ -1,76 +1,75 @@ -using EVIL.Grammar.AST.Statements; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Statements; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private IfStatement IfStatement() { - private IfStatement IfStatement() - { - var (line, col) = Match(Token.If); - Match(Token.LParenthesis); + var (line, col) = Match(Token.If); + Match(Token.LParenthesis); - var expression = AssignmentExpression(); + var expression = AssignmentExpression(); - Match(Token.RParenthesis); + Match(Token.RParenthesis); - var node = new IfStatement - { Line = line, Column = col }; + var node = new IfStatement + { Line = line, Column = col }; - node.AddCondition(expression); + node.AddCondition(expression); - if (CurrentToken == Token.RightArrow) - { - node.AddStatement(ExpressionBodyStatement()); - Match(Token.Semicolon); - } - else - { - node.AddStatement(Statement()); - } + if (CurrentToken == Token.RightArrow) + { + node.AddStatement(ExpressionBodyStatement()); + Match(Token.Semicolon); + } + else + { + node.AddStatement(Statement()); + } - while (CurrentToken.Type == TokenType.Elif || CurrentToken.Type == TokenType.Else) + while (CurrentToken.Type == TokenType.Elif || CurrentToken.Type == TokenType.Else) + { + if (CurrentToken.Type == TokenType.Elif) { - if (CurrentToken.Type == TokenType.Elif) - { - Match(Token.Elif); - Match(Token.LParenthesis); + Match(Token.Elif); + Match(Token.LParenthesis); - expression = AssignmentExpression(); + expression = AssignmentExpression(); - Match(Token.RParenthesis); - node.AddCondition(expression); - if (CurrentToken == Token.RightArrow) - { - node.AddStatement(ExpressionBodyStatement()); - Match(Token.Semicolon); - } - else - { - node.AddStatement(Statement()); - } + Match(Token.RParenthesis); + node.AddCondition(expression); + if (CurrentToken == Token.RightArrow) + { + node.AddStatement(ExpressionBodyStatement()); + Match(Token.Semicolon); + } + else + { + node.AddStatement(Statement()); } - else if (CurrentToken.Type == TokenType.Else) + } + else if (CurrentToken.Type == TokenType.Else) + { + Match(Token.Else); + if (CurrentToken == Token.RightArrow) { - Match(Token.Else); - if (CurrentToken == Token.RightArrow) - { - node.SetElseBranch(ExpressionBodyStatement()); - Match(Token.Semicolon); - } - else - { - node.SetElseBranch(Statement()); - } + node.SetElseBranch(ExpressionBodyStatement()); + Match(Token.Semicolon); } else - throw new ParserException( - $"Expected '}}' or 'else' or 'elif', got '{CurrentToken.Value}'", - (_lexer.State.Line, _lexer.State.Column) - ); + { + node.SetElseBranch(Statement()); + } } - - return node; + else + throw new ParserException( + $"Expected '}}' or 'else' or 'elif', got '{CurrentToken.Value}'", + (_lexer.State.Line, _lexer.State.Column) + ); } + + return node; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Statements/Parser.RetStatement.cs b/Core/EVIL.Grammar/Parsing/Statements/Parser.RetStatement.cs index 87a4a74c..85274574 100644 --- a/Core/EVIL.Grammar/Parsing/Statements/Parser.RetStatement.cs +++ b/Core/EVIL.Grammar/Parsing/Statements/Parser.RetStatement.cs @@ -1,27 +1,26 @@ -using EVIL.Grammar.AST.Base; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Statements; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private RetStatement ReturnStatement() { - private RetStatement Return() - { - var (line, col) = Match(Token.Ret); - Expression? expression; + var (line, col) = Match(Token.Ret); + Expression? expression; - if (CurrentToken.Type == TokenType.Semicolon) - { - expression = null; - } - else - { - expression = AssignmentExpression(); - } - - return new RetStatement(expression) - { Line = line, Column = col }; + if (CurrentToken.Type == TokenType.Semicolon) + { + expression = null; } + else + { + expression = AssignmentExpression(); + } + + return new RetStatement(expression) + { Line = line, Column = col }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Statements/Parser.RetryStatement.cs b/Core/EVIL.Grammar/Parsing/Statements/Parser.RetryStatement.cs index 5563b56c..b1b9357a 100644 --- a/Core/EVIL.Grammar/Parsing/Statements/Parser.RetryStatement.cs +++ b/Core/EVIL.Grammar/Parsing/Statements/Parser.RetryStatement.cs @@ -1,7 +1,7 @@ namespace EVIL.Grammar.Parsing; -using AST.Statements; -using Lexical; +using EVIL.Grammar.AST.Statements; +using EVIL.Lexical; public partial class Parser { diff --git a/Core/EVIL.Grammar/Parsing/Statements/Parser.SkipStatement.cs b/Core/EVIL.Grammar/Parsing/Statements/Parser.SkipStatement.cs index 7983f2bb..b738044d 100644 --- a/Core/EVIL.Grammar/Parsing/Statements/Parser.SkipStatement.cs +++ b/Core/EVIL.Grammar/Parsing/Statements/Parser.SkipStatement.cs @@ -1,24 +1,23 @@ -using EVIL.Grammar.AST.Statements; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Statements; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private SkipStatement SkipStatement() { - private SkipStatement Skip() + if (_loopDescent == 0) { - if (_loopDescent == 0) - { - throw new ParserException( - "Unexpected 'skip' outside of a loop.", - (_lexer.State.Line, _lexer.State.Column) - ); - } + throw new ParserException( + "Unexpected 'skip' outside of a loop.", + (_lexer.State.Line, _lexer.State.Column) + ); + } - var (line, col) = Match(Token.Skip); + var (line, col) = Match(Token.Skip); - return new SkipStatement - { Line = line, Column = col }; - } + return new SkipStatement + { Line = line, Column = col }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Statements/Parser.ThrowStatement.cs b/Core/EVIL.Grammar/Parsing/Statements/Parser.ThrowStatement.cs index ebbdff71..81c5da4a 100644 --- a/Core/EVIL.Grammar/Parsing/Statements/Parser.ThrowStatement.cs +++ b/Core/EVIL.Grammar/Parsing/Statements/Parser.ThrowStatement.cs @@ -1,17 +1,16 @@ +namespace EVIL.Grammar.Parsing; + using EVIL.Grammar.AST.Statements; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private ThrowStatement ThrowStatement() { - private ThrowStatement ThrowStatement() - { - var (line, col) = Match(Token.Throw); - var expression = AssignmentExpression(); + var (line, col) = Match(Token.Throw); + var expression = AssignmentExpression(); - return new ThrowStatement(expression) - { Line = line, Column = col }; - } + return new ThrowStatement(expression) + { Line = line, Column = col }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Statements/Parser.TryStatement.cs b/Core/EVIL.Grammar/Parsing/Statements/Parser.TryStatement.cs index 68398ab0..1dcedbe4 100644 --- a/Core/EVIL.Grammar/Parsing/Statements/Parser.TryStatement.cs +++ b/Core/EVIL.Grammar/Parsing/Statements/Parser.TryStatement.cs @@ -1,32 +1,31 @@ +namespace EVIL.Grammar.Parsing; + using EVIL.Grammar.AST.Miscellaneous; using EVIL.Grammar.AST.Statements; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private TryStatement TryStatement() { - private TryStatement TryStatement() - { - var (line, col) = Match(Token.Try); - var protectedStatement = BlockStatement(); - Match(Token.Catch); + var (line, col) = Match(Token.Try); + var protectedStatement = BlockStatement(); + Match(Token.Catch); - IdentifierNode? exceptionObjectIdentifier = null; - if (CurrentToken == Token.LParenthesis) - { - Match(Token.LParenthesis); - exceptionObjectIdentifier = Identifier(); - Match(Token.RParenthesis); - } + IdentifierNode? exceptionObjectIdentifier = null; + if (CurrentToken == Token.LParenthesis) + { + Match(Token.LParenthesis); + exceptionObjectIdentifier = Identifier(); + Match(Token.RParenthesis); + } - var handlerStatement = BlockStatement(); + var handlerStatement = BlockStatement(); - return new TryStatement( - protectedStatement, - exceptionObjectIdentifier, - handlerStatement - ) { Line = line, Column = col }; - } + return new TryStatement( + protectedStatement, + exceptionObjectIdentifier, + handlerStatement + ) { Line = line, Column = col }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Statements/Parser.ValStatement.ReadWrite.cs b/Core/EVIL.Grammar/Parsing/Statements/Parser.ValStatement.ReadWrite.cs index 9a393644..c37f9d02 100644 --- a/Core/EVIL.Grammar/Parsing/Statements/Parser.ValStatement.ReadWrite.cs +++ b/Core/EVIL.Grammar/Parsing/Statements/Parser.ValStatement.ReadWrite.cs @@ -1,14 +1,13 @@ -using EVIL.Grammar.AST.Statements; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Statements; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private ValStatement ReadWriteValStatement() { - private ValStatement ReadWriteValStatement() - { - Match(Token.Rw); - return ValStatement(true); - } - } + Match(Token.Rw); + return ValStatement(true); + } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Statements/Parser.ValStatement.cs b/Core/EVIL.Grammar/Parsing/Statements/Parser.ValStatement.cs index 4274f58f..345a8d68 100644 --- a/Core/EVIL.Grammar/Parsing/Statements/Parser.ValStatement.cs +++ b/Core/EVIL.Grammar/Parsing/Statements/Parser.ValStatement.cs @@ -1,43 +1,42 @@ -using System.Collections.Generic; +namespace EVIL.Grammar.Parsing; + +using System.Collections.Generic; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Miscellaneous; using EVIL.Grammar.AST.Statements; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private ValStatement ValStatement(bool readWrite) { - private ValStatement ValStatement(bool readWrite) - { - var (line, col) = Match(Token.Val); + var (line, col) = Match(Token.Val); - var definitions = new Dictionary(); + var definitions = new Dictionary(); - while (true) - { - var identifier = Identifier(); - - Expression? initializer = null; - if (CurrentToken.Type == TokenType.Assign) - { - Match(Token.Assign); - initializer = AssignmentExpression(); - } + while (true) + { + var identifier = Identifier(); - definitions.Add(identifier, initializer); + Expression? initializer = null; + if (CurrentToken.Type == TokenType.Assign) + { + Match(Token.Assign); + initializer = AssignmentExpression(); + } - if (CurrentToken.Type == TokenType.Comma) - { - Match(Token.Comma); - continue; - } + definitions.Add(identifier, initializer); - break; + if (CurrentToken.Type == TokenType.Comma) + { + Match(Token.Comma); + continue; } - return new ValStatement(definitions, readWrite) - { Line = line, Column = col }; + break; } + + return new ValStatement(definitions, readWrite) + { Line = line, Column = col }; } } \ No newline at end of file diff --git a/Core/EVIL.Grammar/Parsing/Statements/Parser.WhileStatement.cs b/Core/EVIL.Grammar/Parsing/Statements/Parser.WhileStatement.cs index 4b1f73c7..d5e35d82 100644 --- a/Core/EVIL.Grammar/Parsing/Statements/Parser.WhileStatement.cs +++ b/Core/EVIL.Grammar/Parsing/Statements/Parser.WhileStatement.cs @@ -1,21 +1,20 @@ -using EVIL.Grammar.AST.Statements; +namespace EVIL.Grammar.Parsing; + +using EVIL.Grammar.AST.Statements; using EVIL.Lexical; -namespace EVIL.Grammar.Parsing +public partial class Parser { - public partial class Parser + private WhileStatement WhileStatement() { - private WhileStatement WhileStatement() - { - var (line, col) = Match(Token.While); - Match(Token.LParenthesis); - var condition = AssignmentExpression(); - Match(Token.RParenthesis); + var (line, col) = Match(Token.While); + Match(Token.LParenthesis); + var condition = AssignmentExpression(); + Match(Token.RParenthesis); - var statement = LoopDescent(() => Statement()); + var statement = LoopDescent(() => Statement()); - return new WhileStatement(condition, statement) - { Line = line, Column = col }; - } + return new WhileStatement(condition, statement) + { Line = line, Column = col }; } -} +} \ No newline at end of file diff --git a/Core/EVIL.Grammar/Traversal/AstVisitor.cs b/Core/EVIL.Grammar/Traversal/AstVisitor.cs index da9814bd..2a56a4c6 100644 --- a/Core/EVIL.Grammar/Traversal/AstVisitor.cs +++ b/Core/EVIL.Grammar/Traversal/AstVisitor.cs @@ -1,4 +1,6 @@ -using System; +namespace EVIL.Grammar.Traversal; + +using System; using System.Collections.Generic; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Constants; @@ -7,138 +9,135 @@ using EVIL.Grammar.AST.Statements; using EVIL.Grammar.AST.Statements.TopLevel; -namespace EVIL.Grammar.Traversal +public abstract class AstVisitor { - public abstract class AstVisitor - { - protected Dictionary Handlers { get; } - - protected delegate void NodeHandler(AstNode node); + protected Dictionary Handlers { get; } - protected AstVisitor() - { -#nullable disable - Handlers = new() - { - { typeof(ArgumentList), (n) => Visit((ArgumentList)n) }, - { typeof(AttributeList), (n) => Visit((AttributeList)n) }, - { typeof(ParameterList), (n) => Visit((ParameterList)n) }, - { typeof(BlockStatement), (n) => Visit((BlockStatement)n) }, - { typeof(ConditionalExpression), (n) => Visit((ConditionalExpression)n) }, - { typeof(CoalescingExpression), (n) => Visit((CoalescingExpression)n) }, - { typeof(NumberConstant), (n) => Visit((NumberConstant)n) }, - { typeof(StringConstant), (n) => Visit((StringConstant)n) }, - { typeof(NilConstant), (n) => Visit((NilConstant)n) }, - { typeof(BooleanConstant), (n) => Visit((BooleanConstant)n) }, - { typeof(TypeCodeConstant), (n) => Visit((TypeCodeConstant)n) }, - { typeof(AssignmentExpression), (n) => Visit((AssignmentExpression)n) }, - { typeof(BinaryExpression), (n) => Visit((BinaryExpression)n) }, - { typeof(UnaryExpression), (n) => Visit((UnaryExpression)n) }, - { typeof(SymbolReferenceExpression), (n) => Visit((SymbolReferenceExpression)n) }, - { typeof(ValStatement), (n) => Visit((ValStatement)n) }, - { typeof(FnIndexedStatement), (n) => Visit((FnIndexedStatement)n) }, - { typeof(FnStatement), (n) => Visit((FnStatement)n) }, - { typeof(FnTargetedStatement), (n) => Visit((FnTargetedStatement)n) }, - { typeof(InvocationExpression), (n) => Visit((InvocationExpression)n) }, - { typeof(IfStatement), (n) => Visit((IfStatement)n) }, - { typeof(ForStatement), (n) => Visit((ForStatement)n) }, - { typeof(DoWhileStatement), (n) => Visit((DoWhileStatement)n) }, - { typeof(WhileStatement), (n) => Visit((WhileStatement)n) }, - { typeof(EachStatement), (n) => Visit((EachStatement)n) }, - { typeof(RetStatement), (n) => Visit((RetStatement)n) }, - { typeof(BreakStatement), (n) => Visit((BreakStatement)n) }, - { typeof(SkipStatement), (n) => Visit((SkipStatement)n) }, - { typeof(TryStatement), (n) => Visit((TryStatement)n) }, - { typeof(ThrowStatement), (n) => Visit((ThrowStatement)n) }, - { typeof(RetryStatement), (n) => Visit((RetryStatement)n) }, - { typeof(TableExpression), (n) => Visit((TableExpression)n) }, - { typeof(ArrayExpression), (n) => Visit((ArrayExpression)n) }, - { typeof(ErrorExpression), (n) => Visit((ErrorExpression)n) }, - { typeof(SelfExpression), (n) => Visit((SelfExpression)n) }, - { typeof(SelfFnExpression), (n) => Visit((SelfFnExpression)n) }, - { typeof(SelfInvocationExpression), (n) => Visit((SelfInvocationExpression)n) }, - { typeof(IndexerExpression), (n) => Visit((IndexerExpression)n) }, - { typeof(IncrementationExpression), (n) => Visit((IncrementationExpression)n) }, - { typeof(DecrementationExpression), (n) => Visit((DecrementationExpression)n) }, - { typeof(ExpressionStatement), (n) => Visit((ExpressionStatement)n) }, - { typeof(AttributeNode), (n) => Visit((AttributeNode)n) }, - { typeof(TypeOfExpression), (n) => Visit((TypeOfExpression)n) }, - { typeof(YieldExpression), (n) => Visit((YieldExpression)n) }, - { typeof(ExpressionBodyStatement), (n) => Visit((ExpressionBodyStatement)n) }, - { typeof(ExtraArgumentsExpression), (n) => Visit((ExtraArgumentsExpression)n) }, - { typeof(FnExpression), (n) => Visit((FnExpression)n) }, - { typeof(IsExpression), (n) => Visit((IsExpression)n) }, - { typeof(ByExpression), (n) => Visit((ByExpression)n) }, - { typeof(WithExpression), (n) => Visit((WithExpression)n) } - }; -#nullable enable - } + protected delegate void NodeHandler(AstNode node); - public virtual void Visit(AstNode node) + protected AstVisitor() + { + #nullable disable + Handlers = new() { - var type = node.GetType(); + { typeof(ArgumentList), (n) => Visit((ArgumentList)n) }, + { typeof(AttributeList), (n) => Visit((AttributeList)n) }, + { typeof(ParameterList), (n) => Visit((ParameterList)n) }, + { typeof(BlockStatement), (n) => Visit((BlockStatement)n) }, + { typeof(ConditionalExpression), (n) => Visit((ConditionalExpression)n) }, + { typeof(CoalescingExpression), (n) => Visit((CoalescingExpression)n) }, + { typeof(NumberConstant), (n) => Visit((NumberConstant)n) }, + { typeof(StringConstant), (n) => Visit((StringConstant)n) }, + { typeof(NilConstant), (n) => Visit((NilConstant)n) }, + { typeof(BooleanConstant), (n) => Visit((BooleanConstant)n) }, + { typeof(TypeCodeConstant), (n) => Visit((TypeCodeConstant)n) }, + { typeof(AssignmentExpression), (n) => Visit((AssignmentExpression)n) }, + { typeof(BinaryExpression), (n) => Visit((BinaryExpression)n) }, + { typeof(UnaryExpression), (n) => Visit((UnaryExpression)n) }, + { typeof(SymbolReferenceExpression), (n) => Visit((SymbolReferenceExpression)n) }, + { typeof(ValStatement), (n) => Visit((ValStatement)n) }, + { typeof(FnIndexedStatement), (n) => Visit((FnIndexedStatement)n) }, + { typeof(FnStatement), (n) => Visit((FnStatement)n) }, + { typeof(FnTargetedStatement), (n) => Visit((FnTargetedStatement)n) }, + { typeof(InvocationExpression), (n) => Visit((InvocationExpression)n) }, + { typeof(IfStatement), (n) => Visit((IfStatement)n) }, + { typeof(ForStatement), (n) => Visit((ForStatement)n) }, + { typeof(DoWhileStatement), (n) => Visit((DoWhileStatement)n) }, + { typeof(WhileStatement), (n) => Visit((WhileStatement)n) }, + { typeof(EachStatement), (n) => Visit((EachStatement)n) }, + { typeof(RetStatement), (n) => Visit((RetStatement)n) }, + { typeof(BreakStatement), (n) => Visit((BreakStatement)n) }, + { typeof(SkipStatement), (n) => Visit((SkipStatement)n) }, + { typeof(TryStatement), (n) => Visit((TryStatement)n) }, + { typeof(ThrowStatement), (n) => Visit((ThrowStatement)n) }, + { typeof(RetryStatement), (n) => Visit((RetryStatement)n) }, + { typeof(TableExpression), (n) => Visit((TableExpression)n) }, + { typeof(ArrayExpression), (n) => Visit((ArrayExpression)n) }, + { typeof(ErrorExpression), (n) => Visit((ErrorExpression)n) }, + { typeof(SelfExpression), (n) => Visit((SelfExpression)n) }, + { typeof(SelfFnExpression), (n) => Visit((SelfFnExpression)n) }, + { typeof(SelfInvocationExpression), (n) => Visit((SelfInvocationExpression)n) }, + { typeof(IndexerExpression), (n) => Visit((IndexerExpression)n) }, + { typeof(IncrementationExpression), (n) => Visit((IncrementationExpression)n) }, + { typeof(DecrementationExpression), (n) => Visit((DecrementationExpression)n) }, + { typeof(ExpressionStatement), (n) => Visit((ExpressionStatement)n) }, + { typeof(AttributeNode), (n) => Visit((AttributeNode)n) }, + { typeof(TypeOfExpression), (n) => Visit((TypeOfExpression)n) }, + { typeof(YieldExpression), (n) => Visit((YieldExpression)n) }, + { typeof(ExpressionBodyStatement), (n) => Visit((ExpressionBodyStatement)n) }, + { typeof(ExtraArgumentsExpression), (n) => Visit((ExtraArgumentsExpression)n) }, + { typeof(FnExpression), (n) => Visit((FnExpression)n) }, + { typeof(IsExpression), (n) => Visit((IsExpression)n) }, + { typeof(ByExpression), (n) => Visit((ByExpression)n) }, + { typeof(WithExpression), (n) => Visit((WithExpression)n) } + }; + #nullable enable + } - if (!Handlers.ContainsKey(type)) - { - throw new Exception( - $"Unknown node type '{type.Name}'. " + - $"It might be that you forgor to add a handler for it." - ); - } + public virtual void Visit(AstNode node) + { + var type = node.GetType(); - Handlers[type](node); + if (!Handlers.ContainsKey(type)) + { + throw new Exception( + $"Unknown node type '{type.Name}'. " + + $"It might be that you forgor to add a handler for it." + ); } - public abstract void Visit(ProgramNode programNode); - public abstract void Visit(AttributeList attributeList); - public abstract void Visit(ParameterList parameterList); - public abstract void Visit(ArgumentList argumentList); - public abstract void Visit(BlockStatement blockStatement); - public abstract void Visit(ConditionalExpression conditionalExpression); - public abstract void Visit(CoalescingExpression coalescingExpression); - public abstract void Visit(NumberConstant numberConstant); - public abstract void Visit(StringConstant stringConstant); - public abstract void Visit(NilConstant nilConstant); - public abstract void Visit(BooleanConstant booleanConstant); - public abstract void Visit(TypeCodeConstant typeCodeConstant); - public abstract void Visit(AssignmentExpression assignmentExpression); - public abstract void Visit(BinaryExpression binaryExpression); - public abstract void Visit(UnaryExpression unaryExpression); - public abstract void Visit(SymbolReferenceExpression symbolReferenceExpression); - public abstract void Visit(ValStatement valStatement); - public abstract void Visit(FnIndexedStatement fnIndexedStatement); - public abstract void Visit(FnStatement fnStatement); - public abstract void Visit(FnTargetedStatement fnTargetedStatement); - public abstract void Visit(InvocationExpression invocationExpression); - public abstract void Visit(IfStatement ifStatement); - public abstract void Visit(ForStatement forStatement); - public abstract void Visit(DoWhileStatement doWhileStatement); - public abstract void Visit(WhileStatement whileStatement); - public abstract void Visit(EachStatement eachStatement); - public abstract void Visit(RetStatement retStatement); - public abstract void Visit(BreakStatement breakStatement); - public abstract void Visit(SkipStatement skipStatement); - public abstract void Visit(TryStatement tryStatement); - public abstract void Visit(ThrowStatement throwStatement); - public abstract void Visit(RetryStatement retryStatement); - public abstract void Visit(TableExpression tableExpression); - public abstract void Visit(ArrayExpression arrayExpression); - public abstract void Visit(ErrorExpression errorExpression); - public abstract void Visit(SelfExpression selfExpression); - public abstract void Visit(SelfFnExpression selfFnExpression); - public abstract void Visit(SelfInvocationExpression selfInvocationExpression); - public abstract void Visit(IndexerExpression indexerExpression); - public abstract void Visit(IncrementationExpression incrementationExpression); - public abstract void Visit(DecrementationExpression decrementationExpression); - public abstract void Visit(ExpressionStatement expressionStatement); - public abstract void Visit(AttributeNode attributeNode); - public abstract void Visit(TypeOfExpression typeOfExpression); - public abstract void Visit(YieldExpression yieldExpression); - public abstract void Visit(ExpressionBodyStatement expressionBodyStatement); - public abstract void Visit(ExtraArgumentsExpression extraArgumentsExpression); - public abstract void Visit(FnExpression fnExpression); - public abstract void Visit(IsExpression isExpression); - public abstract void Visit(ByExpression byExpression); - public abstract void Visit(WithExpression withExpression); + Handlers[type](node); } + + public abstract void Visit(ProgramNode programNode); + public abstract void Visit(AttributeList attributeList); + public abstract void Visit(ParameterList parameterList); + public abstract void Visit(ArgumentList argumentList); + public abstract void Visit(BlockStatement blockStatement); + public abstract void Visit(ConditionalExpression conditionalExpression); + public abstract void Visit(CoalescingExpression coalescingExpression); + public abstract void Visit(NumberConstant numberConstant); + public abstract void Visit(StringConstant stringConstant); + public abstract void Visit(NilConstant nilConstant); + public abstract void Visit(BooleanConstant booleanConstant); + public abstract void Visit(TypeCodeConstant typeCodeConstant); + public abstract void Visit(AssignmentExpression assignmentExpression); + public abstract void Visit(BinaryExpression binaryExpression); + public abstract void Visit(UnaryExpression unaryExpression); + public abstract void Visit(SymbolReferenceExpression symbolReferenceExpression); + public abstract void Visit(ValStatement valStatement); + public abstract void Visit(FnIndexedStatement fnIndexedStatement); + public abstract void Visit(FnStatement fnStatement); + public abstract void Visit(FnTargetedStatement fnTargetedStatement); + public abstract void Visit(InvocationExpression invocationExpression); + public abstract void Visit(IfStatement ifStatement); + public abstract void Visit(ForStatement forStatement); + public abstract void Visit(DoWhileStatement doWhileStatement); + public abstract void Visit(WhileStatement whileStatement); + public abstract void Visit(EachStatement eachStatement); + public abstract void Visit(RetStatement retStatement); + public abstract void Visit(BreakStatement breakStatement); + public abstract void Visit(SkipStatement skipStatement); + public abstract void Visit(TryStatement tryStatement); + public abstract void Visit(ThrowStatement throwStatement); + public abstract void Visit(RetryStatement retryStatement); + public abstract void Visit(TableExpression tableExpression); + public abstract void Visit(ArrayExpression arrayExpression); + public abstract void Visit(ErrorExpression errorExpression); + public abstract void Visit(SelfExpression selfExpression); + public abstract void Visit(SelfFnExpression selfFnExpression); + public abstract void Visit(SelfInvocationExpression selfInvocationExpression); + public abstract void Visit(IndexerExpression indexerExpression); + public abstract void Visit(IncrementationExpression incrementationExpression); + public abstract void Visit(DecrementationExpression decrementationExpression); + public abstract void Visit(ExpressionStatement expressionStatement); + public abstract void Visit(AttributeNode attributeNode); + public abstract void Visit(TypeOfExpression typeOfExpression); + public abstract void Visit(YieldExpression yieldExpression); + public abstract void Visit(ExpressionBodyStatement expressionBodyStatement); + public abstract void Visit(ExtraArgumentsExpression extraArgumentsExpression); + public abstract void Visit(FnExpression fnExpression); + public abstract void Visit(IsExpression isExpression); + public abstract void Visit(ByExpression byExpression); + public abstract void Visit(WithExpression withExpression); } \ No newline at end of file diff --git a/Core/EVIL.Lexical/Lexer.cs b/Core/EVIL.Lexical/Lexer.cs index e3d89a7b..d03a9673 100644 --- a/Core/EVIL.Lexical/Lexer.cs +++ b/Core/EVIL.Lexical/Lexer.cs @@ -1,700 +1,699 @@ -using System; +namespace EVIL.Lexical; + +using System; using System.Globalization; using System.Text; -namespace EVIL.Lexical +public class Lexer { - public class Lexer - { - private const string HexAlphabet = "abcdefABCDEF0123456789"; + private const string HexAlphabet = "abcdefABCDEF0123456789"; - private string? _sourceCode; + private string? _sourceCode; - public LexerState State { get; internal set; } = new(); + public LexerState State { get; internal set; } = new(); - public LexerState CopyState() + public LexerState CopyState() + { + return new() { - return new() - { - Character = State.Character, - Column = State.Column, - CurrentToken = State.CurrentToken, - Line = State.Line, - Pointer = State.Pointer, - PreviousToken = State.PreviousToken - }; - } + Character = State.Character, + Column = State.Column, + CurrentToken = State.CurrentToken, + Line = State.Line, + Pointer = State.Pointer, + PreviousToken = State.PreviousToken + }; + } - public void LoadSource(string source) - { - _sourceCode = source; - State.Reset(); + public void LoadSource(string source) + { + _sourceCode = source; + State.Reset(); - if (_sourceCode.Length != 0) - State.Character = _sourceCode[0]; + if (_sourceCode.Length != 0) + State.Character = _sourceCode[0]; - NextToken(); - } + NextToken(); + } - public void NextToken() - { - SkipWhitespace(); + public void NextToken() + { + SkipWhitespace(); - State.PreviousToken = State.CurrentToken; - var (line, col) = (State.Line, State.Column); + State.PreviousToken = State.CurrentToken; + var (line, col) = (State.Line, State.Column); - switch (State.Character) - { - case '.' when Peek() == '.' && Peek(2) == '.': - Advance(); - Advance(); - State.CurrentToken = Token.Ellipsis with { Line = line, Column = col }; - break; - case '-' when Peek() == '>': - Advance(); - State.CurrentToken = Token.RightArrow with { Line = line, Column = col }; - break; - case '-' when Peek() == '-': - Advance(); - State.CurrentToken = Token.Decrement with { Line = line, Column = col }; - break; - case '-' when Peek() == '=': - Advance(); - State.CurrentToken = Token.AssignSubtract with { Line = line, Column = col }; - break; - case '-': - State.CurrentToken = Token.Minus with { Line = line, Column = col }; - break; - case '.' when char.IsDigit(Peek()): - State.CurrentToken = GetDecimalNumber() with { Line = line, Column = col }; - return; - case '.': - State.CurrentToken = Token.Dot with { Line = line, Column = col }; - break; - case '+' when Peek() == '+': - Advance(); - State.CurrentToken = Token.Increment with { Line = line, Column = col }; - break; - case '+' when Peek() == '=': - Advance(); - State.CurrentToken = Token.AssignAdd with { Line = line, Column = col }; - break; - case '+': - State.CurrentToken = Token.Plus with { Line = line, Column = col }; - break; - case '*' when Peek() == '=': - Advance(); - State.CurrentToken = Token.AssignMultiply with { Line = line, Column = col }; - break; - case '*': - State.CurrentToken = Token.Multiply with { Line = line, Column = col }; - break; - case '/' when Peek() == '/': - SkipLineComment(); + switch (State.Character) + { + case '.' when Peek() == '.' && Peek(2) == '.': + Advance(); + Advance(); + State.CurrentToken = Token.Ellipsis with { Line = line, Column = col }; + break; + case '-' when Peek() == '>': + Advance(); + State.CurrentToken = Token.RightArrow with { Line = line, Column = col }; + break; + case '-' when Peek() == '-': + Advance(); + State.CurrentToken = Token.Decrement with { Line = line, Column = col }; + break; + case '-' when Peek() == '=': + Advance(); + State.CurrentToken = Token.AssignSubtract with { Line = line, Column = col }; + break; + case '-': + State.CurrentToken = Token.Minus with { Line = line, Column = col }; + break; + case '.' when char.IsDigit(Peek()): + State.CurrentToken = GetDecimalNumber() with { Line = line, Column = col }; + return; + case '.': + State.CurrentToken = Token.Dot with { Line = line, Column = col }; + break; + case '+' when Peek() == '+': + Advance(); + State.CurrentToken = Token.Increment with { Line = line, Column = col }; + break; + case '+' when Peek() == '=': + Advance(); + State.CurrentToken = Token.AssignAdd with { Line = line, Column = col }; + break; + case '+': + State.CurrentToken = Token.Plus with { Line = line, Column = col }; + break; + case '*' when Peek() == '=': + Advance(); + State.CurrentToken = Token.AssignMultiply with { Line = line, Column = col }; + break; + case '*': + State.CurrentToken = Token.Multiply with { Line = line, Column = col }; + break; + case '/' when Peek() == '/': + SkipLineComment(); - Advance(); - NextToken(); + Advance(); + NextToken(); - return; - case '/' when Peek() == '*': - SkipBlockComment(); + return; + case '/' when Peek() == '*': + SkipBlockComment(); - Advance(); - NextToken(); + Advance(); + NextToken(); - return; - case '/' when Peek() == '=': - Advance(); - State.CurrentToken = Token.AssignDivide with { Line = line, Column = col }; - break; - case '/': - State.CurrentToken = Token.Divide with { Line = line, Column = col }; - break; - case '?' when Peek() == '?' && Peek(2) == '=': - Advance(); - Advance(); - State.CurrentToken = Token.AssignCoalesce with { Line = line, Column = col }; - break; - case '?' when Peek() == '?': - Advance(); - State.CurrentToken = Token.DoubleQuestionMark with { Line = line, Column = col }; - break; - case '?': - State.CurrentToken = Token.QuestionMark with { Line = line, Column = col }; - break; - case '%' when Peek() == '=': - Advance(); - State.CurrentToken = Token.AssignModulo with { Line = line, Column = col }; - break; - case '%': - State.CurrentToken = Token.Modulo with { Line = line, Column = col }; - break; - case '=' when Peek() == '>': - Advance(); - State.CurrentToken = Token.Associate with { Line = line, Column = col }; - break; - case '=' when Peek() == '=': - Advance(); - State.CurrentToken = Token.Equal with { Line = line, Column = col }; - break; - case '=': - State.CurrentToken = Token.Assign with { Line = line, Column = col }; - break; - case '<' when Peek() == '=' && Peek(2) == '=' && Peek(3) == '>': - Advance(); - Advance(); - Advance(); - State.CurrentToken = Token.DeepEqual with { Line = line, Column = col }; - break; - case '<' when Peek() == '!' && Peek(2) == '=' && Peek(3) == '>': - Advance(); - Advance(); - Advance(); - State.CurrentToken = Token.DeepNotEqual with { Line = line, Column = col }; - break; - case '<' when Peek() == '=': - Advance(); - State.CurrentToken = Token.LessThanOrEqual with { Line = line, Column = col }; - break; - case '<' when Peek() == '<': + return; + case '/' when Peek() == '=': + Advance(); + State.CurrentToken = Token.AssignDivide with { Line = line, Column = col }; + break; + case '/': + State.CurrentToken = Token.Divide with { Line = line, Column = col }; + break; + case '?' when Peek() == '?' && Peek(2) == '=': + Advance(); + Advance(); + State.CurrentToken = Token.AssignCoalesce with { Line = line, Column = col }; + break; + case '?' when Peek() == '?': + Advance(); + State.CurrentToken = Token.DoubleQuestionMark with { Line = line, Column = col }; + break; + case '?': + State.CurrentToken = Token.QuestionMark with { Line = line, Column = col }; + break; + case '%' when Peek() == '=': + Advance(); + State.CurrentToken = Token.AssignModulo with { Line = line, Column = col }; + break; + case '%': + State.CurrentToken = Token.Modulo with { Line = line, Column = col }; + break; + case '=' when Peek() == '>': + Advance(); + State.CurrentToken = Token.Associate with { Line = line, Column = col }; + break; + case '=' when Peek() == '=': + Advance(); + State.CurrentToken = Token.Equal with { Line = line, Column = col }; + break; + case '=': + State.CurrentToken = Token.Assign with { Line = line, Column = col }; + break; + case '<' when Peek() == '=' && Peek(2) == '=' && Peek(3) == '>': + Advance(); + Advance(); + Advance(); + State.CurrentToken = Token.DeepEqual with { Line = line, Column = col }; + break; + case '<' when Peek() == '!' && Peek(2) == '=' && Peek(3) == '>': + Advance(); + Advance(); + Advance(); + State.CurrentToken = Token.DeepNotEqual with { Line = line, Column = col }; + break; + case '<' when Peek() == '=': + Advance(); + State.CurrentToken = Token.LessThanOrEqual with { Line = line, Column = col }; + break; + case '<' when Peek() == '<': + { + Advance(); + if (Peek() == '=') { Advance(); - if (Peek() == '=') - { - Advance(); - State.CurrentToken = Token.AssignShiftLeft with { Line = line, Column = col }; - } - else - { - State.CurrentToken = Token.ShiftLeft with { Line = line, Column = col }; - } - - break; + State.CurrentToken = Token.AssignShiftLeft with { Line = line, Column = col }; } - case '<': - State.CurrentToken = Token.LessThan with { Line = line, Column = col }; - break; - case '>' when Peek() == '=': - Advance(); - State.CurrentToken = Token.GreaterThanOrEqual with { Line = line, Column = col }; - break; - case '>' when Peek() == '>': + else + { + State.CurrentToken = Token.ShiftLeft with { Line = line, Column = col }; + } + + break; + } + case '<': + State.CurrentToken = Token.LessThan with { Line = line, Column = col }; + break; + case '>' when Peek() == '=': + Advance(); + State.CurrentToken = Token.GreaterThanOrEqual with { Line = line, Column = col }; + break; + case '>' when Peek() == '>': + { + Advance(); + if (Peek() == '=') { Advance(); - if (Peek() == '=') - { - Advance(); - State.CurrentToken = Token.AssignShiftRight with { Line = line, Column = col }; - } - else - { - State.CurrentToken = Token.ShiftRight with { Line = line, Column = col }; - } + State.CurrentToken = Token.AssignShiftRight with { Line = line, Column = col }; + } + else + { + State.CurrentToken = Token.ShiftRight with { Line = line, Column = col }; + } - break; + break; + } + case '>': + State.CurrentToken = Token.GreaterThan with { Line = line, Column = col }; + break; + case '&' when Peek() == '&': + Advance(); + State.CurrentToken = Token.LogicalAnd with { Line = line, Column = col }; + break; + case '&' when Peek() == '=': + Advance(); + State.CurrentToken = Token.AssignBitwiseAnd with { Line = line, Column = col }; + break; + case '&': + State.CurrentToken = Token.BitwiseAnd with { Line = line, Column = col }; + break; + case '|' when Peek() == '|': + Advance(); + State.CurrentToken = Token.LogicalOr with { Line = line, Column = col }; + break; + case '|' when Peek() == '=': + Advance(); + State.CurrentToken = Token.AssignBitwiseOr with { Line = line, Column = col }; + break; + case '|': + State.CurrentToken = Token.BitwiseOr with { Line = line, Column = col }; + break; + case '^' when Peek() == '=': + Advance(); + State.CurrentToken = Token.AssignBitwiseXor with { Line = line, Column = col }; + break; + case '^': + State.CurrentToken = Token.BitwiseXor with { Line = line, Column = col }; + break; + case '~': + State.CurrentToken = Token.BitwiseNot with { Line = line, Column = col }; + break; + case ',': + State.CurrentToken = Token.Comma with { Line = line, Column = col }; + break; + case ':' when Peek() == ':': + Advance(); + State.CurrentToken = Token.DoubleColon with { Line = line, Column = col }; + break; + case ':': + State.CurrentToken = Token.Colon with { Line = line, Column = col }; + break; + case ';': + State.CurrentToken = Token.Semicolon with { Line = line, Column = col }; + break; + case '(': + State.CurrentToken = Token.LParenthesis with { Line = line, Column = col }; + break; + case ')': + State.CurrentToken = Token.RParenthesis with { Line = line, Column = col }; + break; + case '!' when Peek() == 'i' && Peek(2) == 'n' && char.IsWhiteSpace(Peek(3)): + Advance(); + Advance(); + State.CurrentToken = Token.NotIn with { Line = line, Column = col }; + break; + case '!' when Peek() == 'i' && Peek(2) == 's' && char.IsWhiteSpace(Peek(3)): + Advance(); + Advance(); + State.CurrentToken = Token.IsNot with { Line = line, Column = col }; + break; + case '!' when Peek() == '=': + Advance(); + State.CurrentToken = Token.NotEqual with { Line = line, Column = col }; + break; + case '!': + State.CurrentToken = Token.LogicalNot with { Line = line, Column = col }; + break; + case '[': + State.CurrentToken = Token.LBracket with { Line = line, Column = col }; + break; + case ']': + State.CurrentToken = Token.RBracket with { Line = line, Column = col }; + break; + case '{': + State.CurrentToken = Token.LBrace with { Line = line, Column = col }; + break; + case '}': + State.CurrentToken = Token.RBrace with { Line = line, Column = col }; + break; + case (char)0: + State.CurrentToken = Token.EOF with { Line = line, Column = col }; + break; + case '"': + case '\'': + State.CurrentToken = GetString() with { Line = line, Column = col }; + break; + case '#' when Peek() == '[': + Advance(); + State.CurrentToken = Token.AttributeList with { Line = line, Column = col }; + break; + case '#': + State.CurrentToken = Token.Length with { Line = line, Column = col }; + break; + case '@': + State.CurrentToken = Token.AsString with { Line = line, Column = col }; + break; + case '$': + State.CurrentToken = Token.AsNumber with { Line = line, Column = col }; + break; + + default: + { + if (char.IsLetter(State.Character) || State.Character == '_') + { + State.CurrentToken = GetIdentifierOrKeyword() with { Line = line, Column = col }; + return; } - case '>': - State.CurrentToken = Token.GreaterThan with { Line = line, Column = col }; - break; - case '&' when Peek() == '&': - Advance(); - State.CurrentToken = Token.LogicalAnd with { Line = line, Column = col }; - break; - case '&' when Peek() == '=': - Advance(); - State.CurrentToken = Token.AssignBitwiseAnd with { Line = line, Column = col }; - break; - case '&': - State.CurrentToken = Token.BitwiseAnd with { Line = line, Column = col }; - break; - case '|' when Peek() == '|': - Advance(); - State.CurrentToken = Token.LogicalOr with { Line = line, Column = col }; - break; - case '|' when Peek() == '=': - Advance(); - State.CurrentToken = Token.AssignBitwiseOr with { Line = line, Column = col }; - break; - case '|': - State.CurrentToken = Token.BitwiseOr with { Line = line, Column = col }; - break; - case '^' when Peek() == '=': - Advance(); - State.CurrentToken = Token.AssignBitwiseXor with { Line = line, Column = col }; - break; - case '^': - State.CurrentToken = Token.BitwiseXor with { Line = line, Column = col }; - break; - case '~': - State.CurrentToken = Token.BitwiseNot with { Line = line, Column = col }; - break; - case ',': - State.CurrentToken = Token.Comma with { Line = line, Column = col }; - break; - case ':' when Peek() == ':': - Advance(); - State.CurrentToken = Token.DoubleColon with { Line = line, Column = col }; - break; - case ':': - State.CurrentToken = Token.Colon with { Line = line, Column = col }; - break; - case ';': - State.CurrentToken = Token.Semicolon with { Line = line, Column = col }; - break; - case '(': - State.CurrentToken = Token.LParenthesis with { Line = line, Column = col }; - break; - case ')': - State.CurrentToken = Token.RParenthesis with { Line = line, Column = col }; - break; - case '!' when Peek() == 'i' && Peek(2) == 'n' && char.IsWhiteSpace(Peek(3)): - Advance(); - Advance(); - State.CurrentToken = Token.NotIn with { Line = line, Column = col }; - break; - case '!' when Peek() == 'i' && Peek(2) == 's' && char.IsWhiteSpace(Peek(3)): - Advance(); - Advance(); - State.CurrentToken = Token.IsNot with { Line = line, Column = col }; - break; - case '!' when Peek() == '=': - Advance(); - State.CurrentToken = Token.NotEqual with { Line = line, Column = col }; - break; - case '!': - State.CurrentToken = Token.LogicalNot with { Line = line, Column = col }; - break; - case '[': - State.CurrentToken = Token.LBracket with { Line = line, Column = col }; - break; - case ']': - State.CurrentToken = Token.RBracket with { Line = line, Column = col }; - break; - case '{': - State.CurrentToken = Token.LBrace with { Line = line, Column = col }; - break; - case '}': - State.CurrentToken = Token.RBrace with { Line = line, Column = col }; - break; - case (char)0: - State.CurrentToken = Token.EOF with { Line = line, Column = col }; - break; - case '"': - case '\'': - State.CurrentToken = GetString() with { Line = line, Column = col }; - break; - case '#' when Peek() == '[': - Advance(); - State.CurrentToken = Token.AttributeList with { Line = line, Column = col }; - break; - case '#': - State.CurrentToken = Token.Length with { Line = line, Column = col }; - break; - case '@': - State.CurrentToken = Token.AsString with { Line = line, Column = col }; - break; - case '$': - State.CurrentToken = Token.AsNumber with { Line = line, Column = col }; - break; - - default: + else if (char.IsDigit(State.Character)) { - if (char.IsLetter(State.Character) || State.Character == '_') + if (State.Character == '0') { - State.CurrentToken = GetIdentifierOrKeyword() with { Line = line, Column = col }; - return; - } - else if (char.IsDigit(State.Character)) - { - if (State.Character == '0') + if (Peek() == 'x') { - if (Peek() == 'x') - { - Advance(); - Advance(); - - State.CurrentToken = GetHexNumber() with { Line = line, Column = col }; - return; - } - } + Advance(); + Advance(); - State.CurrentToken = GetDecimalNumber() with { Line = line, Column = col }; - return; + State.CurrentToken = GetHexNumber() with { Line = line, Column = col }; + return; + } } - } - throw new LexerException($"Unexpected token '{State.Character}'", col, line); + State.CurrentToken = GetDecimalNumber() with { Line = line, Column = col }; + return; + } } - Advance(); + throw new LexerException($"Unexpected token '{State.Character}'", col, line); } - public Token PeekToken(int howFar) - { - var prevState = CopyState(); - var token = Token.Empty; + Advance(); + } - for (var i = 0; i < howFar; i++) - { - NextToken(); - token = State.CurrentToken; - } + public Token PeekToken(int howFar) + { + var prevState = CopyState(); + var token = Token.Empty; - State = prevState; - return token; + for (var i = 0; i < howFar; i++) + { + NextToken(); + token = State.CurrentToken; } - private Token GetHexNumber() - { - var number = string.Empty; + State = prevState; + return token; + } - while (IsLegalHexNumberCharacter(State.Character)) - { - number += State.Character; - Advance(); - } + private Token GetHexNumber() + { + var number = string.Empty; - return Token.CreateHexInteger(number); + while (IsLegalHexNumberCharacter(State.Character)) + { + number += State.Character; + Advance(); } - private Token GetDecimalNumber() - { - var number = string.Empty; + return Token.CreateHexInteger(number); + } - if (char.IsDigit(State.Character) || State.Character == '.') - { - var foundDecimalSeparator = false; - var foundExponent = false; - var foundExponentSign = false; + private Token GetDecimalNumber() + { + var number = string.Empty; + + if (char.IsDigit(State.Character) || State.Character == '.') + { + var foundDecimalSeparator = false; + var foundExponent = false; + var foundExponentSign = false; - while (char.IsDigit(State.Character) || State.Character == '.' - || State.Character == 'e' - || State.Character == 'E' - || State.Character == '-' - || State.Character == '+') + while (char.IsDigit(State.Character) || State.Character == '.' + || State.Character == 'e' + || State.Character == 'E' + || State.Character == '-' + || State.Character == '+') + { + if (State.Character == '.') { - if (State.Character == '.') + if (foundDecimalSeparator) { - if (foundDecimalSeparator) - { - throw new LexerException( - $"Character `{State.Character}' was unexpected at this time.", - State.Line, - State.Column - ); - } - - foundDecimalSeparator = true; + throw new LexerException( + $"Character `{State.Character}' was unexpected at this time.", + State.Line, + State.Column + ); } + + foundDecimalSeparator = true; + } - if (State.Character == 'e' || State.Character == 'E') + if (State.Character == 'e' || State.Character == 'E') + { + if (foundExponent) { - if (foundExponent) - { - throw new LexerException( - $"Character `{State.Character}' was unexpected at this time.", - State.Line, - State.Column - ); - } - - foundExponent = true; + throw new LexerException( + $"Character `{State.Character}' was unexpected at this time.", + State.Line, + State.Column + ); } + + foundExponent = true; + } - if (State.Character == '+' || State.Character == '-') + if (State.Character == '+' || State.Character == '-') + { + if (!foundExponent || foundExponentSign) { - if (!foundExponent || foundExponentSign) - { - throw new LexerException( - $"Character `{State.Character}' was unexpected at this time.", - State.Line, - State.Column - ); - } - - foundExponent = true; + throw new LexerException( + $"Character `{State.Character}' was unexpected at this time.", + State.Line, + State.Column + ); } - - number += State.Character; - Advance(); - } - } - else - { - throw new LexerException( - $"Character `{State.Character}' was unexpected at this time.", - State.Line, - State.Column - ); - } - try - { - return Token.CreateNumber(number); - } - catch (FormatException) - { - throw new LexerException($"Malformed numeric constant `{number}'.", State.Line, State.Column); - } - } - - private Token GetIdentifierOrKeyword() - { - var str = string.Empty; - - while (IsLegalIdentifierCharacter(State.Character)) - { - str += State.Character; + foundExponent = true; + } + + number += State.Character; Advance(); } - - return str switch - { - "fn" => Token.Fn, - "loc" => Token.Loc, - "for" => Token.For, - "while" => Token.While, - "do" => Token.Do, - "rw" => Token.Rw, - "val" => Token.Val, - "in" => Token.In, - "if" => Token.If, - "is" => Token.Is, - "elif" => Token.Elif, - "else" => Token.Else, - "break" => Token.Break, - "skip" => Token.Skip, - "by" => Token.By, - "ret" => Token.Ret, - "true" => Token.True, - "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, - "self" => Token.Self, - "error" => Token.Error, - "retry" => Token.Retry, - "with" => Token.With, - "Infinity" => Token.Infinity, - "NaN" => Token.NaN, - "Nil" => Token.NilTypeCode, - "Number" => Token.NumberTypeCode, - "String" => Token.StringTypeCode, - "Boolean" => Token.BooleanTypeCode, - "Table" => Token.TableTypeCode, - "Array" => Token.ArrayTypeCode, - "Fiber" => Token.FiberTypeCode, - "Error" => Token.ErrorTypeCode, - "Function" => Token.ChunkTypeCode, - "Type" => Token.TypeCodeTypeCode, - "NativeFunction" => Token.NativeFunctionTypeCode, - "NativeObject" => Token.NativeObjectTypeCode, - _ => Token.CreateIdentifier(str) - }; } - - private bool IsLegalIdentifierCharacter(char c) + else { - return char.IsLetterOrDigit(c) || c == '_'; + throw new LexerException( + $"Character `{State.Character}' was unexpected at this time.", + State.Line, + State.Column + ); } - private bool IsLegalHexNumberCharacter(char c) + try { - return HexAlphabet.Contains(c); + return Token.CreateNumber(number); } - - private Token GetString() + catch (FormatException) { - var (line, col) = (State.Line, State.Column); - - var str = string.Empty; - var delimiter = State.Character; + throw new LexerException($"Malformed numeric constant `{number}'.", State.Line, State.Column); + } + } - if (delimiter != '"' && delimiter != '\'') - { - throw new LexerException( - "Strings can only be delimited by '' or \"\".", - line, col - ); - } + private Token GetIdentifierOrKeyword() + { + var str = string.Empty; + while (IsLegalIdentifierCharacter(State.Character)) + { + str += State.Character; Advance(); + } - while (State.Character != delimiter) - { - if (State.Character == (char)0) - throw new LexerException("Unterminated string.", line, col); + return str switch + { + "fn" => Token.Fn, + "loc" => Token.Loc, + "for" => Token.For, + "while" => Token.While, + "do" => Token.Do, + "rw" => Token.Rw, + "val" => Token.Val, + "in" => Token.In, + "if" => Token.If, + "is" => Token.Is, + "elif" => Token.Elif, + "else" => Token.Else, + "break" => Token.Break, + "skip" => Token.Skip, + "by" => Token.By, + "ret" => Token.Ret, + "true" => Token.True, + "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, + "self" => Token.Self, + "error" => Token.Error, + "retry" => Token.Retry, + "with" => Token.With, + "Infinity" => Token.Infinity, + "NaN" => Token.NaN, + "Nil" => Token.NilTypeCode, + "Number" => Token.NumberTypeCode, + "String" => Token.StringTypeCode, + "Boolean" => Token.BooleanTypeCode, + "Table" => Token.TableTypeCode, + "Array" => Token.ArrayTypeCode, + "Fiber" => Token.FiberTypeCode, + "Error" => Token.ErrorTypeCode, + "Function" => Token.ChunkTypeCode, + "Type" => Token.TypeCodeTypeCode, + "NativeFunction" => Token.NativeFunctionTypeCode, + "NativeObject" => Token.NativeObjectTypeCode, + _ => Token.CreateIdentifier(str) + }; + } - if (State.Character == '\\') - { - Advance(); + private bool IsLegalIdentifierCharacter(char c) + { + return char.IsLetterOrDigit(c) || c == '_'; + } - switch (State.Character) - { - case 'a': - str += '\a'; - break; - case 'b': - str += '\b'; - break; - case 'f': - str += '\f'; - break; - case 'n': - str += '\n'; - break; - case 'r': - str += '\r'; - break; - case 't': - str += '\t'; - break; - case 'x': - case 'u': - Advance(); - str += GetUnicodeSequence(); - continue; - case 'v': - str += '\v'; - break; - case '"': - str += '"'; - break; - case '\'': - str += '\''; - break; - case '\\': - str += '\\'; - break; - case '$': - str += '$'; - break; - default: - throw new LexerException("Unrecognized escape sequence.", State.Line, State.Column); - } + private bool IsLegalHexNumberCharacter(char c) + { + return HexAlphabet.Contains(c); + } - Advance(); - continue; - } + private Token GetString() + { + var (line, col) = (State.Line, State.Column); - str += State.Character; - Advance(); - } + var str = string.Empty; + var delimiter = State.Character; - if (delimiter == '\'') - { - return Token.CreatePlainString(str); - } - else // '"' - { - return Token.CreateInterpolatedString(str); - } + if (delimiter != '"' && delimiter != '\'') + { + throw new LexerException( + "Strings can only be delimited by '' or \"\".", + line, col + ); } - private char GetUnicodeSequence() + Advance(); + + while (State.Character != delimiter) { - var sb = new StringBuilder(); + if (State.Character == (char)0) + throw new LexerException("Unterminated string.", line, col); - for (var i = 0; i < 4; i++) + if (State.Character == '\\') { - if (HexAlphabet.Contains(State.Character)) - { - sb.Append(State.Character); - Advance(); - } - else + Advance(); + + switch (State.Character) { - throw new LexerException( - "Invalid universal character code.", - State.Line, State.Column); + case 'a': + str += '\a'; + break; + case 'b': + str += '\b'; + break; + case 'f': + str += '\f'; + break; + case 'n': + str += '\n'; + break; + case 'r': + str += '\r'; + break; + case 't': + str += '\t'; + break; + case 'x': + case 'u': + Advance(); + str += GetUnicodeSequence(); + continue; + case 'v': + str += '\v'; + break; + case '"': + str += '"'; + break; + case '\'': + str += '\''; + break; + case '\\': + str += '\\'; + break; + case '$': + str += '$'; + break; + default: + throw new LexerException("Unrecognized escape sequence.", State.Line, State.Column); } + + Advance(); + continue; } - return (char)int.Parse(sb.ToString(), NumberStyles.HexNumber); + str += State.Character; + Advance(); } - private void SkipLineComment() + if (delimiter == '\'') { - while (State.Character != '\n' && State.Character != (char)0) - Advance(); + return Token.CreatePlainString(str); } + else // '"' + { + return Token.CreateInterpolatedString(str); + } + } - private void SkipBlockComment() + private char GetUnicodeSequence() + { + var sb = new StringBuilder(); + + for (var i = 0; i < 4; i++) { - while (true) + if (HexAlphabet.Contains(State.Character)) { - if (Peek() == '*' && Peek(2) == '/') - { - Advance(); - Advance(); - - break; - } - - if (State.Character == 0) - break; - + sb.Append(State.Character); Advance(); } + else + { + throw new LexerException( + "Invalid universal character code.", + State.Line, State.Column); + } } - private void SkipWhitespace() + return (char)int.Parse(sb.ToString(), NumberStyles.HexNumber); + } + + private void SkipLineComment() + { + while (State.Character != '\n' && State.Character != (char)0) + Advance(); + } + + private void SkipBlockComment() + { + while (true) { - while (char.IsWhiteSpace(State.Character) || State.Character == 0xFEFF) + if (Peek() == '*' && Peek(2) == '/') + { Advance(); + Advance(); + + break; + } + + if (State.Character == 0) + break; + + Advance(); } + } - private char Peek(int howFar = 1) - { - if (State.Pointer + howFar >= _sourceCode!.Length) - return (char)0; + private void SkipWhitespace() + { + while (char.IsWhiteSpace(State.Character) || State.Character == 0xFEFF) + Advance(); + } - return _sourceCode[State.Pointer + howFar]; - } + private char Peek(int howFar = 1) + { + if (State.Pointer + howFar >= _sourceCode!.Length) + return (char)0; - private string PeekString(int length = 1) - { - var sb = new StringBuilder(); + return _sourceCode[State.Pointer + howFar]; + } - for (var i = 1; i <= length; i++) - { - if (State.Pointer + i >= _sourceCode!.Length) - break; + private string PeekString(int length = 1) + { + var sb = new StringBuilder(); - sb.Append(_sourceCode[State.Pointer + i]); - } + for (var i = 1; i <= length; i++) + { + if (State.Pointer + i >= _sourceCode!.Length) + break; - return sb.ToString(); + sb.Append(_sourceCode[State.Pointer + i]); } - private void Advance(int howFar = 1) + return sb.ToString(); + } + + private void Advance(int howFar = 1) + { + for (var i = 0; i < howFar; i++) { - for (var i = 0; i < howFar; i++) + if (State.Character == '\n') { - if (State.Character == '\n') - { - State.Column = 1; - State.Line++; - } - else - { - State.Column++; - } + State.Column = 1; + State.Line++; + } + else + { + State.Column++; + } - if (State.Pointer + 1 < _sourceCode!.Length) - { - State.Pointer++; - State.Character = _sourceCode[State.Pointer]; - } - else - { - State.Character = '\0'; - } + if (State.Pointer + 1 < _sourceCode!.Length) + { + State.Pointer++; + State.Character = _sourceCode[State.Pointer]; + } + else + { + State.Character = '\0'; } } } diff --git a/Core/EVIL.Lexical/LexerException.cs b/Core/EVIL.Lexical/LexerException.cs index bf5bc798..7dac377b 100644 --- a/Core/EVIL.Lexical/LexerException.cs +++ b/Core/EVIL.Lexical/LexerException.cs @@ -1,16 +1,15 @@ -using System; +namespace EVIL.Lexical; -namespace EVIL.Lexical +using System; + +public class LexerException : Exception { - public class LexerException : Exception - { - public int Line { get; } - public int Column { get; } + public int Line { get; } + public int Column { get; } - public LexerException(string message, int line, int column) : base(message) - { - Line = line; - Column = column; - } + public LexerException(string message, int line, int column) : base(message) + { + Line = line; + Column = column; } -} +} \ No newline at end of file diff --git a/Core/EVIL.Lexical/LexerState.cs b/Core/EVIL.Lexical/LexerState.cs index 33b8f9b0..e2054419 100644 --- a/Core/EVIL.Lexical/LexerState.cs +++ b/Core/EVIL.Lexical/LexerState.cs @@ -1,34 +1,33 @@ -namespace EVIL.Lexical +namespace EVIL.Lexical; + +public class LexerState { - public class LexerState - { - public Token PreviousToken { get; internal set; } = Token.Empty; - public Token CurrentToken { get; internal set; } = Token.Empty; + public Token PreviousToken { get; internal set; } = Token.Empty; + public Token CurrentToken { get; internal set; } = Token.Empty; - public char Character { get; internal set; } + public char Character { get; internal set; } - public int Pointer { get; internal set; } - public int Column { get; internal set; } - public int Line { get; internal set; } + public int Pointer { get; internal set; } + public int Column { get; internal set; } + public int Line { get; internal set; } - public LexerState Copy() => new() - { - Character = Character, - Column = Column, - CurrentToken = CurrentToken, - Line = Line, - Pointer = Pointer, - PreviousToken = PreviousToken - }; + public LexerState Copy() => new() + { + Character = Character, + Column = Column, + CurrentToken = CurrentToken, + Line = Line, + Pointer = Pointer, + PreviousToken = PreviousToken + }; - internal void Reset() - { - PreviousToken = Token.Empty; - CurrentToken = Token.Empty; - Character = (char)0; - Pointer = 0; - Column = 1; - Line = 1; - } + internal void Reset() + { + PreviousToken = Token.Empty; + CurrentToken = Token.Empty; + Character = (char)0; + Pointer = 0; + Column = 1; + Line = 1; } } \ No newline at end of file diff --git a/Core/EVIL.Lexical/Token.cs b/Core/EVIL.Lexical/Token.cs index 9565dc17..cfc8242a 100644 --- a/Core/EVIL.Lexical/Token.cs +++ b/Core/EVIL.Lexical/Token.cs @@ -1,169 +1,168 @@ -using System; +namespace EVIL.Lexical; -namespace EVIL.Lexical +using System; + +public struct Token : IEquatable { - public struct Token : IEquatable - { - public TokenType Type { get; } - public TokenClass Class { get; } - public string Value { get; } + public TokenType Type { get; } + public TokenClass Class { get; } + public string Value { get; } - public int Line { get; init; } - public int Column { get; init; } + public int Line { get; init; } + public int Column { get; init; } - public Token(TokenType type, TokenClass @class, string value) - { - Type = type; - Class = @class; - Value = value; - } + public Token(TokenType type, TokenClass @class, string value) + { + Type = type; + Class = @class; + Value = value; + } - public static Token CreateHexInteger(string value) - => new(TokenType.HexInteger, TokenClass.Literal, value); + public static Token CreateHexInteger(string value) + => new(TokenType.HexInteger, TokenClass.Literal, value); - public static Token CreatePlainString(string value) - => new(TokenType.PlainString, TokenClass.Literal, value); + public static Token CreatePlainString(string value) + => new(TokenType.PlainString, TokenClass.Literal, value); - public static Token CreateInterpolatedString(string value) - => new(TokenType.InterpolatedString, TokenClass.Literal, value); + public static Token CreateInterpolatedString(string value) + => new(TokenType.InterpolatedString, TokenClass.Literal, value); - public static Token CreateNumber(string value) - => new(TokenType.Number, TokenClass.Literal, value); + public static Token CreateNumber(string value) + => new(TokenType.Number, TokenClass.Literal, value); - public static Token CreateIdentifier(string value) - => new(TokenType.Identifier, TokenClass.Identifier, value); + public static Token CreateIdentifier(string value) + => new(TokenType.Identifier, TokenClass.Identifier, value); - public override string ToString() - => $"[{Type}: {Value}]"; + public override string ToString() + => $"[{Type}: {Value}]"; - public bool Equals(Token other) - => Type == other.Type && Class == other.Class && Value == other.Value; - - public override bool Equals(object? obj) - => obj is Token other && Equals(other); - - public override int GetHashCode() - => HashCode.Combine((int)Type, (int)Class, Value); - - public static bool operator ==(Token left, Token right) - => left.Equals(right); - - public static bool operator !=(Token left, Token right) - => !left.Equals(right); - - public static readonly Token Assign = new(TokenType.Assign, TokenClass.Operator, "="); - public static readonly Token AssignAdd = new(TokenType.AssignAdd, TokenClass.Operator, "+="); - public static readonly Token AssignSubtract = new(TokenType.AssignSubtract, TokenClass.Operator, "-="); - public static readonly Token AssignMultiply = new(TokenType.AssignMultiply, TokenClass.Operator, "*="); - public static readonly Token AssignDivide = new(TokenType.AssignDivide, TokenClass.Operator, "/="); - public static readonly Token AssignModulo = new(TokenType.AssignModulo, TokenClass.Operator, "%="); - public static readonly Token AssignBitwiseAnd = new(TokenType.AssignBitwiseAnd, TokenClass.Operator, "&="); - public static readonly Token AssignBitwiseOr = new(TokenType.AssignBitwiseOr, TokenClass.Operator, "|="); - public static readonly Token AssignBitwiseXor = new(TokenType.AssignBitwiseXor, TokenClass.Operator, "^="); - public static readonly Token AssignShiftRight = new(TokenType.AssignShiftRight, TokenClass.Operator, ">>="); - public static readonly Token AssignShiftLeft = new(TokenType.AssignShiftLeft, TokenClass.Operator, "<<="); - public static readonly Token AssignCoalesce = new(TokenType.AssignCoalesce, TokenClass.Operator, "??="); - public static readonly Token Plus = new(TokenType.Plus, TokenClass.Operator, "+"); - public static readonly Token Minus = new(TokenType.Minus, TokenClass.Operator, "-"); - public static readonly Token Divide = new(TokenType.Divide, TokenClass.Operator, "/"); - public static readonly Token Multiply = new(TokenType.Multiply, TokenClass.Operator, "*"); - public static readonly Token Modulo = new(TokenType.Modulo, TokenClass.Operator, "%"); - public static readonly Token BitwiseAnd = new(TokenType.BitwiseAnd, TokenClass.Operator, "&"); - public static readonly Token BitwiseNot = new(TokenType.BitwiseNot, TokenClass.Operator, "~"); - public static readonly Token BitwiseOr = new(TokenType.BitwiseOr, TokenClass.Operator, "|"); - public static readonly Token BitwiseXor = new(TokenType.BitwiseXor, TokenClass.Operator, "^"); - public static readonly Token ShiftLeft = new(TokenType.ShiftLeft, TokenClass.Operator, "<<"); - public static readonly Token ShiftRight = new(TokenType.ShiftRight, TokenClass.Operator, ">>"); - public static readonly Token Ellipsis = new(TokenType.Ellipsis, TokenClass.Operator, "..."); - public static readonly Token Associate = new(TokenType.Associate, TokenClass.Operator, "=>"); - public static readonly Token RightArrow = new(TokenType.RightArrow, TokenClass.Operator, "->"); - public static readonly Token Decrement = new(TokenType.Decrement, TokenClass.Operator, "--"); - public static readonly Token Increment = new(TokenType.Increment, TokenClass.Operator, "++"); - public static readonly Token LogicalAnd = new(TokenType.LogicalAnd, TokenClass.Operator, "&&"); - public static readonly Token LogicalOr = new(TokenType.LogicalOr, TokenClass.Operator, "||"); - public static readonly Token LogicalNot = new(TokenType.LogicalNot, TokenClass.Operator, "!"); - public static readonly Token DeepEqual = new(TokenType.DeepEqual, TokenClass.Operator, "<==>"); - public static readonly Token DeepNotEqual = new(TokenType.DeepNotEqual, TokenClass.Operator, ""); - public static readonly Token Equal = new(TokenType.Equal, TokenClass.Operator, "=="); - public static readonly Token NotEqual = new(TokenType.NotEqual, TokenClass.Operator, "!="); - public static readonly Token GreaterThan = new(TokenType.GreaterThan, TokenClass.Operator, ">"); - public static readonly Token LessThan = new(TokenType.LessThan, TokenClass.Operator, "<"); - public static readonly Token GreaterThanOrEqual = new(TokenType.GreaterThanOrEqual, TokenClass.Operator, ">="); - public static readonly Token LessThanOrEqual = new(TokenType.LessThanOrEqual, TokenClass.Operator, "<="); - public static readonly Token Length = new(TokenType.Length, TokenClass.Operator, "#"); - public static readonly Token AsNumber = new(TokenType.AsNumber, TokenClass.Operator, "$"); - public static readonly Token AsString = new(TokenType.AsString, TokenClass.Operator, "@"); - public static readonly Token QuestionMark = new(TokenType.QuestionMark, TokenClass.Operator, "?"); - public static readonly Token DoubleQuestionMark = new(TokenType.DoubleQuestionMark, TokenClass.Operator, "??"); - public static readonly Token Colon = new(TokenType.Colon, TokenClass.Operator, ":"); - public static readonly Token DoubleColon = new(TokenType.DoubleColon, TokenClass.Operator, "::"); - public static readonly Token Semicolon = new(TokenType.Semicolon, TokenClass.Operator, ";"); - public static readonly Token Comma = new(TokenType.Comma, TokenClass.Operator, ","); - public static readonly Token Dot = new(TokenType.Dot, TokenClass.Operator, "."); - public static readonly Token LBrace = new(TokenType.LBrace, TokenClass.Operator, "{"); - public static readonly Token RBrace = new(TokenType.RBrace, TokenClass.Operator, "}"); - public static readonly Token LBracket = new(TokenType.LBracket, TokenClass.Operator, "["); - public static readonly Token RBracket = new(TokenType.RBracket, TokenClass.Operator, "]"); - public static readonly Token LParenthesis = new(TokenType.LParenthesis, TokenClass.Operator, "("); - public static readonly Token RParenthesis = new(TokenType.RParenthesis, TokenClass.Operator, ")"); - public static readonly Token AttributeList = new(TokenType.AttributeList, TokenClass.Operator, "#["); - public static readonly Token Array = new(TokenType.Array, TokenClass.Operator, "array"); - public static readonly Token Self = new(TokenType.Self, TokenClass.Operator, "self"); - public static readonly Token Error = new(TokenType.Error, TokenClass.Operator, "error"); - public static readonly Token In = new(TokenType.In, TokenClass.Operator, "in"); - public static readonly Token NotIn = new(TokenType.NotIn, TokenClass.Operator, "!in"); - 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 Retry = new(TokenType.Retry, TokenClass.Keyword, "retry"); - public static readonly Token With = new(TokenType.With, TokenClass.Keyword, "with"); + public bool Equals(Token other) + => Type == other.Type && Class == other.Class && Value == other.Value; + + public override bool Equals(object? obj) + => obj is Token other && Equals(other); + + public override int GetHashCode() + => HashCode.Combine((int)Type, (int)Class, Value); + + public static bool operator ==(Token left, Token right) + => left.Equals(right); + + public static bool operator !=(Token left, Token right) + => !left.Equals(right); + + public static readonly Token Assign = new(TokenType.Assign, TokenClass.Operator, "="); + public static readonly Token AssignAdd = new(TokenType.AssignAdd, TokenClass.Operator, "+="); + public static readonly Token AssignSubtract = new(TokenType.AssignSubtract, TokenClass.Operator, "-="); + public static readonly Token AssignMultiply = new(TokenType.AssignMultiply, TokenClass.Operator, "*="); + public static readonly Token AssignDivide = new(TokenType.AssignDivide, TokenClass.Operator, "/="); + public static readonly Token AssignModulo = new(TokenType.AssignModulo, TokenClass.Operator, "%="); + public static readonly Token AssignBitwiseAnd = new(TokenType.AssignBitwiseAnd, TokenClass.Operator, "&="); + public static readonly Token AssignBitwiseOr = new(TokenType.AssignBitwiseOr, TokenClass.Operator, "|="); + public static readonly Token AssignBitwiseXor = new(TokenType.AssignBitwiseXor, TokenClass.Operator, "^="); + public static readonly Token AssignShiftRight = new(TokenType.AssignShiftRight, TokenClass.Operator, ">>="); + public static readonly Token AssignShiftLeft = new(TokenType.AssignShiftLeft, TokenClass.Operator, "<<="); + public static readonly Token AssignCoalesce = new(TokenType.AssignCoalesce, TokenClass.Operator, "??="); + public static readonly Token Plus = new(TokenType.Plus, TokenClass.Operator, "+"); + public static readonly Token Minus = new(TokenType.Minus, TokenClass.Operator, "-"); + public static readonly Token Divide = new(TokenType.Divide, TokenClass.Operator, "/"); + public static readonly Token Multiply = new(TokenType.Multiply, TokenClass.Operator, "*"); + public static readonly Token Modulo = new(TokenType.Modulo, TokenClass.Operator, "%"); + public static readonly Token BitwiseAnd = new(TokenType.BitwiseAnd, TokenClass.Operator, "&"); + public static readonly Token BitwiseNot = new(TokenType.BitwiseNot, TokenClass.Operator, "~"); + public static readonly Token BitwiseOr = new(TokenType.BitwiseOr, TokenClass.Operator, "|"); + public static readonly Token BitwiseXor = new(TokenType.BitwiseXor, TokenClass.Operator, "^"); + public static readonly Token ShiftLeft = new(TokenType.ShiftLeft, TokenClass.Operator, "<<"); + public static readonly Token ShiftRight = new(TokenType.ShiftRight, TokenClass.Operator, ">>"); + public static readonly Token Ellipsis = new(TokenType.Ellipsis, TokenClass.Operator, "..."); + public static readonly Token Associate = new(TokenType.Associate, TokenClass.Operator, "=>"); + public static readonly Token RightArrow = new(TokenType.RightArrow, TokenClass.Operator, "->"); + public static readonly Token Decrement = new(TokenType.Decrement, TokenClass.Operator, "--"); + public static readonly Token Increment = new(TokenType.Increment, TokenClass.Operator, "++"); + public static readonly Token LogicalAnd = new(TokenType.LogicalAnd, TokenClass.Operator, "&&"); + public static readonly Token LogicalOr = new(TokenType.LogicalOr, TokenClass.Operator, "||"); + public static readonly Token LogicalNot = new(TokenType.LogicalNot, TokenClass.Operator, "!"); + public static readonly Token DeepEqual = new(TokenType.DeepEqual, TokenClass.Operator, "<==>"); + public static readonly Token DeepNotEqual = new(TokenType.DeepNotEqual, TokenClass.Operator, ""); + public static readonly Token Equal = new(TokenType.Equal, TokenClass.Operator, "=="); + public static readonly Token NotEqual = new(TokenType.NotEqual, TokenClass.Operator, "!="); + public static readonly Token GreaterThan = new(TokenType.GreaterThan, TokenClass.Operator, ">"); + public static readonly Token LessThan = new(TokenType.LessThan, TokenClass.Operator, "<"); + public static readonly Token GreaterThanOrEqual = new(TokenType.GreaterThanOrEqual, TokenClass.Operator, ">="); + public static readonly Token LessThanOrEqual = new(TokenType.LessThanOrEqual, TokenClass.Operator, "<="); + public static readonly Token Length = new(TokenType.Length, TokenClass.Operator, "#"); + public static readonly Token AsNumber = new(TokenType.AsNumber, TokenClass.Operator, "$"); + public static readonly Token AsString = new(TokenType.AsString, TokenClass.Operator, "@"); + public static readonly Token QuestionMark = new(TokenType.QuestionMark, TokenClass.Operator, "?"); + public static readonly Token DoubleQuestionMark = new(TokenType.DoubleQuestionMark, TokenClass.Operator, "??"); + public static readonly Token Colon = new(TokenType.Colon, TokenClass.Operator, ":"); + public static readonly Token DoubleColon = new(TokenType.DoubleColon, TokenClass.Operator, "::"); + public static readonly Token Semicolon = new(TokenType.Semicolon, TokenClass.Operator, ";"); + public static readonly Token Comma = new(TokenType.Comma, TokenClass.Operator, ","); + public static readonly Token Dot = new(TokenType.Dot, TokenClass.Operator, "."); + public static readonly Token LBrace = new(TokenType.LBrace, TokenClass.Operator, "{"); + public static readonly Token RBrace = new(TokenType.RBrace, TokenClass.Operator, "}"); + public static readonly Token LBracket = new(TokenType.LBracket, TokenClass.Operator, "["); + public static readonly Token RBracket = new(TokenType.RBracket, TokenClass.Operator, "]"); + public static readonly Token LParenthesis = new(TokenType.LParenthesis, TokenClass.Operator, "("); + public static readonly Token RParenthesis = new(TokenType.RParenthesis, TokenClass.Operator, ")"); + public static readonly Token AttributeList = new(TokenType.AttributeList, TokenClass.Operator, "#["); + public static readonly Token Array = new(TokenType.Array, TokenClass.Operator, "array"); + public static readonly Token Self = new(TokenType.Self, TokenClass.Operator, "self"); + public static readonly Token Error = new(TokenType.Error, TokenClass.Operator, "error"); + public static readonly Token In = new(TokenType.In, TokenClass.Operator, "in"); + public static readonly Token NotIn = new(TokenType.NotIn, TokenClass.Operator, "!in"); + 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 Retry = new(TokenType.Retry, TokenClass.Keyword, "retry"); + public static readonly Token With = new(TokenType.With, TokenClass.Keyword, "with"); - public static readonly Token Val = new(TokenType.Val, TokenClass.Keyword, "val"); - public static readonly Token If = new(TokenType.If, TokenClass.Keyword, "if"); - public static readonly Token Elif = new(TokenType.Elif, TokenClass.Keyword, "elif"); - public static readonly Token Else = new(TokenType.Else, TokenClass.Keyword, "else"); - public static readonly Token By = new(TokenType.By, TokenClass.Keyword, "by"); - public static readonly Token Fn = new(TokenType.Fn, TokenClass.Keyword, "fn"); - public static readonly Token Loc = new(TokenType.Loc, TokenClass.Keyword, "loc"); - public static readonly Token Ret = new(TokenType.Ret, TokenClass.Keyword, "ret"); - public static readonly Token For = new(TokenType.For, TokenClass.Keyword, "for"); - public static readonly Token Do = new(TokenType.Do, TokenClass.Keyword, "do"); - public static readonly Token While = new(TokenType.While, TokenClass.Keyword, "while"); - public static readonly Token Break = new(TokenType.Break, TokenClass.Keyword, "break"); - public static readonly Token Nil = new(TokenType.Nil, TokenClass.Keyword, "nil"); - public static readonly Token Skip = new(TokenType.Skip, TokenClass.Keyword, "skip"); - public static readonly Token False = new(TokenType.False, TokenClass.Keyword, "false"); - public static readonly Token True = new(TokenType.True, TokenClass.Keyword, "true"); - public static readonly Token Yield = new(TokenType.Yield, TokenClass.Keyword, "yield"); - public static readonly Token Rw = new(TokenType.Rw, TokenClass.Keyword, "rw"); - public static readonly Token Each = new(TokenType.Each, TokenClass.Keyword, "each"); + public static readonly Token Val = new(TokenType.Val, TokenClass.Keyword, "val"); + public static readonly Token If = new(TokenType.If, TokenClass.Keyword, "if"); + public static readonly Token Elif = new(TokenType.Elif, TokenClass.Keyword, "elif"); + public static readonly Token Else = new(TokenType.Else, TokenClass.Keyword, "else"); + public static readonly Token By = new(TokenType.By, TokenClass.Keyword, "by"); + public static readonly Token Fn = new(TokenType.Fn, TokenClass.Keyword, "fn"); + public static readonly Token Loc = new(TokenType.Loc, TokenClass.Keyword, "loc"); + public static readonly Token Ret = new(TokenType.Ret, TokenClass.Keyword, "ret"); + public static readonly Token For = new(TokenType.For, TokenClass.Keyword, "for"); + public static readonly Token Do = new(TokenType.Do, TokenClass.Keyword, "do"); + public static readonly Token While = new(TokenType.While, TokenClass.Keyword, "while"); + public static readonly Token Break = new(TokenType.Break, TokenClass.Keyword, "break"); + public static readonly Token Nil = new(TokenType.Nil, TokenClass.Keyword, "nil"); + public static readonly Token Skip = new(TokenType.Skip, TokenClass.Keyword, "skip"); + public static readonly Token False = new(TokenType.False, TokenClass.Keyword, "false"); + public static readonly Token True = new(TokenType.True, TokenClass.Keyword, "true"); + public static readonly Token Yield = new(TokenType.Yield, TokenClass.Keyword, "yield"); + public static readonly Token Rw = new(TokenType.Rw, TokenClass.Keyword, "rw"); + public static readonly Token Each = new(TokenType.Each, TokenClass.Keyword, "each"); - public static readonly Token NaN = new(TokenType.NaN, TokenClass.Alias, "NaN"); - public static readonly Token Infinity = new(TokenType.Infinity, TokenClass.Alias, "Infinity"); - - public static readonly Token NilTypeCode = new(TokenType.NilTypeCode, TokenClass.TypeCode, "Nil"); - public static readonly Token NumberTypeCode = new(TokenType.NumberTypeCode, TokenClass.TypeCode, "Number"); - public static readonly Token StringTypeCode = new(TokenType.StringTypeCode, TokenClass.TypeCode, "String"); - public static readonly Token BooleanTypeCode = new(TokenType.BooleanTypeCode, TokenClass.TypeCode, "Boolean"); - public static readonly Token TableTypeCode = new(TokenType.TableTypeCode, TokenClass.TypeCode, "Table"); - public static readonly Token ArrayTypeCode = new(TokenType.ArrayTypeCode, TokenClass.TypeCode, "Array"); - public static readonly Token FiberTypeCode = new(TokenType.FiberTypeCode, TokenClass.TypeCode, "Fiber"); - public static readonly Token ChunkTypeCode = new(TokenType.ChunkTypeCode, TokenClass.TypeCode, "Function"); - public static readonly Token ErrorTypeCode = new(TokenType.ErrorTypeCode, TokenClass.TypeCode, "Error"); - public static readonly Token TypeCodeTypeCode = new(TokenType.TypeCodeTypeCode, TokenClass.TypeCode, "Type"); - public static readonly Token NativeFunctionTypeCode = new(TokenType.NativeFunctionTypeCode, TokenClass.TypeCode, "NativeFunction"); - public static readonly Token NativeObjectTypeCode = new(TokenType.NativeObjectTypeCode, TokenClass.TypeCode, "NativeObject"); + public static readonly Token NaN = new(TokenType.NaN, TokenClass.Alias, "NaN"); + public static readonly Token Infinity = new(TokenType.Infinity, TokenClass.Alias, "Infinity"); + + public static readonly Token NilTypeCode = new(TokenType.NilTypeCode, TokenClass.TypeCode, "Nil"); + public static readonly Token NumberTypeCode = new(TokenType.NumberTypeCode, TokenClass.TypeCode, "Number"); + public static readonly Token StringTypeCode = new(TokenType.StringTypeCode, TokenClass.TypeCode, "String"); + public static readonly Token BooleanTypeCode = new(TokenType.BooleanTypeCode, TokenClass.TypeCode, "Boolean"); + public static readonly Token TableTypeCode = new(TokenType.TableTypeCode, TokenClass.TypeCode, "Table"); + public static readonly Token ArrayTypeCode = new(TokenType.ArrayTypeCode, TokenClass.TypeCode, "Array"); + public static readonly Token FiberTypeCode = new(TokenType.FiberTypeCode, TokenClass.TypeCode, "Fiber"); + public static readonly Token ChunkTypeCode = new(TokenType.ChunkTypeCode, TokenClass.TypeCode, "Function"); + public static readonly Token ErrorTypeCode = new(TokenType.ErrorTypeCode, TokenClass.TypeCode, "Error"); + public static readonly Token TypeCodeTypeCode = new(TokenType.TypeCodeTypeCode, TokenClass.TypeCode, "Type"); + public static readonly Token NativeFunctionTypeCode = new(TokenType.NativeFunctionTypeCode, TokenClass.TypeCode, "NativeFunction"); + public static readonly Token NativeObjectTypeCode = new(TokenType.NativeObjectTypeCode, TokenClass.TypeCode, "NativeObject"); - public static readonly Token Identifier = new(TokenType.Identifier, TokenClass.Identifier, string.Empty); - public static readonly Token Number = new(TokenType.Number, TokenClass.Literal, string.Empty); - public static readonly Token HexInteger = new(TokenType.HexInteger, TokenClass.Literal, string.Empty); - public static readonly Token PlainString = new(TokenType.PlainString, TokenClass.Literal, string.Empty); - public static readonly Token InterpolatedString = new(TokenType.InterpolatedString, TokenClass.Literal, string.Empty); + public static readonly Token Identifier = new(TokenType.Identifier, TokenClass.Identifier, string.Empty); + public static readonly Token Number = new(TokenType.Number, TokenClass.Literal, string.Empty); + public static readonly Token HexInteger = new(TokenType.HexInteger, TokenClass.Literal, string.Empty); + public static readonly Token PlainString = new(TokenType.PlainString, TokenClass.Literal, string.Empty); + public static readonly Token InterpolatedString = new(TokenType.InterpolatedString, TokenClass.Literal, string.Empty); - public static readonly Token EOF = new(TokenType.EOF, TokenClass.Meta, ""); - public static readonly Token Empty = new(TokenType.Empty, TokenClass.Meta, string.Empty); - } + public static readonly Token EOF = new(TokenType.EOF, TokenClass.Meta, ""); + public static readonly Token Empty = new(TokenType.Empty, TokenClass.Meta, string.Empty); } \ No newline at end of file diff --git a/Core/EVIL.Lexical/TokenClass.cs b/Core/EVIL.Lexical/TokenClass.cs index 1b925ea1..f2e5db8d 100644 --- a/Core/EVIL.Lexical/TokenClass.cs +++ b/Core/EVIL.Lexical/TokenClass.cs @@ -1,14 +1,13 @@ -namespace EVIL.Lexical +namespace EVIL.Lexical; + +public enum TokenClass { - public enum TokenClass - { - Operator, - Keyword, - Identifier, - Literal, - Alias, - Meta, - TypeCode, - Override - } + Operator, + Keyword, + Identifier, + Literal, + Alias, + Meta, + TypeCode, + Override } \ No newline at end of file diff --git a/Core/EVIL.Lexical/TokenType.cs b/Core/EVIL.Lexical/TokenType.cs index 4ddb7fc0..86eefd8b 100644 --- a/Core/EVIL.Lexical/TokenType.cs +++ b/Core/EVIL.Lexical/TokenType.cs @@ -1,128 +1,127 @@ -namespace EVIL.Lexical +namespace EVIL.Lexical; + +public enum TokenType { - public enum TokenType - { - Empty = -1, + Empty = -1, - Minus, - Plus, - Multiply, - Divide, - Modulo, - BitwiseAnd, - BitwiseOr, - BitwiseXor, - BitwiseNot, - AsNumber, - AsString, - Length, - Increment, - Decrement, - ShiftRight, - ShiftLeft, + Minus, + Plus, + Multiply, + Divide, + Modulo, + BitwiseAnd, + BitwiseOr, + BitwiseXor, + BitwiseNot, + AsNumber, + AsString, + Length, + Increment, + Decrement, + ShiftRight, + ShiftLeft, - Ellipsis, - Associate, - RightArrow, + Ellipsis, + Associate, + RightArrow, - Dot, - QuestionMark, - DoubleQuestionMark, + Dot, + QuestionMark, + DoubleQuestionMark, - Assign, - AssignAdd, - AssignSubtract, - AssignMultiply, - AssignDivide, - AssignModulo, - AssignBitwiseAnd, - AssignBitwiseOr, - AssignBitwiseXor, - AssignShiftRight, - AssignShiftLeft, - AssignCoalesce, + Assign, + AssignAdd, + AssignSubtract, + AssignMultiply, + AssignDivide, + AssignModulo, + AssignBitwiseAnd, + AssignBitwiseOr, + AssignBitwiseXor, + AssignShiftRight, + AssignShiftLeft, + AssignCoalesce, - DeepEqual, - DeepNotEqual, - Equal, - NotEqual, - LessThan, - LessThanOrEqual, - GreaterThan, - GreaterThanOrEqual, + DeepEqual, + DeepNotEqual, + Equal, + NotEqual, + LessThan, + LessThanOrEqual, + GreaterThan, + GreaterThanOrEqual, - LogicalNot, - LogicalAnd, - LogicalOr, + LogicalNot, + LogicalAnd, + LogicalOr, - Comma, - Colon, - DoubleColon, - Semicolon, - LParenthesis, - RParenthesis, - LBrace, - RBrace, - LBracket, - RBracket, - Array, - Self, - Error, + Comma, + Colon, + DoubleColon, + Semicolon, + LParenthesis, + RParenthesis, + LBrace, + RBrace, + LBracket, + RBracket, + Array, + Self, + Error, - AttributeList, - Identifier, + AttributeList, + Identifier, - Number, - HexInteger, - PlainString, - InterpolatedString, + Number, + HexInteger, + PlainString, + InterpolatedString, - True, - False, + True, + False, - Fn, - Loc, - For, - Do, - While, - Each, - If, - Elif, - Else, - Skip, - Break, - By, - Ret, - Val, - In, - NotIn, - Is, - IsNot, - Nil, - TypeOf, - Try, - Catch, - Throw, - Retry, - Yield, - With, - Rw, - NaN, - Infinity, + Fn, + Loc, + For, + Do, + While, + Each, + If, + Elif, + Else, + Skip, + Break, + By, + Ret, + Val, + In, + NotIn, + Is, + IsNot, + Nil, + TypeOf, + Try, + Catch, + Throw, + Retry, + Yield, + With, + Rw, + NaN, + Infinity, - NilTypeCode, - NumberTypeCode, - StringTypeCode, - BooleanTypeCode, - TableTypeCode, - ArrayTypeCode, - FiberTypeCode, - ChunkTypeCode, - ErrorTypeCode, - TypeCodeTypeCode, - NativeFunctionTypeCode, - NativeObjectTypeCode, + NilTypeCode, + NumberTypeCode, + StringTypeCode, + BooleanTypeCode, + TableTypeCode, + ArrayTypeCode, + FiberTypeCode, + ChunkTypeCode, + ErrorTypeCode, + TypeCodeTypeCode, + NativeFunctionTypeCode, + NativeObjectTypeCode, - EOF - } + EOF } \ No newline at end of file diff --git a/Core/Tests/EVIL.CoreTests/LexerTests.cs b/Core/Tests/EVIL.CoreTests/LexerTests.cs index b25196dc..d210be98 100644 --- a/Core/Tests/EVIL.CoreTests/LexerTests.cs +++ b/Core/Tests/EVIL.CoreTests/LexerTests.cs @@ -1,217 +1,216 @@ +namespace EVIL.CoreTests; + +using static EVIL.Lexical.Token; + using EVIL.Lexical; using NUnit.Framework; using Shouldly; -using static EVIL.Lexical.Token; -namespace EVIL.CoreTests +public class LexerTests { - public class LexerTests + protected Lexer _lexer = null!; + + protected Token CurrentToken => _lexer.State.CurrentToken; + + [SetUp] + public virtual void Setup() { - protected Lexer _lexer = null!; + _lexer = new Lexer(); + } - protected Token CurrentToken => _lexer.State.CurrentToken; + [TearDown] + public virtual void Teardown() + { + _lexer = null!; + } - [SetUp] - public virtual void Setup() - { - _lexer = new Lexer(); - } + protected void InitializeWithSource(string source) + { + _lexer.LoadSource(source); + } - [TearDown] - public virtual void Teardown() + protected void Expect(params Token[] tokens) + { + foreach (var token in tokens) { - _lexer = null!; + CurrentToken.ShouldBe(token); + _lexer.NextToken(); } + } - protected void InitializeWithSource(string source) + protected void ExpectExact(params (TokenType ExpectedTokenType, string ExpectedValue)[] constraints) + { + foreach (var constraint in constraints) { - _lexer.LoadSource(source); - } + CurrentToken.Type.ShouldBe(constraint.ExpectedTokenType); + CurrentToken.Value.ShouldBe(constraint.ExpectedValue); - protected void Expect(params Token[] tokens) - { - foreach (var token in tokens) - { - CurrentToken.ShouldBe(token); - _lexer.NextToken(); - } + _lexer.NextToken(); } + } - protected void ExpectExact(params (TokenType ExpectedTokenType, string ExpectedValue)[] constraints) - { - foreach (var constraint in constraints) - { - CurrentToken.Type.ShouldBe(constraint.ExpectedTokenType); - CurrentToken.Value.ShouldBe(constraint.ExpectedValue); - - _lexer.NextToken(); - } - } - - [Test] - public void Keywords() - { - _lexer.LoadSource( - "typeof " + - "while break yield false " + - "skip each elif else true " + - "val ret for nil " + - "if rw do in fn is !is" - ); - - Expect(TypeOf); - Expect(While, Break, Yield, False); - Expect(Skip, Each, Elif, Else, True); - Expect(Val, Ret, For, Nil); - Expect(If, Rw, Do, In, Fn, Token.Is, IsNot); - Expect(EOF); - } + [Test] + public void Keywords() + { + _lexer.LoadSource( + "typeof " + + "while break yield false " + + "skip each elif else true " + + "val ret for nil " + + "if rw do in fn is !is" + ); + + Expect(TypeOf); + Expect(While, Break, Yield, False); + Expect(Skip, Each, Elif, Else, True); + Expect(Val, Ret, For, Nil); + Expect(If, Rw, Do, In, Fn, Token.Is, IsNot); + Expect(EOF); + } - [Test] - public void Operators() - { - _lexer.LoadSource( - "= += -= *= /= %= &= |= ^= >>= <<= " + - "+ - / * % & ~ | ^ << >> " + - "... => -> -- ++ && || ! " + - "<==> == != > < >= <= " + - "# $ @ ? : ; , . { } [ ] ( ) #[ " + - "array self with" - ); - - Expect( - Assign, AssignAdd, AssignSubtract, AssignMultiply, - AssignDivide, AssignModulo, AssignBitwiseAnd, AssignBitwiseOr, - AssignBitwiseXor, AssignShiftRight, AssignShiftLeft - ); - - Expect( - Plus, Minus, Divide, Multiply, Modulo, BitwiseAnd, BitwiseNot, - BitwiseOr, BitwiseXor, ShiftLeft, ShiftRight - ); - - Expect( - Ellipsis, Associate, RightArrow, Decrement, Increment, - LogicalAnd, LogicalOr, LogicalNot - ); - - Expect( - DeepEqual, DeepNotEqual, Equal, NotEqual, GreaterThan, - LessThan, GreaterThanOrEqual, LessThanOrEqual - ); - - Expect( - Length, AsNumber, AsString, QuestionMark, Colon, Semicolon, - Comma, Dot, LBrace, RBrace, LBracket, RBracket, LParenthesis, - RParenthesis, AttributeList - ); - - Expect(Token.Array, Self, With); - - Expect(EOF); - } + [Test] + public void Operators() + { + _lexer.LoadSource( + "= += -= *= /= %= &= |= ^= >>= <<= " + + "+ - / * % & ~ | ^ << >> " + + "... => -> -- ++ && || ! " + + "<==> == != > < >= <= " + + "# $ @ ? : ; , . { } [ ] ( ) #[ " + + "array self with" + ); + + Expect( + Assign, AssignAdd, AssignSubtract, AssignMultiply, + AssignDivide, AssignModulo, AssignBitwiseAnd, AssignBitwiseOr, + AssignBitwiseXor, AssignShiftRight, AssignShiftLeft + ); + + Expect( + Plus, Minus, Divide, Multiply, Modulo, BitwiseAnd, BitwiseNot, + BitwiseOr, BitwiseXor, ShiftLeft, ShiftRight + ); + + Expect( + Ellipsis, Associate, RightArrow, Decrement, Increment, + LogicalAnd, LogicalOr, LogicalNot + ); + + Expect( + DeepEqual, DeepNotEqual, Equal, NotEqual, GreaterThan, + LessThan, GreaterThanOrEqual, LessThanOrEqual + ); + + Expect( + Length, AsNumber, AsString, QuestionMark, Colon, Semicolon, + Comma, Dot, LBrace, RBrace, LBracket, RBracket, LParenthesis, + RParenthesis, AttributeList + ); + + Expect(Array, Self, With); + + Expect(EOF); + } - [Test] - public void Aliases() - { - _lexer.LoadSource("NaN Infinity"); - Expect(NaN, Infinity, EOF); - } + [Test] + public void Aliases() + { + _lexer.LoadSource("NaN Infinity"); + Expect(NaN, Infinity, EOF); + } - [Test] - public void Identifiers() - { - _lexer.LoadSource("identifier_1 identifier_2 identifier_3"); - - ExpectExact( - (TokenType.Identifier, "identifier_1"), - (TokenType.Identifier, "identifier_2"), - (TokenType.Identifier, "identifier_3") - ); - - Expect(EOF); - } + [Test] + public void Identifiers() + { + _lexer.LoadSource("identifier_1 identifier_2 identifier_3"); - [Test] - public void DecimalNumbers() - { - _lexer.LoadSource("21.37 44.11 .42 27.0 31.1 .1 12"); - - ExpectExact( - (TokenType.Number, "21.37"), - (TokenType.Number, "44.11"), - (TokenType.Number, ".42"), - (TokenType.Number, "27.0"), - (TokenType.Number, "31.1"), - (TokenType.Number, ".1"), - (TokenType.Number, "12") - ); - - Expect(EOF); - } - - [Test] - public void HexIntegers() - { - _lexer.LoadSource( - "0x1 0x12 0x123 0x1234 0x12345 0x123456 0x1234567 " + - "0x12345678 0xDEADBEEF13371 0x1D34d 0x2CafE 0x3b33f" - ); - - ExpectExact( - (TokenType.HexInteger, "1"), - (TokenType.HexInteger, "12"), - (TokenType.HexInteger, "123"), - (TokenType.HexInteger, "1234"), - (TokenType.HexInteger, "12345"), - (TokenType.HexInteger, "123456"), - (TokenType.HexInteger, "1234567"), - (TokenType.HexInteger, "12345678"), - (TokenType.HexInteger, "DEADBEEF13371"), - (TokenType.HexInteger, "1D34d"), - (TokenType.HexInteger, "2CafE"), - (TokenType.HexInteger, "3b33f") - - ); - - Expect(EOF); - } + ExpectExact( + (TokenType.Identifier, "identifier_1"), + (TokenType.Identifier, "identifier_2"), + (TokenType.Identifier, "identifier_3") + ); - [Test] - public void Strings() - { - _lexer.LoadSource( - "'single-quoted string' " + - "'single-quoted string with \\' escape' " + - "\"double quoted string\" " + - "\"double quoted string with \\\" escape\" " + - "'this is a \\uABCD \\x1234'" - ); - - ExpectExact( - (TokenType.PlainString, "single-quoted string"), - (TokenType.PlainString, "single-quoted string with ' escape"), - (TokenType.InterpolatedString, "double quoted string"), - (TokenType.InterpolatedString, "double quoted string with \" escape"), - (TokenType.PlainString, "this is a \uABCD \x1234") - ); - - Expect(EOF); - } + Expect(EOF); + } - [Test] - public void TypeCodes() - { - _lexer.LoadSource( - "Nil Number Boolean String " + - "Table Function Type " + - "NativeFunction NativeObject" - ); - - Expect(NilTypeCode, NumberTypeCode, BooleanTypeCode, StringTypeCode); - Expect(TableTypeCode, ChunkTypeCode, TypeCodeTypeCode); - Expect(NativeFunctionTypeCode, NativeObjectTypeCode); - Expect(EOF); - } + [Test] + public void DecimalNumbers() + { + _lexer.LoadSource("21.37 44.11 .42 27.0 31.1 .1 12"); + + ExpectExact( + (TokenType.Number, "21.37"), + (TokenType.Number, "44.11"), + (TokenType.Number, ".42"), + (TokenType.Number, "27.0"), + (TokenType.Number, "31.1"), + (TokenType.Number, ".1"), + (TokenType.Number, "12") + ); + + Expect(EOF); + } + + [Test] + public void HexIntegers() + { + _lexer.LoadSource( + "0x1 0x12 0x123 0x1234 0x12345 0x123456 0x1234567 " + + "0x12345678 0xDEADBEEF13371 0x1D34d 0x2CafE 0x3b33f" + ); + + ExpectExact( + (TokenType.HexInteger, "1"), + (TokenType.HexInteger, "12"), + (TokenType.HexInteger, "123"), + (TokenType.HexInteger, "1234"), + (TokenType.HexInteger, "12345"), + (TokenType.HexInteger, "123456"), + (TokenType.HexInteger, "1234567"), + (TokenType.HexInteger, "12345678"), + (TokenType.HexInteger, "DEADBEEF13371"), + (TokenType.HexInteger, "1D34d"), + (TokenType.HexInteger, "2CafE"), + (TokenType.HexInteger, "3b33f") + ); + + Expect(EOF); + } + + [Test] + public void Strings() + { + _lexer.LoadSource( + "'single-quoted string' " + + "'single-quoted string with \\' escape' " + + "\"double quoted string\" " + + "\"double quoted string with \\\" escape\" " + + "'this is a \\uABCD \\x1234'" + ); + + ExpectExact( + (TokenType.PlainString, "single-quoted string"), + (TokenType.PlainString, "single-quoted string with ' escape"), + (TokenType.InterpolatedString, "double quoted string"), + (TokenType.InterpolatedString, "double quoted string with \" escape"), + (TokenType.PlainString, "this is a \uABCD \x1234") + ); + + Expect(EOF); + } + + [Test] + public void TypeCodes() + { + _lexer.LoadSource( + "Nil Number Boolean String " + + "Table Function Type " + + "NativeFunction NativeObject" + ); + + Expect(NilTypeCode, NumberTypeCode, BooleanTypeCode, StringTypeCode); + Expect(TableTypeCode, ChunkTypeCode, TypeCodeTypeCode); + Expect(NativeFunctionTypeCode, NativeObjectTypeCode); + Expect(EOF); } } \ No newline at end of file diff --git a/Core/Tests/EVIL.CoreTests/ParserTests/ParserTestBase.cs b/Core/Tests/EVIL.CoreTests/ParserTests/ParserTestBase.cs index da2f2a19..f47fa0df 100644 --- a/Core/Tests/EVIL.CoreTests/ParserTests/ParserTestBase.cs +++ b/Core/Tests/EVIL.CoreTests/ParserTests/ParserTestBase.cs @@ -1,26 +1,25 @@ +namespace EVIL.CoreTests.ParserTests; + using EVIL.Grammar.AST.Miscellaneous; using EVIL.Grammar.Parsing; using NUnit.Framework; -namespace EVIL.CoreTests.ParserTests +public abstract class ParserTestBase { - public abstract class ParserTestBase - { - protected Parser _parser = null!; + protected Parser _parser = null!; - [SetUp] - public virtual void Setup() - { - _parser = new Parser(); - } - - [TearDown] - public virtual void Teardown() - { - _parser = null!; - } + [SetUp] + public virtual void Setup() + { + _parser = new Parser(); + } - protected ProgramNode BuildProgramTree(string source) - => _parser.Parse(source); + [TearDown] + public virtual void Teardown() + { + _parser = null!; } + + protected ProgramNode BuildProgramTree(string source) + => _parser.Parse(source); } \ No newline at end of file diff --git a/FrontEnd/EVIL.evil/EvmFrontEnd.Utilities.cs b/FrontEnd/EVIL.evil/EvmFrontEnd.Utilities.cs index 19fffa88..a6966802 100644 --- a/FrontEnd/EVIL.evil/EvmFrontEnd.Utilities.cs +++ b/FrontEnd/EVIL.evil/EvmFrontEnd.Utilities.cs @@ -1,3 +1,5 @@ +namespace EVIL.evil; + using System; using System.Text; using EVIL.Ceres.ExecutionEngine; @@ -5,57 +7,54 @@ using EVIL.Grammar.Parsing; using EVIL.Lexical; -namespace EVIL.evil +public partial class EvmFrontEnd { - public partial class EvmFrontEnd + private static string BuildVersionBanner() { - private static string BuildVersionBanner() - { - var sb = new StringBuilder(); - sb.AppendLine("Integrated EVIL front-end environment."); - sb.AppendLine("This project is distributed under GPLv3 license."); - sb.AppendLine(); - sb.AppendLine("--[component versions]--------"); - sb.AppendLine($" EVM front-end: v{GetAssemblyVersionFromType()}"); - sb.AppendLine($" EVIL lexer: v{GetAssemblyVersionFromType()}"); - sb.AppendLine($" EVIL parser: v{GetAssemblyVersionFromType()}"); - sb.AppendLine($" EVIL.Ceres VM: v{GetAssemblyVersionFromType()}"); - sb.AppendLine($"EVIL.Ceres.Runtime: v{GetAssemblyVersionFromType()}"); + var sb = new StringBuilder(); + sb.AppendLine("Integrated EVIL front-end environment."); + sb.AppendLine("This project is distributed under GPLv3 license."); + sb.AppendLine(); + sb.AppendLine("--[component versions]--------"); + sb.AppendLine($" EVM front-end: v{GetAssemblyVersionFromType()}"); + sb.AppendLine($" EVIL lexer: v{GetAssemblyVersionFromType()}"); + sb.AppendLine($" EVIL parser: v{GetAssemblyVersionFromType()}"); + sb.AppendLine($" EVIL.Ceres VM: v{GetAssemblyVersionFromType()}"); + sb.AppendLine($"EVIL.Ceres.Runtime: v{GetAssemblyVersionFromType()}"); - return sb.ToString(); - } + return sb.ToString(); + } - private static string GetAssemblyVersionFromType() - { - var type = typeof(T); - var asm = type.Assembly; - var name = asm.GetName(); - var version = name.Version!; + private static string GetAssemblyVersionFromType() + { + var type = typeof(T); + var asm = type.Assembly; + var name = asm.GetName(); + var version = name.Version!; - return $"{version.Major}.{version.Minor}.{version.Build}"; - } + return $"{version.Major}.{version.Minor}.{version.Build}"; + } - private static void Message(string msg) + private static void Message(string msg) + { + Console.WriteLine(msg); + } + + private static void Terminate(string? msg = null, bool writeHelp = false, ExitCode exitCode = ExitCode.OK) + { + if (msg != null) { - Console.WriteLine(msg); + Message(msg); } - private static void Terminate(string? msg = null, bool writeHelp = false, ExitCode exitCode = ExitCode.OK) + if (writeHelp) { - if (msg != null) - { - Message(msg); - } - - if (writeHelp) - { - _options.WriteOptionDescriptions( - Console.Out - ); - } - - Console.Out.Flush(); - Environment.Exit((int)exitCode); + _options.WriteOptionDescriptions( + Console.Out + ); } + + Console.Out.Flush(); + Environment.Exit((int)exitCode); } } \ No newline at end of file diff --git a/FrontEnd/EVIL.evil/EvmFrontEnd.cs b/FrontEnd/EVIL.evil/EvmFrontEnd.cs index f52a97fd..2c4f9447 100644 --- a/FrontEnd/EVIL.evil/EvmFrontEnd.cs +++ b/FrontEnd/EVIL.evil/EvmFrontEnd.cs @@ -1,3 +1,7 @@ +namespace EVIL.evil; + +using EvilArray = EVIL.Ceres.ExecutionEngine.Collections.Array; + using System; using System.Collections.Generic; using System.IO; @@ -14,381 +18,377 @@ using EVIL.Grammar; using EVIL.Lexical; using Mono.Options; -using EvilArray = EVIL.Ceres.ExecutionEngine.Collections.Array; -namespace EVIL.evil +public partial class EvmFrontEnd { - public partial class EvmFrontEnd - { - private static CeresVM _vm = new(CrashHandler); - private static Compiler _compiler = new(); - private static EvilRuntime _runtime = new(_vm); - private static RuntimeModuleLoader _runtimeModuleLoader = new(_runtime); + private static CeresVM _vm = new(CrashHandler); + private static Compiler _compiler = new(); + private static EvilRuntime _runtime = new(_vm); + private static RuntimeModuleLoader _runtimeModuleLoader = new(_runtime); - private static OptionSet _options = new() + private static OptionSet _options = new() + { + { "h|help", "display this message and quit.", (h) => _displayHelpAndQuit = h != null }, + { "v|version", "display compiler and VM version information.", (v) => _displayVersionAndQuit = v != null }, + { "g|gen-docs", "generate documentation for all detected native modules.", (g) => _generateModuleDocsAndQuit = g != null }, + { "d|disasm", "disassemble the compiled script.", (d) => _disassembleCompiledScript = d != null }, + { "o|optimize", "optimize generated code.", (o) => _optimizeCode = o != null }, + { "c|compile-only=", "don't run, compile only requires a file name", (o) => { - { "h|help", "display this message and quit.", (h) => _displayHelpAndQuit = h != null }, - { "v|version", "display compiler and VM version information.", (v) => _displayVersionAndQuit = v != null }, - { "g|gen-docs", "generate documentation for all detected native modules.", (g) => _generateModuleDocsAndQuit = g != null }, - { "d|disasm", "disassemble the compiled script.", (d) => _disassembleCompiledScript = d != null }, - { "o|optimize", "optimize generated code.", (o) => _optimizeCode = o != null }, - { "c|compile-only=", "don't run, compile only requires a file name", (o) => - { - _compileOnly = !string.IsNullOrEmpty(o); - _outputFileName = o; - }} - }; - - private static bool _displayHelpAndQuit; - private static bool _displayVersionAndQuit; - private static bool _generateModuleDocsAndQuit; - private static bool _disassembleCompiledScript; - private static bool _optimizeCode; - private static bool _compileOnly; - private static string _outputFileName = "a.evx"; + _compileOnly = !string.IsNullOrEmpty(o); + _outputFileName = o; + }} + }; + + private static bool _displayHelpAndQuit; + private static bool _displayVersionAndQuit; + private static bool _generateModuleDocsAndQuit; + private static bool _disassembleCompiledScript; + private static bool _optimizeCode; + private static bool _compileOnly; + private static string _outputFileName = "a.evx"; - public async Task Run(string[] args) - { - var extra = InitializeOptions(args); + public async Task Run(string[] args) + { + var extra = InitializeOptions(args); - if (_displayHelpAndQuit) - { - Terminate(writeHelp: true); - } + if (_displayHelpAndQuit) + { + Terminate(writeHelp: true); + } - if (_displayVersionAndQuit) - { - Terminate(BuildVersionBanner()); - } + if (_displayVersionAndQuit) + { + Terminate(BuildVersionBanner()); + } - if (_generateModuleDocsAndQuit) - { - GenerateModuleDocs(); - Terminate(); - } + if (_generateModuleDocsAndQuit) + { + GenerateModuleDocs(); + Terminate(); + } - if (_optimizeCode) - { - _compiler.OptimizeCodeGeneration = true; - } + if (_optimizeCode) + { + _compiler.OptimizeCodeGeneration = true; + } - if (!extra.Any()) - { - Terminate( - "Fatal: no input file.", - exitCode: ExitCode.NoInputFiles - ); - } + if (!extra.Any()) + { + Terminate( + "Fatal: no input file.", + exitCode: ExitCode.NoInputFiles + ); + } - if (extra.Count > 1) - { - Terminate( - "Fatal: too many input files.", - exitCode: ExitCode.TooManyInputFiles - ); - } + if (extra.Count > 1) + { + Terminate( + "Fatal: too many input files.", + exitCode: ExitCode.TooManyInputFiles + ); + } - var scriptPath = extra.First(); - if (!File.Exists(scriptPath)) - { - Terminate( - "Fatal: input file does not exist.", - exitCode: ExitCode.InputFileDoesNotExist - ); - } + var scriptPath = extra.First(); + if (!File.Exists(scriptPath)) + { + Terminate( + "Fatal: input file does not exist.", + exitCode: ExitCode.InputFileDoesNotExist + ); + } - var scriptArgs = extra - .Skip(1) - .Select(x => new DynamicValue(x)) - .ToArray(); + var scriptArgs = extra + .Skip(1) + .Select(x => new DynamicValue(x)) + .ToArray(); - var source = File.ReadAllText(scriptPath); - - Chunk rootChunk = null!; - try - { - rootChunk = _compiler.Compile(source, scriptPath); - } - catch (LexerException le) - { - Terminate( - $"Syntax error in {scriptPath} ({le.Line}:{le.Column}): {le.Message}", - exitCode: ExitCode.LexerError - ); - } - catch (ParserException pe) - { - Terminate( - $"Syntax error in {scriptPath} ({pe.Line}:{pe.Column}): {pe.Message}", - exitCode: ExitCode.ParserError - ); - } - catch (CompilerException ce) - { - var msg = $"Compilation error in {scriptPath}:\n" + - $" {ce.Log.Messages.Last()}"; + var source = File.ReadAllText(scriptPath); - if (ce.InnerException != null - && ce.InnerException is not ParserException - and not DuplicateSymbolException) - { - msg += $"\n\n {ce.InnerException.Message}"; - } - - Terminate(msg, exitCode: ExitCode.CompilerError); - } - - if (_disassembleCompiledScript) - { - Console.WriteLine($"Disassembly of '{scriptPath}'\n-------------------"); - Disassembler.Disassemble(rootChunk, Console.Out); - } + Chunk rootChunk = null!; + try + { + rootChunk = _compiler.Compile(source, scriptPath); + } + catch (LexerException le) + { + Terminate( + $"Syntax error in {scriptPath} ({le.Line}:{le.Column}): {le.Message}", + exitCode: ExitCode.LexerError + ); + } + catch (ParserException pe) + { + Terminate( + $"Syntax error in {scriptPath} ({pe.Line}:{pe.Column}): {pe.Message}", + exitCode: ExitCode.ParserError + ); + } + catch (CompilerException ce) + { + var msg = $"Compilation error in {scriptPath}:\n" + + $" {ce.Log.Messages.Last()}"; - if (_compiler.Log.HasAnyMessages) + if (ce.InnerException != null + && ce.InnerException is not ParserException + and not DuplicateSymbolException) { - Console.WriteLine(_compiler.Log.ToString()); + msg += $"\n\n {ce.InnerException.Message}"; } + + Terminate(msg, exitCode: ExitCode.CompilerError); + } - if (_compileOnly) - { - try - { - using var fs = new FileStream( - Path.Combine( - Environment.CurrentDirectory, - _outputFileName - ), - FileMode.Create - ); - - rootChunk.Serialize(fs); - } - catch (Exception e) - { - Terminate($"Fatal: unable to write executable to disk - {e.Message}"); - } + if (_disassembleCompiledScript) + { + Console.WriteLine($"Disassembly of '{scriptPath}'\n-------------------"); + Disassembler.Disassemble(rootChunk, Console.Out); + } - return; - } - - RegisterAllModules(); - SetStandardGlobals(scriptPath); + if (_compiler.Log.HasAnyMessages) + { + Console.WriteLine(_compiler.Log.ToString()); + } + if (_compileOnly) + { try { - _runtime.RegisterBuiltInFunctions(); + using var fs = new FileStream( + Path.Combine( + Environment.CurrentDirectory, + _outputFileName + ), + FileMode.Create + ); + + rootChunk.Serialize(fs); } - catch (EvilRuntimeException e) + catch (Exception e) { - var msg = $"Internal error: {e.Message}"; - if (e.InnerException is CompilerException ce) - { - msg += "See below for details:\n\n"; - msg += $"{ce.Message}\n{ce.Log}"; - } - - Terminate(msg); + Terminate($"Fatal: unable to write executable to disk - {e.Message}"); } - _vm.Start(); + return; + } - _vm.MainFiber.Schedule(rootChunk, scriptArgs); - await _vm.MainFiber.BlockUntilFinishedAsync(); + RegisterAllModules(); + SetStandardGlobals(scriptPath); - while (_vm.MainFiber.State == FiberState.Crashed) + try + { + _runtime.RegisterBuiltInFunctions(); + } + catch (EvilRuntimeException e) + { + var msg = $"Internal error: {e.Message}"; + if (e.InnerException is CompilerException ce) { - await Task.Delay(1); + msg += "See below for details:\n\n"; + msg += $"{ce.Message}\n{ce.Log}"; } + + Terminate(msg); } - private List InitializeOptions(string[] args) + _vm.Start(); + + _vm.MainFiber.Schedule(rootChunk, scriptArgs); + await _vm.MainFiber.BlockUntilFinishedAsync(); + + while (_vm.MainFiber.State == FiberState.Crashed) { - List fileNames = new(); + await Task.Delay(1); + } + } - try - { - var extra = _options.Parse(args); + private List InitializeOptions(string[] args) + { + List fileNames = new(); - if (extra != null) - { - fileNames.AddRange(extra); - } - } - catch (OptionException oe) + try + { + var extra = _options.Parse(args); + + if (extra != null) { - Terminate( - $"Fatal: {oe.Message}\nrun with `--help' to see usage instructions", - exitCode: ExitCode.GenericError - ); + fileNames.AddRange(extra); } - - return fileNames; } - - private void GenerateModuleDocs() + catch (OptionException oe) { - var modules = RegisterAllModules(); - var docsPath = Path.Combine( - AppContext.BaseDirectory, - "docs" + Terminate( + $"Fatal: {oe.Message}\nrun with `--help' to see usage instructions", + exitCode: ExitCode.GenericError ); + } + + return fileNames; + } + + private void GenerateModuleDocs() + { + var modules = RegisterAllModules(); + var docsPath = Path.Combine( + AppContext.BaseDirectory, + "docs" + ); - Directory.CreateDirectory(docsPath); + Directory.CreateDirectory(docsPath); - foreach (var module in modules) - { - var filePath = Path.Combine(docsPath, $"evrt_{module.FullyQualifiedName}.doc.md"); - Console.WriteLine($"Generating '{filePath}'..."); + foreach (var module in modules) + { + var filePath = Path.Combine(docsPath, $"evrt_{module.FullyQualifiedName}.doc.md"); + Console.WriteLine($"Generating '{filePath}'..."); - using (var sw = new StreamWriter(filePath)) - { - sw.WriteLine(module.Describe()); - } + using (var sw = new StreamWriter(filePath)) + { + sw.WriteLine(module.Describe()); } } + } - private List RegisterAllModules() - { - var ret = new List(); + private List RegisterAllModules() + { + var ret = new List(); - ret.AddRange(_runtime.RegisterBuiltInModules()); + ret.AddRange(_runtime.RegisterBuiltInModules()); - var moduleStorePath = Path.Combine(AppContext.BaseDirectory, "modules"); - if (Directory.Exists(moduleStorePath)) + var moduleStorePath = Path.Combine(AppContext.BaseDirectory, "modules"); + if (Directory.Exists(moduleStorePath)) + { + try { - try - { - ret.AddRange(_runtimeModuleLoader.RegisterUserRuntimeModules(moduleStorePath)); - } - catch (RuntimeModuleLoadException rmle) - { - var sb = new StringBuilder(); - sb.AppendLine($"Failed to load user runtime module '{rmle.FilePath}'."); - sb.AppendLine(rmle.ToString()); + ret.AddRange(_runtimeModuleLoader.RegisterUserRuntimeModules(moduleStorePath)); + } + catch (RuntimeModuleLoadException rmle) + { + var sb = new StringBuilder(); + sb.AppendLine($"Failed to load user runtime module '{rmle.FilePath}'."); + sb.AppendLine(rmle.ToString()); - Terminate(sb.ToString(), exitCode: ExitCode.ModuleLoaderFailed); - } + Terminate(sb.ToString(), exitCode: ExitCode.ModuleLoaderFailed); } - - return ret; } - private void SetStandardGlobals(string scriptPath) - { - _vm.Global["_G"] = _vm.Global; + return ret; + } + + private void SetStandardGlobals(string scriptPath) + { + _vm.Global["_G"] = _vm.Global; - _vm.Global["__SCRIPT_HOME"] = ( - Path.GetDirectoryName(scriptPath) ?? string.Empty - ).Replace('\\', '/'); + _vm.Global["__SCRIPT_HOME"] = ( + Path.GetDirectoryName(scriptPath) ?? string.Empty + ).Replace('\\', '/'); - _vm.Global["__SCRIPT_FILE"] = Path.GetFileName(scriptPath); + _vm.Global["__SCRIPT_FILE"] = Path.GetFileName(scriptPath); - var importConfigPath = Path.Combine( - AppContext.BaseDirectory, - "config", - "default.imports" - ); + var importConfigPath = Path.Combine( + AppContext.BaseDirectory, + "config", + "default.imports" + ); - var evilHomeDir = AppContext.BaseDirectory - .Replace('\\', '/') - .TrimEnd('/'); + var evilHomeDir = AppContext.BaseDirectory + .Replace('\\', '/') + .TrimEnd('/'); - var appDataDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) - .Replace('\\', '/') - .TrimEnd('/'); + var appDataDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + .Replace('\\', '/') + .TrimEnd('/'); - if (File.Exists(importConfigPath)) - { - var lines = File.ReadAllLines(importConfigPath); - var array = new EvilArray(lines.Length); - - for (var i = 0; i < lines.Length; i++) - { - array[i] = lines[i] - .Replace("$EVILHOME", evilHomeDir) - .Replace("$APPDATA", appDataDir); - } + if (File.Exists(importConfigPath)) + { + var lines = File.ReadAllLines(importConfigPath); + var array = new EvilArray(lines.Length); - _vm.Global["__IMPORT_PATHS"] = array; + for (var i = 0; i < lines.Length; i++) + { + array[i] = lines[i] + .Replace("$EVILHOME", evilHomeDir) + .Replace("$APPDATA", appDataDir); } + + _vm.Global["__IMPORT_PATHS"] = array; } + } - private static void CrashHandler(Fiber fiber, Exception exception) + private static void CrashHandler(Fiber fiber, Exception exception) + { + var fiberArray = _vm.Scheduler.Fibers.ToArray(); + var fiberIndex = Array.IndexOf(fiberArray, fiber); + + StackFrame[] callStack; + + if (exception is UserUnhandledExceptionException uuee) + { + callStack = uuee.EvilStackTrace; + } + else { - var fiberArray = _vm.Scheduler.Fibers.ToArray(); - var fiberIndex = Array.IndexOf(fiberArray, fiber); + callStack = fiber.CallStack.ToArray(); + } - StackFrame[] callStack; + TerminateWithError(fiberIndex, callStack, exception); + } - if (exception is UserUnhandledExceptionException uuee) - { - callStack = uuee.EvilStackTrace; - } - else - { - callStack = fiber.CallStack.ToArray(); - } + private static void TerminateWithError(int fiberIndex, StackFrame[] callStack, Exception exception) + { + var top = callStack[0]; + ScriptStackFrame? scriptTop = null; - TerminateWithError(fiberIndex, callStack, exception); + var sb = new StringBuilder(); + + if (top is NativeStackFrame) + { + scriptTop = callStack[1].As(); } - - private static void TerminateWithError(int fiberIndex, StackFrame[] callStack, Exception exception) + else { - var top = callStack[0]; - ScriptStackFrame? scriptTop = null; + scriptTop = top.As(); + } - var sb = new StringBuilder(); + var dd = scriptTop.Chunk.DebugDatabase; + + sb.Append($"Runtime error in fiber {fiberIndex}, function {scriptTop.Chunk.Name}"); - if (top is NativeStackFrame) - { - scriptTop = callStack[1].As(); - } - else + if (!string.IsNullOrEmpty(scriptTop.Chunk.DebugDatabase.DefinedInFile)) + { + sb.Append($" (def. in {scriptTop.Chunk.DebugDatabase.DefinedInFile}"); + + if (scriptTop.Chunk.DebugDatabase.DefinedOnLine > 0) { - scriptTop = top.As(); + sb.Append($", on line {scriptTop.Chunk.DebugDatabase.DefinedOnLine}"); } - var dd = scriptTop.Chunk.DebugDatabase; - - sb.Append($"Runtime error in fiber {fiberIndex}, function {scriptTop.Chunk.Name}"); + sb.Append(")"); + } + sb.AppendLine(": "); - if (!string.IsNullOrEmpty(scriptTop.Chunk.DebugDatabase.DefinedInFile)) + sb.Append($"{dd.DefinedInFile}:{dd.GetLineForIP((int)scriptTop.PreviousOpCodeIP)}: "); + sb.Append(exception.Message); + + if (exception is UserUnhandledExceptionException uuee) + { + if (uuee.EvilExceptionObject.Type == DynamicValueType.Error) { - sb.Append($" (def. in {scriptTop.Chunk.DebugDatabase.DefinedInFile}"); - - if (scriptTop.Chunk.DebugDatabase.DefinedOnLine > 0) + var msg = uuee.EvilExceptionObject.Error!["msg"]; + if (msg.Type == DynamicValueType.String) { - sb.Append($", on line {scriptTop.Chunk.DebugDatabase.DefinedOnLine}"); + sb.Append($" ({msg.String})"); } - - sb.Append(")"); } - sb.AppendLine(": "); - - sb.Append($"{dd.DefinedInFile}:{dd.GetLineForIP((int)scriptTop.PreviousOpCodeIP)}: "); - sb.Append(exception.Message); - - if (exception is UserUnhandledExceptionException uuee) + else if (uuee.EvilExceptionObject.Type != DynamicValueType.Nil) { - if (uuee.EvilExceptionObject.Type == DynamicValueType.Error) - { - var msg = uuee.EvilExceptionObject.Error!["msg"]; - if (msg.Type == DynamicValueType.String) - { - sb.Append($" ({msg.String})"); - } - } - else if (uuee.EvilExceptionObject.Type != DynamicValueType.Nil) - { - sb.Append($" ({uuee.EvilExceptionObject.ConvertToString().String!})"); - } + sb.Append($" ({uuee.EvilExceptionObject.ConvertToString().String!})"); } + } - sb.AppendLine(); - sb.AppendLine("Stack trace:"); - sb.Append(Fiber.StackTrace(callStack)); + sb.AppendLine(); + sb.AppendLine("Stack trace:"); + sb.Append(Fiber.StackTrace(callStack)); - Terminate(sb.ToString(), exitCode: ExitCode.RuntimeError); - } + Terminate(sb.ToString(), exitCode: ExitCode.RuntimeError); } } \ No newline at end of file diff --git a/FrontEnd/EVIL.evil/ExitCode.cs b/FrontEnd/EVIL.evil/ExitCode.cs index a4ec144d..73585092 100644 --- a/FrontEnd/EVIL.evil/ExitCode.cs +++ b/FrontEnd/EVIL.evil/ExitCode.cs @@ -1,18 +1,17 @@ -namespace EVIL.evil +namespace EVIL.evil; + +public enum ExitCode { - public enum ExitCode - { - OK = 0000, - GenericError = 0001, - ArgumentError = 0002, - NoInputFiles = 0003, - TooManyInputFiles = 0004, - LexerError = 0005, - ParserError = 0006, - CompilerError = 0007, - MissingEntryPoint = 0008, - RuntimeError = 0009, - InputFileDoesNotExist = 0010, - ModuleLoaderFailed = 0011 - } + OK = 0000, + GenericError = 0001, + ArgumentError = 0002, + NoInputFiles = 0003, + TooManyInputFiles = 0004, + LexerError = 0005, + ParserError = 0006, + CompilerError = 0007, + MissingEntryPoint = 0008, + RuntimeError = 0009, + InputFileDoesNotExist = 0010, + ModuleLoaderFailed = 0011 } \ No newline at end of file diff --git a/FrontEnd/EVIL.evil/Program.cs b/FrontEnd/EVIL.evil/Program.cs index 7b2a5148..de0f23d9 100644 --- a/FrontEnd/EVIL.evil/Program.cs +++ b/FrontEnd/EVIL.evil/Program.cs @@ -1,10 +1,9 @@ -using System.Threading.Tasks; +namespace EVIL.evil; -namespace EVIL.evil +using System.Threading.Tasks; + +internal class Program { - internal class Program - { - public static async Task Main(string[] args) - => await new EvmFrontEnd().Run(args); - } + public static async Task Main(string[] args) + => await new EvmFrontEnd().Run(args); } \ No newline at end of file diff --git a/FrontEnd/EVIL.evil/RuntimeModuleLoadException.cs b/FrontEnd/EVIL.evil/RuntimeModuleLoadException.cs index 8958932c..760edb2a 100644 --- a/FrontEnd/EVIL.evil/RuntimeModuleLoadException.cs +++ b/FrontEnd/EVIL.evil/RuntimeModuleLoadException.cs @@ -1,15 +1,14 @@ +namespace EVIL.evil; + using System; -namespace EVIL.evil +public class RuntimeModuleLoadException : Exception { - public class RuntimeModuleLoadException : Exception - { - public string FilePath { get; } + public string FilePath { get; } - public RuntimeModuleLoadException(string message, Exception innerException, string filePath) - : base(message, innerException) - { - FilePath = filePath; - } + public RuntimeModuleLoadException(string message, Exception innerException, string filePath) + : base(message, innerException) + { + FilePath = filePath; } } \ No newline at end of file diff --git a/FrontEnd/EVIL.evil/RuntimeModuleLoader.cs b/FrontEnd/EVIL.evil/RuntimeModuleLoader.cs index 91873f9a..49c9e449 100644 --- a/FrontEnd/EVIL.evil/RuntimeModuleLoader.cs +++ b/FrontEnd/EVIL.evil/RuntimeModuleLoader.cs @@ -1,3 +1,5 @@ +namespace EVIL.evil; + using System; using System.Collections.Generic; using System.IO; @@ -5,45 +7,42 @@ using System.Reflection; using EVIL.Ceres.Runtime; -namespace EVIL.evil +public class RuntimeModuleLoader { - public class RuntimeModuleLoader - { - private const string RuntimeModuleExtensionPattern = "*.evrm.dll"; + private const string RuntimeModuleExtensionPattern = "*.evrm.dll"; - private readonly EvilRuntime _runtime; + private readonly EvilRuntime _runtime; - public RuntimeModuleLoader(EvilRuntime runtime) - { - _runtime = runtime; - } + public RuntimeModuleLoader(EvilRuntime runtime) + { + _runtime = runtime; + } - public List RegisterUserRuntimeModules(string directoryPath) - { - var filePaths = Directory.GetFiles(directoryPath, $"{RuntimeModuleExtensionPattern}"); - var modules = new List(); + public List RegisterUserRuntimeModules(string directoryPath) + { + var filePaths = Directory.GetFiles(directoryPath, $"{RuntimeModuleExtensionPattern}"); + var modules = new List(); - foreach (var filePath in filePaths) + foreach (var filePath in filePaths) + { + try { - try - { - var assembly = Assembly.LoadFrom(filePath); - var types = assembly.GetExportedTypes().Where(t => t.IsAssignableTo(typeof(RuntimeModule))); + var assembly = Assembly.LoadFrom(filePath); + var types = assembly.GetExportedTypes().Where(t => t.IsAssignableTo(typeof(RuntimeModule))); - foreach (var type in types) - { - modules.Add(_runtime.RegisterModule(type, out _)); - } - } - catch (Exception e) + foreach (var type in types) { - throw new RuntimeModuleLoadException("Failed to load a user runtime module.", e, filePath); + modules.Add(_runtime.RegisterModule(type, out _)); } } + catch (Exception e) + { + throw new RuntimeModuleLoadException("Failed to load a user runtime module.", e, filePath); + } + } - return modules; - } + return modules; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/EvilDocArgumentAttribute.cs b/VirtualMachine/EVIL.Ceres.Runtime/EvilDocArgumentAttribute.cs index add44248..36b67127 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/EvilDocArgumentAttribute.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/EvilDocArgumentAttribute.cs @@ -1,43 +1,42 @@ +namespace EVIL.Ceres.Runtime; + using System; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.Runtime +[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] +public class EvilDocArgumentAttribute : Attribute { - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - public class EvilDocArgumentAttribute : Attribute - { - public string Name { get; } - public string Description { get; } + public string Name { get; } + public string Description { get; } - public DynamicValueType PrimaryType { get; } - public DynamicValueType[]? OtherTypes { get; } - public bool IsAnyType { get; } + public DynamicValueType PrimaryType { get; } + public DynamicValueType[]? OtherTypes { get; } + public bool IsAnyType { get; } - public bool CanBeNil { get; init; } - public string? DefaultValue { get; init; } + public bool CanBeNil { get; init; } + public string? DefaultValue { get; init; } - public EvilDocArgumentAttribute(string name, string description, DynamicValueType primaryType, params DynamicValueType[] types) - { - Name = name; - Description = description; - PrimaryType = primaryType; - OtherTypes = types; - } + public EvilDocArgumentAttribute(string name, string description, DynamicValueType primaryType, params DynamicValueType[] types) + { + Name = name; + Description = description; + PrimaryType = primaryType; + OtherTypes = types; + } - public EvilDocArgumentAttribute(string name, string description, DynamicValueType type) - { - Name = name; - Description = description; + public EvilDocArgumentAttribute(string name, string description, DynamicValueType type) + { + Name = name; + Description = description; - PrimaryType = type; - IsAnyType = false; - } + PrimaryType = type; + IsAnyType = false; + } - public EvilDocArgumentAttribute(string name, string description) - { - Name = name; - Description = description; - IsAnyType = true; - } + public EvilDocArgumentAttribute(string name, string description) + { + Name = name; + Description = description; + IsAnyType = true; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/EvilDocFunctionAttribute.cs b/VirtualMachine/EVIL.Ceres.Runtime/EvilDocFunctionAttribute.cs index a38b1211..d42fde97 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/EvilDocFunctionAttribute.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/EvilDocFunctionAttribute.cs @@ -1,22 +1,21 @@ +namespace EVIL.Ceres.Runtime; + using System; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.Runtime +[AttributeUsage(AttributeTargets.Method)] +public class EvilDocFunctionAttribute : Attribute { - [AttributeUsage(AttributeTargets.Method)] - public class EvilDocFunctionAttribute : Attribute - { - public string Description { get; } + public string Description { get; } - public bool IsVariadic { get; set; } = false; - public bool IsAnyReturn { get; set; } = false; + public bool IsVariadic { get; set; } = false; + public bool IsAnyReturn { get; set; } = false; - public DynamicValueType ReturnType { get; set; } = DynamicValueType.Nil; - public string? Returns { get; set; } = "Nothing."; + public DynamicValueType ReturnType { get; set; } = DynamicValueType.Nil; + public string? Returns { get; set; } = "Nothing."; - public EvilDocFunctionAttribute(string description) - { - Description = description; - } + public EvilDocFunctionAttribute(string description) + { + Description = description; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/EvilDocPropertyAttribute.cs b/VirtualMachine/EVIL.Ceres.Runtime/EvilDocPropertyAttribute.cs index 6453f14a..551bac81 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/EvilDocPropertyAttribute.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/EvilDocPropertyAttribute.cs @@ -1,24 +1,23 @@ +namespace EVIL.Ceres.Runtime; + using System; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.Runtime +[AttributeUsage(AttributeTargets.Method)] +public class EvilDocPropertyAttribute : Attribute { - [AttributeUsage(AttributeTargets.Method)] - public class EvilDocPropertyAttribute : Attribute - { - public EvilDocPropertyMode Mode { get; } - public string Description { get; } + public EvilDocPropertyMode Mode { get; } + public string Description { get; } - public bool IsAnyGet { get; set; } = false; - public bool IsAnySet { get; set; } = false; + public bool IsAnyGet { get; set; } = false; + public bool IsAnySet { get; set; } = false; - public DynamicValueType ReturnType { get; set; } = DynamicValueType.Nil; - public DynamicValueType[] InputTypes { get; set; } = new DynamicValueType[0]; + public DynamicValueType ReturnType { get; set; } = DynamicValueType.Nil; + public DynamicValueType[] InputTypes { get; set; } = new DynamicValueType[0]; - public EvilDocPropertyAttribute(EvilDocPropertyMode mode, string description) - { - Mode = mode; - Description = description; - } - } + public EvilDocPropertyAttribute(EvilDocPropertyMode mode, string description) + { + Mode = mode; + Description = description; + } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/EvilDocPropertyMode.cs b/VirtualMachine/EVIL.Ceres.Runtime/EvilDocPropertyMode.cs index a55faafc..d571fd3e 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/EvilDocPropertyMode.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/EvilDocPropertyMode.cs @@ -1,11 +1,10 @@ +namespace EVIL.Ceres.Runtime; + using System; -namespace EVIL.Ceres.Runtime +[Flags] +public enum EvilDocPropertyMode : byte { - [Flags] - public enum EvilDocPropertyMode : byte - { - Get = 1 << 0, - Set = 1 << 1 - } + Get = 1 << 0, + Set = 1 << 1 } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/EvilDocThrowsAttribute.cs b/VirtualMachine/EVIL.Ceres.Runtime/EvilDocThrowsAttribute.cs index 9b03cb3a..63a1fa9c 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/EvilDocThrowsAttribute.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/EvilDocThrowsAttribute.cs @@ -1,18 +1,17 @@ +namespace EVIL.Ceres.Runtime; + using System; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.Runtime +[AttributeUsage(AttributeTargets.Method)] +public class EvilDocThrowsAttribute : Attribute { - [AttributeUsage(AttributeTargets.Method)] - public class EvilDocThrowsAttribute : Attribute - { - public DynamicValueType ThrownType { get; } - public string Description { get; } + public DynamicValueType ThrownType { get; } + public string Description { get; } - public EvilDocThrowsAttribute(DynamicValueType thrownType, string description) - { - ThrownType = thrownType; - Description = description; - } + public EvilDocThrowsAttribute(DynamicValueType thrownType, string description) + { + ThrownType = thrownType; + Description = description; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/EvilRuntime.cs b/VirtualMachine/EVIL.Ceres.Runtime/EvilRuntime.cs index ed385463..b6979938 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/EvilRuntime.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/EvilRuntime.cs @@ -1,4 +1,6 @@ -using System; +namespace EVIL.Ceres.Runtime; + +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -10,88 +12,85 @@ using EVIL.Ceres.Runtime.Modules; using EVIL.Ceres.TranslationEngine; -namespace EVIL.Ceres.Runtime +public sealed class EvilRuntime { - public sealed class EvilRuntime - { - private readonly CeresVM _vm; - private readonly Compiler _compiler; + private readonly CeresVM _vm; + private readonly Compiler _compiler; - private Table Global => _vm.Global; + private Table Global => _vm.Global; - public EvilRuntime(CeresVM vm) - { - _vm = vm; - _compiler = new Compiler(); - } + public EvilRuntime(CeresVM vm) + { + _vm = vm; + _compiler = new Compiler(); + } + + public void RegisterBuiltInFunctions() + { + var scriptNames = Assembly + .GetExecutingAssembly() + .GetManifestResourceNames() + .Where(x => x.StartsWith("EVIL.Ceres.Runtime.ScriptBuiltins")); - public void RegisterBuiltInFunctions() + foreach (var scriptName in scriptNames) { - var scriptNames = Assembly + using var stream = Assembly .GetExecutingAssembly() - .GetManifestResourceNames() - .Where(x => x.StartsWith("EVIL.Ceres.Runtime.ScriptBuiltins")); - - foreach (var scriptName in scriptNames) - { - using var stream = Assembly - .GetExecutingAssembly() - .GetManifestResourceStream(scriptName)!; + .GetManifestResourceStream(scriptName)!; - using var streamReader = new StreamReader(stream); - var fileName = $"builtin::{scriptName}"; + using var streamReader = new StreamReader(stream); + var fileName = $"builtin::{scriptName}"; - try - { - var text = streamReader.ReadToEnd(); - var root = _compiler.Compile(text, fileName); - _vm.MainFiber.Schedule(root); - } - catch (CompilerException e) - { - throw new EvilRuntimeException($"Failed to compile the built-in script '{fileName}'.", e); - } + try + { + var text = streamReader.ReadToEnd(); + var root = _compiler.Compile(text, fileName); + _vm.MainFiber.Schedule(root); + } + catch (CompilerException e) + { + throw new EvilRuntimeException($"Failed to compile the built-in script '{fileName}'.", e); } } + } - public List RegisterBuiltInModules() - { - var modules = new List(); + public List RegisterBuiltInModules() + { + var modules = new List(); - modules.Add(RegisterModule(out _)); - modules.Add(RegisterModule(out _)); - modules.Add(RegisterModule(out _)); - modules.Add(RegisterModule(out _)); - modules.Add(RegisterModule(out _)); - modules.Add(RegisterModule(out _)); - modules.Add(RegisterModule(out _)); - modules.Add(RegisterModule(out _)); - modules.Add(RegisterModule(out _)); - modules.Add(RegisterModule(out _)); - modules.Add(RegisterModule(out _)); + modules.Add(RegisterModule(out _)); + modules.Add(RegisterModule(out _)); + modules.Add(RegisterModule(out _)); + modules.Add(RegisterModule(out _)); + modules.Add(RegisterModule(out _)); + modules.Add(RegisterModule(out _)); + modules.Add(RegisterModule(out _)); + modules.Add(RegisterModule(out _)); + modules.Add(RegisterModule(out _)); + modules.Add(RegisterModule(out _)); + modules.Add(RegisterModule(out _)); - return modules; - } + return modules; + } - public T RegisterModule(out DynamicValue table) where T : RuntimeModule, new() - { - var module = new T(); + public T RegisterModule(out DynamicValue table) where T : RuntimeModule, new() + { + var module = new T(); - table = module.AttachTo(Global); - module.Registered(this); + table = module.AttachTo(Global); + module.Registered(this); - return module; - } - - public RuntimeModule RegisterModule(Type type, out DynamicValue table) - { - var module = (RuntimeModule)Activator.CreateInstance(type)!; - table = module.AttachTo(Global); + return module; + } - return module; - } + public RuntimeModule RegisterModule(Type type, out DynamicValue table) + { + var module = (RuntimeModule)Activator.CreateInstance(type)!; + table = module.AttachTo(Global); - public DynamicValue Register(string fullyQualifiedName, DynamicValue value, bool replaceIfExists = true) - => Global.SetUsingPath(fullyQualifiedName, value, replaceIfExists); + return module; } + + public DynamicValue Register(string fullyQualifiedName, DynamicValue value, bool replaceIfExists = true) + => Global.SetUsingPath(fullyQualifiedName, value, replaceIfExists); } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/EvilRuntimeException.cs b/VirtualMachine/EVIL.Ceres.Runtime/EvilRuntimeException.cs index 87966ab5..93d8ea82 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/EvilRuntimeException.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/EvilRuntimeException.cs @@ -1,17 +1,16 @@ -using System; +namespace EVIL.Ceres.Runtime; -namespace EVIL.Ceres.Runtime +using System; + +public class EvilRuntimeException : Exception { - public class EvilRuntimeException : Exception + public EvilRuntimeException(string message) + : base(message) { - public EvilRuntimeException(string message) - : base(message) - { - } + } - public EvilRuntimeException(string message, Exception innerException) - : base(message, innerException) - { - } + public EvilRuntimeException(string message, Exception innerException) + : base(message, innerException) + { } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Extensions/FunctionArguments.Bounds.cs b/VirtualMachine/EVIL.Ceres.Runtime/Extensions/FunctionArguments.Bounds.cs index 225c3dd7..e360c7e0 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Extensions/FunctionArguments.Bounds.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Extensions/FunctionArguments.Bounds.cs @@ -1,34 +1,33 @@ -using EVIL.Ceres.ExecutionEngine.TypeSystem; +namespace EVIL.Ceres.Runtime.Extensions; -namespace EVIL.Ceres.Runtime.Extensions +using EVIL.Ceres.ExecutionEngine.TypeSystem; + +public static partial class FunctionArguments { - public static partial class FunctionArguments + public static DynamicValue[] ExpectExactly(this DynamicValue[] args, int count) { - public static DynamicValue[] ExpectExactly(this DynamicValue[] args, int count) - { - if (count != args.Length) - throw new EvilRuntimeException($"Expected {(count == 0 ? "no" : count)} arguments, found {args.Length}."); - - return args; - } + if (count != args.Length) + throw new EvilRuntimeException($"Expected {(count == 0 ? "no" : count)} arguments, found {args.Length}."); - public static DynamicValue[] ExpectAtLeast(this DynamicValue[] args, int count) - { - if (args.Length < count) - throw new EvilRuntimeException($"Expected at least {count} arguments, found {args.Length}."); + return args; + } - return args; - } + public static DynamicValue[] ExpectAtLeast(this DynamicValue[] args, int count) + { + if (args.Length < count) + throw new EvilRuntimeException($"Expected at least {count} arguments, found {args.Length}."); - public static DynamicValue[] ExpectAtMost(this DynamicValue[] args, int count) - { - if (args.Length > count) - throw new EvilRuntimeException($"Expected at most {count} arguments, found {args.Length}."); + return args; + } - return args; - } + public static DynamicValue[] ExpectAtMost(this DynamicValue[] args, int count) + { + if (args.Length > count) + throw new EvilRuntimeException($"Expected at most {count} arguments, found {args.Length}."); - public static DynamicValue[] ExpectNone(this DynamicValue[] args) - => args.ExpectExactly(0); + return args; } + + public static DynamicValue[] ExpectNone(this DynamicValue[] args) + => args.ExpectExactly(0); } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Extensions/FunctionArguments.Convert.cs b/VirtualMachine/EVIL.Ceres.Runtime/Extensions/FunctionArguments.Convert.cs index 4790f42d..e805cf6d 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Extensions/FunctionArguments.Convert.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Extensions/FunctionArguments.Convert.cs @@ -1,28 +1,27 @@ -using EVIL.Ceres.ExecutionEngine.Collections; +namespace EVIL.Ceres.Runtime.Extensions; + +using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.TypeSystem; -namespace EVIL.Ceres.Runtime.Extensions +public static partial class FunctionArguments { - public static partial class FunctionArguments + public static Table ToTable(this DynamicValue[] args) { - public static Table ToTable(this DynamicValue[] args) - { - var ret = new Table(); + var ret = new Table(); - for (var i = 0; i < args.Length; i++) - ret[i] = args[i]; + for (var i = 0; i < args.Length; i++) + ret[i] = args[i]; - return ret; - } + return ret; + } - public static Array ToArray(this DynamicValue[] args) - { - var ret = new Array(args.Length); + public static Array ToArray(this DynamicValue[] args) + { + var ret = new Array(args.Length); - for (var i = 0; i < args.Length; i++) - ret[i] = args[i]; + for (var i = 0; i < args.Length; i++) + ret[i] = args[i]; - return ret; - } + return ret; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Extensions/FunctionArguments.Expect.cs b/VirtualMachine/EVIL.Ceres.Runtime/Extensions/FunctionArguments.Expect.cs index a4fafe97..cf1f8f07 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Extensions/FunctionArguments.Expect.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Extensions/FunctionArguments.Expect.cs @@ -1,253 +1,252 @@ -using System.Diagnostics.CodeAnalysis; +namespace EVIL.Ceres.Runtime.Extensions; + +using System.Diagnostics.CodeAnalysis; using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.Concurrency; using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.Runtime.Extensions +public static partial class FunctionArguments { - public static partial class FunctionArguments + public static DynamicValue[] ExpectTypeAt(this DynamicValue[] args, int index, DynamicValueType type, bool allowNil = false) { - public static DynamicValue[] ExpectTypeAt(this DynamicValue[] args, int index, DynamicValueType type, bool allowNil = false) - { - args.ExpectAtLeast(index + 1); + args.ExpectAtLeast(index + 1); - var argType = args[index].Type; + var argType = args[index].Type; - if (argType != type) + if (argType != type) + { + if (allowNil) { - if (allowNil) + if (argType == DynamicValueType.Nil) { - if (argType == DynamicValueType.Nil) - { - return args; - } - else - { - throw new EvilRuntimeException($"Expected a {type} or {DynamicValueType.Nil} at argument index {index}, found {argType}."); - } + return args; + } + else + { + throw new EvilRuntimeException($"Expected a {type} or {DynamicValueType.Nil} at argument index {index}, found {argType}."); } - - throw new EvilRuntimeException($"Expected a {type} at argument index {index}, found {argType}."); } - return args; + throw new EvilRuntimeException($"Expected a {type} at argument index {index}, found {argType}."); } - public static DynamicValue[] ExpectOneOfTypesAt( - this DynamicValue[] args, - int index, - out DynamicValue value, - DynamicValueType firstType, - params DynamicValueType[] types) - { - args.ExpectAtLeast(index + 1); + return args; + } + + public static DynamicValue[] ExpectOneOfTypesAt( + this DynamicValue[] args, + int index, + out DynamicValue value, + DynamicValueType firstType, + params DynamicValueType[] types) + { + args.ExpectAtLeast(index + 1); - var argType = args[index].Type; + var argType = args[index].Type; - if (firstType != argType) + if (firstType != argType) + { + if (System.Array.IndexOf(types, argType) < 0) { - if (System.Array.IndexOf(types, argType) < 0) - { - throw new EvilRuntimeException( - $"Expected one of the following types: [{string.Join(',', types)}] " + - $"at argument index {index}, found {argType}." - ); - } + throw new EvilRuntimeException( + $"Expected one of the following types: [{string.Join(',', types)}] " + + $"at argument index {index}, found {argType}." + ); } + } - value = args[index]; + value = args[index]; - return args; - } + return args; + } - public static DynamicValue[] ExpectNilAt(this DynamicValue[] args, int index) - => args.ExpectTypeAt(index, DynamicValueType.Nil); + public static DynamicValue[] ExpectNilAt(this DynamicValue[] args, int index) + => args.ExpectTypeAt(index, DynamicValueType.Nil); - public static DynamicValue[] ExpectAnyAt(this DynamicValue[] args, int index, out DynamicValue value) - { - args.ExpectAtLeast(index + 1); - value = args[index]; + public static DynamicValue[] ExpectAnyAt(this DynamicValue[] args, int index, out DynamicValue value) + { + args.ExpectAtLeast(index + 1); + value = args[index]; - return args; - } + return args; + } - public static DynamicValue[] ExpectNumberAt( - this DynamicValue[] args, - int index, - out double value, - bool allowNil = false) - { - args.ExpectTypeAt(index, DynamicValueType.Number, allowNil); - value = args[index].Number; + public static DynamicValue[] ExpectNumberAt( + this DynamicValue[] args, + int index, + out double value, + bool allowNil = false) + { + args.ExpectTypeAt(index, DynamicValueType.Number, allowNil); + value = args[index].Number; - return args; - } + return args; + } - public static DynamicValue[] ExpectIntegerAt( - this DynamicValue[] args, - int index, - out long value, - bool allowNil = false) - { - args.ExpectTypeAt(index, DynamicValueType.Number, allowNil); + public static DynamicValue[] ExpectIntegerAt( + this DynamicValue[] args, + int index, + out long value, + bool allowNil = false) + { + args.ExpectTypeAt(index, DynamicValueType.Number, allowNil); - var num = args[index].Number; - if (num % 1 != 0) - throw new EvilRuntimeException($"Expected an integer at argument index {index}."); + var num = args[index].Number; + if (num % 1 != 0) + throw new EvilRuntimeException($"Expected an integer at argument index {index}."); - value = (long)args[index].Number; - return args; - } + value = (long)args[index].Number; + return args; + } - public static DynamicValue[] ExpectStringAt( - this DynamicValue[] args, - int index, - [AllowNull] out string value, - bool allowNil = false) - { - args.ExpectTypeAt(index, DynamicValueType.String, allowNil); - value = args[index].String!; + public static DynamicValue[] ExpectStringAt( + this DynamicValue[] args, + int index, + [AllowNull] out string value, + bool allowNil = false) + { + args.ExpectTypeAt(index, DynamicValueType.String, allowNil); + value = args[index].String!; - return args; - } + return args; + } - public static DynamicValue[] ExpectCharAt( - this DynamicValue[] args, - int index, - out char value, - bool allowNil = false) - { - args.ExpectTypeAt(index, DynamicValueType.String, allowNil); + public static DynamicValue[] ExpectCharAt( + this DynamicValue[] args, + int index, + out char value, + bool allowNil = false) + { + args.ExpectTypeAt(index, DynamicValueType.String, allowNil); - var str = args[index].String!; - if (str.Length != 1) - throw new EvilRuntimeException($"Expected a single character at argument index {index}."); + var str = args[index].String!; + if (str.Length != 1) + throw new EvilRuntimeException($"Expected a single character at argument index {index}."); - value = str[0]; - return args; - } + value = str[0]; + return args; + } - public static DynamicValue[] ExpectBooleanAt( - this DynamicValue[] args, - int index, - out bool value, - bool allowNil = false) - { - args.ExpectTypeAt(index, DynamicValueType.Boolean, allowNil); - value = args[index].Boolean; + public static DynamicValue[] ExpectBooleanAt( + this DynamicValue[] args, + int index, + out bool value, + bool allowNil = false) + { + args.ExpectTypeAt(index, DynamicValueType.Boolean, allowNil); + value = args[index].Boolean; - return args; - } + return args; + } - public static DynamicValue[] ExpectTableAt( - this DynamicValue[] args, - int index, - out Table value, - bool allowNil = false) - { - args.ExpectTypeAt(index, DynamicValueType.Table, allowNil); - value = args[index].Table!; + public static DynamicValue[] ExpectTableAt( + this DynamicValue[] args, + int index, + out Table value, + bool allowNil = false) + { + args.ExpectTypeAt(index, DynamicValueType.Table, allowNil); + value = args[index].Table!; - return args; - } + return args; + } - public static DynamicValue[] ExpectArrayAt( - this DynamicValue[] args, - int index, - out Array value, - bool allowNil = false) - { - args.ExpectTypeAt(index, DynamicValueType.Array, allowNil); - value = args[index].Array!; + public static DynamicValue[] ExpectArrayAt( + this DynamicValue[] args, + int index, + out Array value, + bool allowNil = false) + { + args.ExpectTypeAt(index, DynamicValueType.Array, allowNil); + value = args[index].Array!; - return args; - } + return args; + } - public static DynamicValue[] ExpectFiberAt( - this DynamicValue[] args, - int index, - out Fiber value, - bool allowNil = false) - { - args.ExpectTypeAt(index, DynamicValueType.Fiber, allowNil); - value = args[index].Fiber!; + public static DynamicValue[] ExpectFiberAt( + this DynamicValue[] args, + int index, + out Fiber value, + bool allowNil = false) + { + args.ExpectTypeAt(index, DynamicValueType.Fiber, allowNil); + value = args[index].Fiber!; - return args; - } + return args; + } - public static DynamicValue[] ExpectChunkAt( - this DynamicValue[] args, - int index, - out Chunk value, - bool allowNil = false) - { - args.ExpectTypeAt(index, DynamicValueType.Chunk, allowNil); - value = args[index].Chunk!; + public static DynamicValue[] ExpectChunkAt( + this DynamicValue[] args, + int index, + out Chunk value, + bool allowNil = false) + { + args.ExpectTypeAt(index, DynamicValueType.Chunk, allowNil); + value = args[index].Chunk!; - return args; - } + return args; + } - public static DynamicValue[] ExpectTypeCodeAt( - this DynamicValue[] args, - int index, - out DynamicValueType value, - bool allowNil = false) - { - args.ExpectTypeAt(index, DynamicValueType.TypeCode, allowNil); - value = args[index].TypeCode; + public static DynamicValue[] ExpectTypeCodeAt( + this DynamicValue[] args, + int index, + out DynamicValueType value, + bool allowNil = false) + { + args.ExpectTypeAt(index, DynamicValueType.TypeCode, allowNil); + value = args[index].TypeCode; - return args; - } + return args; + } - public static DynamicValue[] ExpectNativeFunctionAt( - this DynamicValue[] args, - int index, - out NativeFunction value, - bool allowNil = false) - { - args.ExpectTypeAt(index, DynamicValueType.NativeFunction, allowNil); - value = args[index].NativeFunction!; + public static DynamicValue[] ExpectNativeFunctionAt( + this DynamicValue[] args, + int index, + out NativeFunction value, + bool allowNil = false) + { + args.ExpectTypeAt(index, DynamicValueType.NativeFunction, allowNil); + value = args[index].NativeFunction!; - return args; - } + return args; + } - public static DynamicValue[] ExpectNativeObjectAt( - this DynamicValue[] args, - int index, - out object? value, - bool allowNil = false) - { - args.ExpectTypeAt(index, DynamicValueType.NativeObject, allowNil); - value = args[index].NativeObject; + public static DynamicValue[] ExpectNativeObjectAt( + this DynamicValue[] args, + int index, + out object? value, + bool allowNil = false) + { + args.ExpectTypeAt(index, DynamicValueType.NativeObject, allowNil); + value = args[index].NativeObject; - return args; - } + return args; + } - public static DynamicValue[] ExpectNativeObjectAt( - this DynamicValue[] args, - int index, - out T value, - bool allowNil = false) - { - args.ExpectTypeAt(index, DynamicValueType.NativeObject, allowNil); + public static DynamicValue[] ExpectNativeObjectAt( + this DynamicValue[] args, + int index, + out T value, + bool allowNil = false) + { + args.ExpectTypeAt(index, DynamicValueType.NativeObject, allowNil); - if (args[index].NativeObject is not T tValue) + if (args[index].NativeObject is not T tValue) + { + if (args[index].Type == DynamicValueType.Nil && allowNil) { - if (args[index].Type == DynamicValueType.Nil && allowNil) - { - value = default(T)!; - return args; - } - - throw new EvilRuntimeException( - $"A NativeObject value is not the expected CLR type '{typeof(T).FullName}'." - ); + value = default(T)!; + return args; } - value = tValue; - return args; + throw new EvilRuntimeException( + $"A NativeObject value is not the expected CLR type '{typeof(T).FullName}'." + ); } + + value = tValue; + return args; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Extensions/FunctionArguments.Optional.cs b/VirtualMachine/EVIL.Ceres.Runtime/Extensions/FunctionArguments.Optional.cs index 86dcf6f1..15803c00 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Extensions/FunctionArguments.Optional.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Extensions/FunctionArguments.Optional.cs @@ -1,207 +1,207 @@ -using EVIL.Ceres.ExecutionEngine.Collections; +namespace EVIL.Ceres.Runtime.Extensions; + +using static EVIL.Ceres.ExecutionEngine.TypeSystem.DynamicValue; + +using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.Concurrency; using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.CommonTypes.TypeSystem; -using static EVIL.Ceres.ExecutionEngine.TypeSystem.DynamicValue; -namespace EVIL.Ceres.Runtime.Extensions +public static partial class FunctionArguments { - public static partial class FunctionArguments + public static DynamicValue[] OptionalNumberAt(this DynamicValue[] args, int index, double defaultValue, out double value) { - public static DynamicValue[] OptionalNumberAt(this DynamicValue[] args, int index, double defaultValue, out double value) - { - value = defaultValue; + value = defaultValue; - if (index < args.Length) - { - if (args[index] == Nil) - return args; + if (index < args.Length) + { + if (args[index] == Nil) + return args; - args.ExpectNumberAt(index, out value); - } - - return args; + args.ExpectNumberAt(index, out value); } + + return args; + } - public static DynamicValue[] OptionalIntegerAt(this DynamicValue[] args, int index, long defaultValue, out long value) - { - value = defaultValue; + public static DynamicValue[] OptionalIntegerAt(this DynamicValue[] args, int index, long defaultValue, out long value) + { + value = defaultValue; - if (index < args.Length) - { - if (args[index] == Nil) - return args; + if (index < args.Length) + { + if (args[index] == Nil) + return args; - args.ExpectIntegerAt(index, out value); - } - - return args; + args.ExpectIntegerAt(index, out value); } + + return args; + } - public static DynamicValue[] OptionalStringAt(this DynamicValue[] args, int index, string defaultValue, out string value) - { - value = defaultValue; + public static DynamicValue[] OptionalStringAt(this DynamicValue[] args, int index, string defaultValue, out string value) + { + value = defaultValue; - if (index < args.Length) - { - if (args[index] == Nil) - return args; + if (index < args.Length) + { + if (args[index] == Nil) + return args; - args.ExpectStringAt(index, out value); - } - - return args; + args.ExpectStringAt(index, out value); } + + return args; + } - public static DynamicValue[] OptionalCharAt(this DynamicValue[] args, int index, char defaultValue, out char value) - { - value = defaultValue; + public static DynamicValue[] OptionalCharAt(this DynamicValue[] args, int index, char defaultValue, out char value) + { + value = defaultValue; - if (index < args.Length) - { - if (args[index] == Nil) - return args; + if (index < args.Length) + { + if (args[index] == Nil) + return args; - args.ExpectCharAt(index, out value); - } - - return args; + args.ExpectCharAt(index, out value); } + + return args; + } - public static DynamicValue[] OptionalBooleanAt(this DynamicValue[] args, int index, bool defaultValue, out bool value) - { - value = defaultValue; + public static DynamicValue[] OptionalBooleanAt(this DynamicValue[] args, int index, bool defaultValue, out bool value) + { + value = defaultValue; - if (index < args.Length) - { - if (args[index] == Nil) - return args; + if (index < args.Length) + { + if (args[index] == Nil) + return args; - args.ExpectBooleanAt(index, out value); - } - - return args; + args.ExpectBooleanAt(index, out value); } + + return args; + } - public static DynamicValue[] OptionalTableAt(this DynamicValue[] args, int index, Table defaultValue, out Table value) - { - value = defaultValue; + public static DynamicValue[] OptionalTableAt(this DynamicValue[] args, int index, Table defaultValue, out Table value) + { + value = defaultValue; - if (index < args.Length) - { - if (args[index] == Nil) - return args; + if (index < args.Length) + { + if (args[index] == Nil) + return args; - args.ExpectTableAt(index, out value); - } - - return args; + args.ExpectTableAt(index, out value); } - public static DynamicValue[] OptionalArrayAt(this DynamicValue[] args, int index, Array defaultValue, out Array value) - { - value = defaultValue; - - if (index < args.Length) - { - if (args[index] == Nil) - return args; + return args; + } - args.ExpectArrayAt(index, out value); - } + public static DynamicValue[] OptionalArrayAt(this DynamicValue[] args, int index, Array defaultValue, out Array value) + { + value = defaultValue; + + if (index < args.Length) + { + if (args[index] == Nil) + return args; - return args; + args.ExpectArrayAt(index, out value); } + + return args; + } - public static DynamicValue[] OptionalFiberAt(this DynamicValue[] args, int index, Fiber defaultValue, out Fiber value) - { - value = defaultValue; + public static DynamicValue[] OptionalFiberAt(this DynamicValue[] args, int index, Fiber defaultValue, out Fiber value) + { + value = defaultValue; - if (index < args.Length) - { - if (args[index] == Nil) - return args; + if (index < args.Length) + { + if (args[index] == Nil) + return args; - args.ExpectFiberAt(index, out value); - } - - return args; + args.ExpectFiberAt(index, out value); } + + return args; + } - public static DynamicValue[] OptionalChunkAt(this DynamicValue[] args, int index, Chunk defaultValue, out Chunk value) - { - value = defaultValue; + public static DynamicValue[] OptionalChunkAt(this DynamicValue[] args, int index, Chunk defaultValue, out Chunk value) + { + value = defaultValue; - if (index < args.Length) - { - if (args[index] == Nil) - return args; + if (index < args.Length) + { + if (args[index] == Nil) + return args; - args.ExpectChunkAt(index, out value); - } - - return args; + args.ExpectChunkAt(index, out value); } - public static DynamicValue[] OptionalTypeCodeAt(this DynamicValue[] args, int index, DynamicValueType defaultValue, out DynamicValueType value) - { - value = defaultValue; + return args; + } - if (index < args.Length) - { - if (args[index] == Nil) - return args; + public static DynamicValue[] OptionalTypeCodeAt(this DynamicValue[] args, int index, DynamicValueType defaultValue, out DynamicValueType value) + { + value = defaultValue; - args.ExpectTypeCodeAt(index, out value); - } + if (index < args.Length) + { + if (args[index] == Nil) + return args; - return args; + args.ExpectTypeCodeAt(index, out value); } + + return args; + } - public static DynamicValue[] OptionalNativeFunctionAt(this DynamicValue[] args, int index, NativeFunction defaultValue, out NativeFunction value) - { - value = defaultValue; + public static DynamicValue[] OptionalNativeFunctionAt(this DynamicValue[] args, int index, NativeFunction defaultValue, out NativeFunction value) + { + value = defaultValue; - if (index < args.Length) - { - if (args[index] == Nil) - return args; + if (index < args.Length) + { + if (args[index] == Nil) + return args; - args.ExpectNativeFunctionAt(index, out value); - } - - return args; + args.ExpectNativeFunctionAt(index, out value); } + + return args; + } - public static DynamicValue[] OptionalNativeObjectAt(this DynamicValue[] args, int index, object? defaultValue, out object? value) - { - value = defaultValue; + public static DynamicValue[] OptionalNativeObjectAt(this DynamicValue[] args, int index, object? defaultValue, out object? value) + { + value = defaultValue; - if (index < args.Length) - { - if (args[index] == Nil) - return args; + if (index < args.Length) + { + if (args[index] == Nil) + return args; - args.ExpectNativeObjectAt(index, out value); - } - - return args; + args.ExpectNativeObjectAt(index, out value); } - public static DynamicValue[] OptionalNativeObjectAt(this DynamicValue[] args, int index, T defaultValue, out T value) - { - value = defaultValue; + return args; + } - if (index < args.Length) - { - if (args[index] == Nil) - return args; + public static DynamicValue[] OptionalNativeObjectAt(this DynamicValue[] args, int index, T defaultValue, out T value) + { + value = defaultValue; - args.ExpectNativeObjectAt(index, out value); - } + if (index < args.Length) + { + if (args[index] == Nil) + return args; - return args; + args.ExpectNativeObjectAt(index, out value); } + + return args; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Extensions/TableExtensions.cs b/VirtualMachine/EVIL.Ceres.Runtime/Extensions/TableExtensions.cs index f99a16f5..78ebea2c 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Extensions/TableExtensions.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Extensions/TableExtensions.cs @@ -1,157 +1,156 @@ -using System.Linq; +namespace EVIL.Ceres.Runtime.Extensions; + +using System.Linq; using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.Runtime.Extensions +public static class TableExtensions { - public static class TableExtensions + public static DynamicValue SetUsingPath(this Table table, string fullyQualifiedName, DynamicValue value, bool replaceIfExists = true) + where TSubTable: Table, new() { - public static DynamicValue SetUsingPath(this Table table, string fullyQualifiedName, DynamicValue value, bool replaceIfExists = true) - where TSubTable: Table, new() + var segments = fullyQualifiedName.Split("."); + var tablePath = segments + .SkipLast(1) + .ToArray(); + + var memberName = segments.Last(); + var currentTable = table; + foreach (var tableName in tablePath) { - var segments = fullyQualifiedName.Split("."); - var tablePath = segments - .SkipLast(1) - .ToArray(); - - var memberName = segments.Last(); - var currentTable = table; - foreach (var tableName in tablePath) + if (!currentTable.Contains(tableName)) + { + currentTable.Set( + tableName, + new TSubTable() + ); + } + else { - if (!currentTable.Contains(tableName)) + if (currentTable[tableName].Type != DynamicValueType.Table) { - currentTable.Set( - tableName, - new TSubTable() + throw new EvilRuntimeException( + $"Attempted to set '{value}' as '{fullyQualifiedName}', but '{tableName}' is not a Table." ); } - else - { - if (currentTable[tableName].Type != DynamicValueType.Table) - { - throw new EvilRuntimeException( - $"Attempted to set '{value}' as '{fullyQualifiedName}', but '{tableName}' is not a Table." - ); - } - } - - currentTable = currentTable[tableName].Table!; } - if (currentTable.Contains(memberName) && !replaceIfExists) - { - throw new EvilRuntimeException( - $"Attempt to set '{value}' as '{fullyQualifiedName}', but '{memberName}' already exists in the target Table." - ); - } + currentTable = currentTable[tableName].Table!; + } - if (currentTable.IsFrozen) - { - throw new EvilRuntimeException( - $"Attempt to set '{value}' as '{fullyQualifiedName}', but the target Table is frozen." - ); - } + if (currentTable.Contains(memberName) && !replaceIfExists) + { + throw new EvilRuntimeException( + $"Attempt to set '{value}' as '{fullyQualifiedName}', but '{memberName}' already exists in the target Table." + ); + } - currentTable.Set(memberName, value); - return value; + if (currentTable.IsFrozen) + { + throw new EvilRuntimeException( + $"Attempt to set '{value}' as '{fullyQualifiedName}', but the target Table is frozen." + ); } - public static bool ContainsPath(this Table table, string fullyQualifiedName) + currentTable.Set(memberName, value); + return value; + } + + public static bool ContainsPath(this Table table, string fullyQualifiedName) + { + var segments = fullyQualifiedName.Split("."); + var tablePath = segments + .SkipLast(1) + .ToArray(); + + var memberName = segments.Last(); + var currentTable = table; + foreach (var tableName in tablePath) { - var segments = fullyQualifiedName.Split("."); - var tablePath = segments - .SkipLast(1) - .ToArray(); - - var memberName = segments.Last(); - var currentTable = table; - foreach (var tableName in tablePath) + if (!(currentTable.Contains(tableName) && currentTable[tableName].Type == DynamicValueType.Table)) { - if (!(currentTable.Contains(tableName) && currentTable[tableName].Type == DynamicValueType.Table)) - { - return false; - } - - currentTable = currentTable[tableName].Table!; + return false; } - return currentTable.Contains(memberName); + currentTable = currentTable[tableName].Table!; } + + return currentTable.Contains(memberName); + } - public static bool ContainsValuePath(this PropertyTable table, string fullyQualifiedName) + public static bool ContainsValuePath(this PropertyTable table, string fullyQualifiedName) + { + var segments = fullyQualifiedName.Split("."); + var tablePath = segments + .SkipLast(1) + .ToArray(); + + var memberName = segments.Last(); + var currentTable = (Table)table; + foreach (var tableName in tablePath) { - var segments = fullyQualifiedName.Split("."); - var tablePath = segments - .SkipLast(1) - .ToArray(); - - var memberName = segments.Last(); - var currentTable = (Table)table; - foreach (var tableName in tablePath) + if (!(currentTable.Contains(tableName) && currentTable[tableName].Type == DynamicValueType.Table)) { - if (!(currentTable.Contains(tableName) && currentTable[tableName].Type == DynamicValueType.Table)) - { - return false; - } - - currentTable = currentTable[tableName].Table!; + return false; } - if (currentTable is not PropertyTable pt) - return false; - - return pt.ContainsValue(memberName); + currentTable = currentTable[tableName].Table!; } + + if (currentTable is not PropertyTable pt) + return false; + + return pt.ContainsValue(memberName); + } - public static bool ContainsGetterPath(this PropertyTable table, string fullyQualifiedName) + public static bool ContainsGetterPath(this PropertyTable table, string fullyQualifiedName) + { + var segments = fullyQualifiedName.Split("."); + var tablePath = segments + .SkipLast(1) + .ToArray(); + + var memberName = segments.Last(); + var currentTable = (Table)table; + foreach (var tableName in tablePath) { - var segments = fullyQualifiedName.Split("."); - var tablePath = segments - .SkipLast(1) - .ToArray(); - - var memberName = segments.Last(); - var currentTable = (Table)table; - foreach (var tableName in tablePath) + if (!(currentTable.Contains(tableName) && currentTable[tableName].Type == DynamicValueType.Table)) { - if (!(currentTable.Contains(tableName) && currentTable[tableName].Type == DynamicValueType.Table)) - { - return false; - } - - currentTable = currentTable[tableName].Table!; + return false; } - if (currentTable is not PropertyTable pt) - return false; - - return pt.ContainsGetter(memberName); + currentTable = currentTable[tableName].Table!; } + + if (currentTable is not PropertyTable pt) + return false; + + return pt.ContainsGetter(memberName); + } - public static bool ContainsSetterPath(this PropertyTable table, string fullyQualifiedName) + public static bool ContainsSetterPath(this PropertyTable table, string fullyQualifiedName) + { + var segments = fullyQualifiedName.Split("."); + var tablePath = segments + .SkipLast(1) + .ToArray(); + + var memberName = segments.Last(); + var currentTable = (Table)table; + foreach (var tableName in tablePath) { - var segments = fullyQualifiedName.Split("."); - var tablePath = segments - .SkipLast(1) - .ToArray(); - - var memberName = segments.Last(); - var currentTable = (Table)table; - foreach (var tableName in tablePath) + if (!(currentTable.Contains(tableName) && currentTable[tableName].Type == DynamicValueType.Table)) { - if (!(currentTable.Contains(tableName) && currentTable[tableName].Type == DynamicValueType.Table)) - { - return false; - } - - currentTable = currentTable[tableName].Table!; + return false; } - if (currentTable is not PropertyTable pt) - return false; - - return pt.ContainsSetter(memberName); + currentTable = currentTable[tableName].Table!; } + + if (currentTable is not PropertyTable pt) + return false; + + return pt.ContainsSetter(memberName); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Modules/ArrayModule.cs b/VirtualMachine/EVIL.Ceres.Runtime/Modules/ArrayModule.cs index 30ef805d..b137865b 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Modules/ArrayModule.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Modules/ArrayModule.cs @@ -1,121 +1,121 @@ +namespace EVIL.Ceres.Runtime.Modules; + +using static EVIL.CommonTypes.TypeSystem.DynamicValueType; + using System.Linq; using EVIL.Ceres.ExecutionEngine.Concurrency; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.Ceres.Runtime.Extensions; -using static EVIL.CommonTypes.TypeSystem.DynamicValueType; -namespace EVIL.Ceres.Runtime.Modules +public class ArrayModule : RuntimeModule { - public class ArrayModule : RuntimeModule - { - public override string FullyQualifiedName => "arr"; + public override string FullyQualifiedName => "arr"; - [RuntimeModuleFunction("index_of")] - [EvilDocFunction( - "Searches the given array for an index of the given value.", - Returns = "A 0-based index of the first matching element in the given array or -1 if not found.", - ReturnType = Number - )] - [EvilDocArgument("array", "An array to be searched.", Array)] - [EvilDocArgument("value", "A value to be searched for.")] - private static DynamicValue IndexOf(Fiber _, params DynamicValue[] args) - { - args.ExpectArrayAt(0, out var array) - .ExpectAnyAt(1, out var value); + [RuntimeModuleFunction("index_of")] + [EvilDocFunction( + "Searches the given array for an index of the given value.", + Returns = "A 0-based index of the first matching element in the given array or -1 if not found.", + ReturnType = Number + )] + [EvilDocArgument("array", "An array to be searched.", Array)] + [EvilDocArgument("value", "A value to be searched for.")] + private static DynamicValue IndexOf(Fiber _, params DynamicValue[] args) + { + args.ExpectArrayAt(0, out var array) + .ExpectAnyAt(1, out var value); - return array.IndexOf(value); - } + return array.IndexOf(value); + } - [RuntimeModuleFunction("fill")] - [EvilDocFunction("Fills the given array with the given value.")] - [EvilDocArgument("array", "An array to be filled with the given value.", Array)] - [EvilDocArgument("value", "A value to fill the given array with.")] - private static DynamicValue Fill(Fiber _, params DynamicValue[] args) - { - args.ExpectArrayAt(0, out var array) - .ExpectAnyAt(1, out var value); + [RuntimeModuleFunction("fill")] + [EvilDocFunction("Fills the given array with the given value.")] + [EvilDocArgument("array", "An array to be filled with the given value.", Array)] + [EvilDocArgument("value", "A value to fill the given array with.")] + private static DynamicValue Fill(Fiber _, params DynamicValue[] args) + { + args.ExpectArrayAt(0, out var array) + .ExpectAnyAt(1, out var value); - array.Fill(value); + array.Fill(value); - return DynamicValue.Nil; - } + return DynamicValue.Nil; + } - [RuntimeModuleFunction("resize")] - [EvilDocFunction( - "Attempts to resize the given array to match the given size. Existing contents are preserved.", - Returns = "New size of the array or -1 if the operation fails.", - ReturnType = Number - )] - [EvilDocArgument("array", "An array to be resized.", Array)] - [EvilDocArgument("size", "An integer specifying the new array size.", Number)] - private static DynamicValue Resize(Fiber _, params DynamicValue[] args) - { - args.ExpectArrayAt(0, out var array) - .ExpectIntegerAt(1, out var size); + [RuntimeModuleFunction("resize")] + [EvilDocFunction( + "Attempts to resize the given array to match the given size. Existing contents are preserved.", + Returns = "New size of the array or -1 if the operation fails.", + ReturnType = Number + )] + [EvilDocArgument("array", "An array to be resized.", Array)] + [EvilDocArgument("size", "An integer specifying the new array size.", Number)] + private static DynamicValue Resize(Fiber _, params DynamicValue[] args) + { + args.ExpectArrayAt(0, out var array) + .ExpectIntegerAt(1, out var size); - return array.Resize((int)size); - } + return array.Resize((int)size); + } - [RuntimeModuleFunction("push")] - [EvilDocFunction( - "Appends the given values at the end of the given array.", - Returns = "Size of the array after the values have been appended.", - ReturnType = Number, - IsVariadic = true - )] - [EvilDocArgument("array", "An array to append the given values to.", Array)] - [EvilDocArgument("...", "An arbitrary amount of values to be appended to the given array.")] - private static DynamicValue Push(Fiber _, params DynamicValue[] args) - { - args.ExpectArrayAt(0, out var array); + [RuntimeModuleFunction("push")] + [EvilDocFunction( + "Appends the given values at the end of the given array.", + Returns = "Size of the array after the values have been appended.", + ReturnType = Number, + IsVariadic = true + )] + [EvilDocArgument("array", "An array to append the given values to.", Array)] + [EvilDocArgument("...", "An arbitrary amount of values to be appended to the given array.")] + private static DynamicValue Push(Fiber _, params DynamicValue[] args) + { + args.ExpectArrayAt(0, out var array); - var values = args.Skip(1).ToArray(); - return array.Push(values); - } + var values = args.Skip(1).ToArray(); + return array.Push(values); + } - [RuntimeModuleFunction("insert")] - [EvilDocFunction( - "Inserts the given values at the given index of the given array", - Returns = "Size of the array after the values have been inserted or -1 if the operation fails.", - ReturnType = Number, - IsVariadic = true - )] - [EvilDocArgument("array", "An array into which the values will be inserted.", Array)] - [EvilDocArgument("index", "An integer specifying the index at which to insert the given values.", Number)] - [EvilDocArgument("...", "An arbitrary amount of values to be inserted into the given array.")] - private static DynamicValue Insert(Fiber _, params DynamicValue[] args) - { - args.ExpectArrayAt(0, out var array) - .ExpectIntegerAt(1, out var index); + [RuntimeModuleFunction("insert")] + [EvilDocFunction( + "Inserts the given values at the given index of the given array", + Returns = "Size of the array after the values have been inserted or -1 if the operation fails.", + ReturnType = Number, + IsVariadic = true + )] + [EvilDocArgument("array", "An array into which the values will be inserted.", Array)] + [EvilDocArgument("index", "An integer specifying the index at which to insert the given values.", Number)] + [EvilDocArgument("...", "An arbitrary amount of values to be inserted into the given array.")] + private static DynamicValue Insert(Fiber _, params DynamicValue[] args) + { + args.ExpectArrayAt(0, out var array) + .ExpectIntegerAt(1, out var index); - var values = args.Skip(2).ToArray(); - return array.Insert((int)index, values); - } + var values = args.Skip(2).ToArray(); + return array.Insert((int)index, values); + } - [RuntimeModuleFunction("rsh")] - [EvilDocFunction( - "Removes the last element of the given array. This operation changes (shrinks) the size of the array.", - Returns = "Array element that has been removed or `nil` if the array was empty.", - IsAnyReturn = true - )] - [EvilDocArgument("array", "An array to remove an element from.", Array)] - private static DynamicValue RightShift(Fiber _, params DynamicValue[] args) - { - args.ExpectArrayAt(0, out var array); - return array.RightShift(); - } + [RuntimeModuleFunction("rsh")] + [EvilDocFunction( + "Removes the last element of the given array. This operation changes (shrinks) the size of the array.", + Returns = "Array element that has been removed or `nil` if the array was empty.", + IsAnyReturn = true + )] + [EvilDocArgument("array", "An array to remove an element from.", Array)] + private static DynamicValue RightShift(Fiber _, params DynamicValue[] args) + { + args.ExpectArrayAt(0, out var array); + return array.RightShift(); + } - [RuntimeModuleFunction("lsh")] - [EvilDocFunction( - "Removes the first element of the given array. This operation changes (shrinks) the size of the array.", - Returns = "Array element that has been removed or `nil` if the array was empty.", - IsAnyReturn = true - )] - [EvilDocArgument("array", "An array to remove an element from.", Array)] - private static DynamicValue Shift(Fiber _, params DynamicValue[] args) - { - args.ExpectArrayAt(0, out var array); - return array.LeftShift(); - } + [RuntimeModuleFunction("lsh")] + [EvilDocFunction( + "Removes the first element of the given array. This operation changes (shrinks) the size of the array.", + Returns = "Array element that has been removed or `nil` if the array was empty.", + IsAnyReturn = true + )] + [EvilDocArgument("array", "An array to remove an element from.", Array)] + private static DynamicValue Shift(Fiber _, params DynamicValue[] args) + { + args.ExpectArrayAt(0, out var array); + return array.LeftShift(); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Modules/ConvertModule.cs b/VirtualMachine/EVIL.Ceres.Runtime/Modules/ConvertModule.cs index 4c17b9ac..5fb8c139 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Modules/ConvertModule.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Modules/ConvertModule.cs @@ -1,132 +1,132 @@ +namespace EVIL.Ceres.Runtime.Modules; + +using static EVIL.CommonTypes.TypeSystem.DynamicValueType; + using EVIL.Ceres.ExecutionEngine.Concurrency; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.Ceres.Runtime.Extensions; -using static EVIL.CommonTypes.TypeSystem.DynamicValueType; -namespace EVIL.Ceres.Runtime.Modules +public class ConvertModule : RuntimeModule { - public class ConvertModule : RuntimeModule - { - public override string FullyQualifiedName => "cnv"; + public override string FullyQualifiedName => "cnv"; - [RuntimeModuleFunction("u64")] - [EvilDocFunction( - "Casts the given number to an unsigned 64-bit integer.", - Returns = "A 64-bit unsigned integer.", - ReturnType = Number - )] - [EvilDocArgument("number", "A number to be converted.", Number)] - private static DynamicValue U64(Fiber _, params DynamicValue[] args) - { - args.ExpectNumberAt(0, out var number); + [RuntimeModuleFunction("u64")] + [EvilDocFunction( + "Casts the given number to an unsigned 64-bit integer.", + Returns = "A 64-bit unsigned integer.", + ReturnType = Number + )] + [EvilDocArgument("number", "A number to be converted.", Number)] + private static DynamicValue U64(Fiber _, params DynamicValue[] args) + { + args.ExpectNumberAt(0, out var number); - var ret = (ulong)number; - return ret; - } + var ret = (ulong)number; + return ret; + } - [RuntimeModuleFunction("u32")] - [EvilDocFunction( - "Casts the given number to an unsigned 32-bit integer. Remember to mask off the relevant bits.", - Returns = "A 32-bit unsigned integer.", - ReturnType = Number - )] - [EvilDocArgument("number", "A number to be converted.", Number)] - private static DynamicValue U32(Fiber _, params DynamicValue[] args) - { - args.ExpectNumberAt(0, out var number); + [RuntimeModuleFunction("u32")] + [EvilDocFunction( + "Casts the given number to an unsigned 32-bit integer. Remember to mask off the relevant bits.", + Returns = "A 32-bit unsigned integer.", + ReturnType = Number + )] + [EvilDocArgument("number", "A number to be converted.", Number)] + private static DynamicValue U32(Fiber _, params DynamicValue[] args) + { + args.ExpectNumberAt(0, out var number); - var ret = (uint)number; - return ret; - } + var ret = (uint)number; + return ret; + } - [RuntimeModuleFunction("u16")] - [EvilDocFunction( - "Casts the given number to an unsigned 16-bit integer. Remember to mask off the relevant bits.", - Returns = "A 16-bit unsigned integer.", - ReturnType = Number - )] - [EvilDocArgument("number", "A number to be converted.", Number)] - private static DynamicValue U16(Fiber _, params DynamicValue[] args) - { - args.ExpectNumberAt(0, out var number); + [RuntimeModuleFunction("u16")] + [EvilDocFunction( + "Casts the given number to an unsigned 16-bit integer. Remember to mask off the relevant bits.", + Returns = "A 16-bit unsigned integer.", + ReturnType = Number + )] + [EvilDocArgument("number", "A number to be converted.", Number)] + private static DynamicValue U16(Fiber _, params DynamicValue[] args) + { + args.ExpectNumberAt(0, out var number); - var ret = (ushort)number; - return ret; - } + var ret = (ushort)number; + return ret; + } - [RuntimeModuleFunction("u8")] - [EvilDocFunction( - "Casts the given number to an unsigned 8-bit integer. Remember to mask off the relevant bits.", - Returns = "An 8-bit unsigned integer.", - ReturnType = Number - )] - [EvilDocArgument("number", "A number to be converted.", Number)] - private static DynamicValue U8(Fiber _, params DynamicValue[] args) - { - args.ExpectNumberAt(0, out var number); + [RuntimeModuleFunction("u8")] + [EvilDocFunction( + "Casts the given number to an unsigned 8-bit integer. Remember to mask off the relevant bits.", + Returns = "An 8-bit unsigned integer.", + ReturnType = Number + )] + [EvilDocArgument("number", "A number to be converted.", Number)] + private static DynamicValue U8(Fiber _, params DynamicValue[] args) + { + args.ExpectNumberAt(0, out var number); - var ret = (byte)number; - return ret; - } + var ret = (byte)number; + return ret; + } - [RuntimeModuleFunction("i8")] - [EvilDocFunction( - "Casts the given number to a signed 8-bit integer. Remember to mask off the relevant bits.", - Returns = "An 8-bit signed integer.", - ReturnType = Number - )] - [EvilDocArgument("number", "A number to be converted.", Number)] - private static DynamicValue I8(Fiber _, params DynamicValue[] args) - { - args.ExpectNumberAt(0, out var number); + [RuntimeModuleFunction("i8")] + [EvilDocFunction( + "Casts the given number to a signed 8-bit integer. Remember to mask off the relevant bits.", + Returns = "An 8-bit signed integer.", + ReturnType = Number + )] + [EvilDocArgument("number", "A number to be converted.", Number)] + private static DynamicValue I8(Fiber _, params DynamicValue[] args) + { + args.ExpectNumberAt(0, out var number); - var ret = (sbyte)number; - return ret; - } + var ret = (sbyte)number; + return ret; + } - [RuntimeModuleFunction("i16")] - [EvilDocFunction( - "Casts the given number to a signed 16-bit integer. Remember to mask off the relevant bits.", - Returns = "A 16-bit signed integer.", - ReturnType = Number - )] - [EvilDocArgument("number", "A number to be converted.", Number)] - private static DynamicValue I16(Fiber _, params DynamicValue[] args) - { - args.ExpectNumberAt(0, out var number); + [RuntimeModuleFunction("i16")] + [EvilDocFunction( + "Casts the given number to a signed 16-bit integer. Remember to mask off the relevant bits.", + Returns = "A 16-bit signed integer.", + ReturnType = Number + )] + [EvilDocArgument("number", "A number to be converted.", Number)] + private static DynamicValue I16(Fiber _, params DynamicValue[] args) + { + args.ExpectNumberAt(0, out var number); - var ret = (short)number; - return ret; - } + var ret = (short)number; + return ret; + } - [RuntimeModuleFunction("i32")] - [EvilDocFunction( - "Casts the given number to a signed 32-bit integer. Remember to mask off the relevant bits.", - Returns = "A 32-bit signed integer.", - ReturnType = Number - )] - [EvilDocArgument("number", "A number to be converted.", Number)] - private static DynamicValue I32(Fiber _, params DynamicValue[] args) - { - args.ExpectNumberAt(0, out var number); + [RuntimeModuleFunction("i32")] + [EvilDocFunction( + "Casts the given number to a signed 32-bit integer. Remember to mask off the relevant bits.", + Returns = "A 32-bit signed integer.", + ReturnType = Number + )] + [EvilDocArgument("number", "A number to be converted.", Number)] + private static DynamicValue I32(Fiber _, params DynamicValue[] args) + { + args.ExpectNumberAt(0, out var number); - var ret = (int)number; - return ret; - } + var ret = (int)number; + return ret; + } - [RuntimeModuleFunction("i64")] - [EvilDocFunction( - "Casts the given number to a signed 64-bit integer.", - Returns = "A 64-bit signed integer.", - ReturnType = Number - )] - [EvilDocArgument("number", "A number to be converted.", Number)] - private static DynamicValue I64(Fiber _, params DynamicValue[] args) - { - args.ExpectNumberAt(0, out var number); + [RuntimeModuleFunction("i64")] + [EvilDocFunction( + "Casts the given number to a signed 64-bit integer.", + Returns = "A 64-bit signed integer.", + ReturnType = Number + )] + [EvilDocArgument("number", "A number to be converted.", Number)] + private static DynamicValue I64(Fiber _, params DynamicValue[] args) + { + args.ExpectNumberAt(0, out var number); - var ret = (long)number; - return ret; - } + var ret = (long)number; + return ret; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Modules/CoreModule.cs b/VirtualMachine/EVIL.Ceres.Runtime/Modules/CoreModule.cs index f63ec971..dcdc30b0 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Modules/CoreModule.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Modules/CoreModule.cs @@ -1,28 +1,27 @@ -using EVIL.Ceres.ExecutionEngine.Concurrency; +namespace EVIL.Ceres.Runtime.Modules; + +using EVIL.Ceres.ExecutionEngine.Concurrency; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.Ceres.Runtime.Extensions; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.Runtime.Modules +public sealed class CoreModule : RuntimeModule { - public sealed class CoreModule : RuntimeModule - { - public override string FullyQualifiedName => "core"; + public override string FullyQualifiedName => "core"; - [RuntimeModuleFunction("fail")] - [EvilDocFunction( - "Terminates VM execution with a user-requested runtime failure. This function does not return." - )] - [EvilDocArgument( - "message", - "The message that should be displayed for the failure.", - DynamicValueType.String, - DefaultValue = "no details provided" - )] - private static DynamicValue Fail(Fiber fiber, params DynamicValue[] args) - { - args.OptionalStringAt(0, "no details provided", out var message); - throw new UserFailException(message, fiber, args); - } + [RuntimeModuleFunction("fail")] + [EvilDocFunction( + "Terminates VM execution with a user-requested runtime failure. This function does not return." + )] + [EvilDocArgument( + "message", + "The message that should be displayed for the failure.", + DynamicValueType.String, + DefaultValue = "no details provided" + )] + private static DynamicValue Fail(Fiber fiber, params DynamicValue[] args) + { + args.OptionalStringAt(0, "no details provided", out var message); + throw new UserFailException(message, fiber, args); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Modules/DebugModule.GC.cs b/VirtualMachine/EVIL.Ceres.Runtime/Modules/DebugModule.GC.cs index ad075a61..b93b47e6 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Modules/DebugModule.GC.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Modules/DebugModule.GC.cs @@ -1,76 +1,75 @@ -using System; +namespace EVIL.Ceres.Runtime.Modules; + +using System; using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.Concurrency; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.Ceres.Runtime.Extensions; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.Runtime.Modules +public partial class DebugModule { - public partial class DebugModule + [RuntimeModuleFunction("gc.mem.get_used_total")] + [EvilDocFunction( + "Attempts to retrieve the amount of managed memory currently thought to be allocated.", + Returns = "The amount of managed memory - in bytes - currently thought to be allocated.", + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument( + "force_full_collection", + "`true` to indicate waiting for GC, `false` to return an immediate value.", + DynamicValueType.Boolean, + DefaultValue = "false" + )] + private static DynamicValue GcMemGetTotal(Fiber _, params DynamicValue[] args) { - [RuntimeModuleFunction("gc.mem.get_used_total")] - [EvilDocFunction( - "Attempts to retrieve the amount of managed memory currently thought to be allocated.", - Returns = "The amount of managed memory - in bytes - currently thought to be allocated.", - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument( - "force_full_collection", - "`true` to indicate waiting for GC, `false` to return an immediate value.", - DynamicValueType.Boolean, - DefaultValue = "false" - )] - private static DynamicValue GcMemGetTotal(Fiber _, params DynamicValue[] args) - { - args.ExpectAtMost(1); - args.OptionalBooleanAt(0, false, out var forceFullCollection); - - return GC.GetTotalMemory(forceFullCollection); - } + args.ExpectAtMost(1); + args.OptionalBooleanAt(0, false, out var forceFullCollection); - [RuntimeModuleFunction("gc.mem.get_info")] - [EvilDocFunction( - "Retrieves memory statistics of the garbage collector.", - Returns = "A table containing information about GC memory statistics.", - ReturnType = DynamicValueType.Table - )] - private static DynamicValue GcMemGetInfo(Fiber _, params DynamicValue[] args) - { - args.ExpectNone(); + return GC.GetTotalMemory(forceFullCollection); + } - var info = GC.GetGCMemoryInfo(); + [RuntimeModuleFunction("gc.mem.get_info")] + [EvilDocFunction( + "Retrieves memory statistics of the garbage collector.", + Returns = "A table containing information about GC memory statistics.", + ReturnType = DynamicValueType.Table + )] + private static DynamicValue GcMemGetInfo(Fiber _, params DynamicValue[] args) + { + args.ExpectNone(); - return new Table - { - ["index"] = info.Index, - ["generation"] = info.Generation, - ["is_compacted"] = info.Compacted, - ["is_concurrent"] = info.Concurrent, - ["finalization_pending_count"] = info.FinalizationPendingCount, - ["fragmented_bytes"] = info.FragmentedBytes, - ["promoted_bytes"] = info.PromotedBytes, - ["heap_size_bytes"] = info.HeapSizeBytes, - ["total_committed_bytes"] = info.TotalCommittedBytes, - ["total_avail_mem_bytes"] = info.TotalAvailableMemoryBytes, - ["pause_time_percent"] = info.PauseTimePercentage, - ["pinned_object_count"] = info.PinnedObjectsCount - }; - } + var info = GC.GetGCMemoryInfo(); - [RuntimeModuleFunction("gc.collect")] - [EvilDocFunction("Forces a compacting asynchronous aggressive garbage collection for all generations.")] - private static DynamicValue GcCollect(Fiber _, params DynamicValue[] args) + return new Table { - args.ExpectNone(); - GC.Collect( - GC.MaxGeneration, - GCCollectionMode.Aggressive, - false, - true - ); + ["index"] = info.Index, + ["generation"] = info.Generation, + ["is_compacted"] = info.Compacted, + ["is_concurrent"] = info.Concurrent, + ["finalization_pending_count"] = info.FinalizationPendingCount, + ["fragmented_bytes"] = info.FragmentedBytes, + ["promoted_bytes"] = info.PromotedBytes, + ["heap_size_bytes"] = info.HeapSizeBytes, + ["total_committed_bytes"] = info.TotalCommittedBytes, + ["total_avail_mem_bytes"] = info.TotalAvailableMemoryBytes, + ["pause_time_percent"] = info.PauseTimePercentage, + ["pinned_object_count"] = info.PinnedObjectsCount + }; + } + + [RuntimeModuleFunction("gc.collect")] + [EvilDocFunction("Forces a compacting asynchronous aggressive garbage collection for all generations.")] + private static DynamicValue GcCollect(Fiber _, params DynamicValue[] args) + { + args.ExpectNone(); + GC.Collect( + GC.MaxGeneration, + GCCollectionMode.Aggressive, + false, + true + ); - return DynamicValue.Nil; - } + return DynamicValue.Nil; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Modules/DebugModule.cs b/VirtualMachine/EVIL.Ceres.Runtime/Modules/DebugModule.cs index 615e3c0f..b928654b 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Modules/DebugModule.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Modules/DebugModule.cs @@ -1,119 +1,117 @@ -using EVIL.Ceres.ExecutionEngine.Collections; +namespace EVIL.Ceres.Runtime.Modules; + +using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.Concurrency; using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.Ceres.Runtime.Extensions; using EVIL.CommonTypes.TypeSystem; -using Array = EVIL.Ceres.ExecutionEngine.Collections.Array; -namespace EVIL.Ceres.Runtime.Modules +public partial class DebugModule : RuntimeModule { - public partial class DebugModule : RuntimeModule - { - public override string FullyQualifiedName => "debug"; + public override string FullyQualifiedName => "debug"; - [RuntimeModuleFunction("strace")] - [EvilDocFunction( - "Gets the current stack trace in the form of raw data.", - Returns = "Array containing Table values with stack frame information available at the time of invocation.", - ReturnType = DynamicValueType.Array - )] - [EvilDocArgument( - "skip_native_frames", - "Set to `true` to skip CLR (native) frames, `false` to include them in the output.", - DynamicValueType.Boolean, - DefaultValue = "false" - )] - private static DynamicValue StackTrace(Fiber fiber, params DynamicValue[] args) - { - args.ExpectAtMost(1) - .OptionalBooleanAt(0, defaultValue: false, out var skipNativeFrames); + [RuntimeModuleFunction("strace")] + [EvilDocFunction( + "Gets the current stack trace in the form of raw data.", + Returns = "Array containing Table values with stack frame information available at the time of invocation.", + ReturnType = DynamicValueType.Array + )] + [EvilDocArgument( + "skip_native_frames", + "Set to `true` to skip CLR (native) frames, `false` to include them in the output.", + DynamicValueType.Boolean, + DefaultValue = "false" + )] + private static DynamicValue StackTrace(Fiber fiber, params DynamicValue[] args) + { + args.ExpectAtMost(1) + .OptionalBooleanAt(0, defaultValue: false, out var skipNativeFrames); - var callStack = fiber.CallStack.ToArray(skipNativeFrames); - var array = new Array(callStack.Length); + var callStack = fiber.CallStack.ToArray(skipNativeFrames); + var array = new Array(callStack.Length); - for (var i = 0; i < callStack.Length; i++) + for (var i = 0; i < callStack.Length; i++) + { + if (callStack[i] is ScriptStackFrame ssf) { - if (callStack[i] is ScriptStackFrame ssf) + array[i] = new Table { - array[i] = new Table - { - { "is_script", true }, - { "fn_name", ssf.Chunk.Name ?? "" }, - { "ip", ssf.IP }, - { "line", ssf.Chunk.HasDebugInfo ? ssf.Chunk.DebugDatabase.GetLineForIP((int)ssf.PreviousOpCodeIP) : DynamicValue.Nil }, - { "locals", ssf.Locals?.ToTable() ?? DynamicValue.Nil }, - { "args", ssf.Arguments.ToTable() }, - { "xargs", new Array(ssf.ExtraArguments) }, - { "has_self", ssf.Chunk.IsSelfAware }, - { "def_on_line", ssf.Chunk.DebugDatabase.DefinedOnLine > 0 ? ssf.Chunk.DebugDatabase.DefinedOnLine : DynamicValue.Nil }, - { "def_in_file", !string.IsNullOrEmpty(ssf.Chunk.DebugDatabase.DefinedInFile) ? ssf.Chunk.DebugDatabase.DefinedInFile : DynamicValue.Nil } - }; - } - else if (callStack[i] is NativeStackFrame nsf && !skipNativeFrames) + { "is_script", true }, + { "fn_name", ssf.Chunk.Name ?? "" }, + { "ip", ssf.IP }, + { "line", ssf.Chunk.HasDebugInfo ? ssf.Chunk.DebugDatabase.GetLineForIP((int)ssf.PreviousOpCodeIP) : DynamicValue.Nil }, + { "locals", ssf.Locals?.ToTable() ?? DynamicValue.Nil }, + { "args", ssf.Arguments.ToTable() }, + { "xargs", new Array(ssf.ExtraArguments) }, + { "has_self", ssf.Chunk.IsSelfAware }, + { "def_on_line", ssf.Chunk.DebugDatabase.DefinedOnLine > 0 ? ssf.Chunk.DebugDatabase.DefinedOnLine : DynamicValue.Nil }, + { "def_in_file", !string.IsNullOrEmpty(ssf.Chunk.DebugDatabase.DefinedInFile) ? ssf.Chunk.DebugDatabase.DefinedInFile : DynamicValue.Nil } + }; + } + else if (callStack[i] is NativeStackFrame nsf && !skipNativeFrames) + { + array[i] = new Table { - array[i] = new Table - { - { "is_script", false }, - { "fn_name", nsf.NativeFunction.Method.Name }, - { "decl_type", nsf.NativeFunction.Method.DeclaringType!.FullName! }, - }; - } + { "is_script", false }, + { "fn_name", nsf.NativeFunction.Method.Name }, + { "decl_type", nsf.NativeFunction.Method.DeclaringType!.FullName! }, + }; } - - return array; } + + return array; + } - [RuntimeModuleFunction("strace_s")] - [EvilDocFunction( - "Gets the current stack trace as a formatted string.", - Returns = "Formatted string containing the stack trace available at the time of the invocation.", - ReturnType = DynamicValueType.Boolean - )] - [EvilDocArgument( - "skip_native_frames", - "Set to `true` to CLR (native) frames, `false` to include them in the output.", - DynamicValueType.Boolean, - DefaultValue = "false" - )] - private static DynamicValue StackTraceString(Fiber fiber, params DynamicValue[] args) - { - args.ExpectAtMost(1) - .OptionalBooleanAt(0, defaultValue: false, out var skipNativeFrames); + [RuntimeModuleFunction("strace_s")] + [EvilDocFunction( + "Gets the current stack trace as a formatted string.", + Returns = "Formatted string containing the stack trace available at the time of the invocation.", + ReturnType = DynamicValueType.Boolean + )] + [EvilDocArgument( + "skip_native_frames", + "Set to `true` to CLR (native) frames, `false` to include them in the output.", + DynamicValueType.Boolean, + DefaultValue = "false" + )] + private static DynamicValue StackTraceString(Fiber fiber, params DynamicValue[] args) + { + args.ExpectAtMost(1) + .OptionalBooleanAt(0, defaultValue: false, out var skipNativeFrames); - return fiber.StackTrace(skipNativeFrames); - } + return fiber.StackTrace(skipNativeFrames); + } - [RuntimeModuleFunction("assert")] - [EvilDocFunction( - "Throws if the provided condition does not evaluate to a `true`.", - ReturnType = DynamicValueType.Nil - )] - [EvilDocArgument( - "expr", - "Expression to be evaluated and checked for truth.", - DynamicValueType.Boolean, - CanBeNil = false - )] - [EvilDocArgument( - "fail_msg", - "Message to be set for the thrown Error if assertion fails.", - DynamicValueType.String, - CanBeNil = true, - DefaultValue = "Assertion failed." - )] - private static DynamicValue Assert(Fiber fiber, params DynamicValue[] args) - { - args.ExpectAtLeast(1) - .ExpectBooleanAt(0, out var expr) - .OptionalStringAt(1, "Assertion failed.", out var failMsg); + [RuntimeModuleFunction("assert")] + [EvilDocFunction( + "Throws if the provided condition does not evaluate to a `true`.", + ReturnType = DynamicValueType.Nil + )] + [EvilDocArgument( + "expr", + "Expression to be evaluated and checked for truth.", + DynamicValueType.Boolean, + CanBeNil = false + )] + [EvilDocArgument( + "fail_msg", + "Message to be set for the thrown Error if assertion fails.", + DynamicValueType.String, + CanBeNil = true, + DefaultValue = "Assertion failed." + )] + private static DynamicValue Assert(Fiber fiber, params DynamicValue[] args) + { + args.ExpectAtLeast(1) + .ExpectBooleanAt(0, out var expr) + .OptionalStringAt(1, "Assertion failed.", out var failMsg); - if (!expr) - { - return fiber.ThrowFromNative(new Error(failMsg)); - } - - return DynamicValue.Nil; + if (!expr) + { + return fiber.ThrowFromNative(new Error(failMsg)); } + + return DynamicValue.Nil; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Modules/EvilModule.cs b/VirtualMachine/EVIL.Ceres.Runtime/Modules/EvilModule.cs index ac4717e5..7ea2ed91 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Modules/EvilModule.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Modules/EvilModule.cs @@ -1,4 +1,8 @@ -using EVIL.Ceres.ExecutionEngine.Collections; +namespace EVIL.Ceres.Runtime.Modules; + +using static EVIL.CommonTypes.TypeSystem.DynamicValueType; + +using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.Concurrency; using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.ExecutionEngine.TypeSystem; @@ -6,164 +10,160 @@ using EVIL.Ceres.TranslationEngine; using EVIL.Ceres.TranslationEngine.Diagnostics; using EVIL.CommonTypes.TypeSystem; -using static EVIL.CommonTypes.TypeSystem.DynamicValueType; -namespace EVIL.Ceres.Runtime.Modules +public sealed class EvilModule : RuntimeModule { - public sealed class EvilModule : RuntimeModule + public override string FullyQualifiedName => "evil"; + + private static Table _severities = new Table() + { + { "VERBOSE", (int)CompilerMessageSeverity.Verbose }, + { "WARNING", (int)CompilerMessageSeverity.Warning }, + { "FATAL", (int)CompilerMessageSeverity.Fatal }, + { "INTERNAL_FAILURE", (int)CompilerMessageSeverity.InternalFailure }, + }.Freeze(); + + [RuntimeModuleGetter("compiler.severity")] + [EvilDocProperty( + EvilDocPropertyMode.Get, + "Retrieves a table mapping error severity names to numeric representation fo compiler error severity. \n" + + "```\n" + + "{\n" + + " VERBOSE: 0,\n" + + " WARNING: 1,\n" + + " FATAL: 2,\n" + + " INTERNAL_FAILURE: 3\n" + + "}\n" + + "```\n" + )] + private static DynamicValue CompilerErrorSeverity(DynamicValue _) + => _severities; + + [RuntimeModuleFunction("compile")] + [EvilDocFunction( + "Attempts to compile the provided EVIL source.", + Returns = "A Table containing either the script data (`.success == true`), " + + "or the compiler error message and compilation log (`.success == false`).", + ReturnType = DynamicValueType.Table + )] + [EvilDocArgument("source", "Source code that is to be compiled.", String)] + [EvilDocArgument( + "file_name", + "File name to be embedded into compiled script's metadata.", + String, + DefaultValue = "" + )] + private static DynamicValue Compile(Fiber fiber, params DynamicValue[] args) { - public override string FullyQualifiedName => "evil"; + args.ExpectAtLeast(1) + .ExpectAtMost(2) + .ExpectStringAt(0, out var source) + .OptionalStringAt(1, "", out var fileName); - private static Table _severities = new Table() + try { - { "VERBOSE", (int)CompilerMessageSeverity.Verbose }, - { "WARNING", (int)CompilerMessageSeverity.Warning }, - { "FATAL", (int)CompilerMessageSeverity.Fatal }, - { "INTERNAL_FAILURE", (int)CompilerMessageSeverity.InternalFailure }, - }.Freeze(); - - [RuntimeModuleGetter("compiler.severity")] - [EvilDocProperty( - EvilDocPropertyMode.Get, - "Retrieves a table mapping error severity names to numeric representation fo compiler error severity. \n" + - "```\n" + - "{\n" + - " VERBOSE: 0,\n" + - " WARNING: 1,\n" + - " FATAL: 2,\n" + - " INTERNAL_FAILURE: 3\n" + - "}\n" + - "```\n" - )] - private static DynamicValue CompilerErrorSeverity(DynamicValue _) - => _severities; - - [RuntimeModuleFunction("compile")] - [EvilDocFunction( - "Attempts to compile the provided EVIL source.", - Returns = "A Table containing either the script data (`.success == true`), " + - "or the compiler error message and compilation log (`.success == false`).", - ReturnType = DynamicValueType.Table - )] - [EvilDocArgument("source", "Source code that is to be compiled.", String)] - [EvilDocArgument( - "file_name", - "File name to be embedded into compiled script's metadata.", - String, - DefaultValue = "" - )] - private static DynamicValue Compile(Fiber fiber, params DynamicValue[] args) - { - args.ExpectAtLeast(1) - .ExpectAtMost(2) - .ExpectStringAt(0, out var source) - .OptionalStringAt(1, "", out var fileName); + var compiler = new Compiler(); + var rootChunk = compiler.Compile(source, fileName); - try - { - var compiler = new Compiler(); - var rootChunk = compiler.Compile(source, fileName); - - return new Table - { - { "success", true }, - { "chunk", rootChunk } - }; - } - catch (CompilerException e) + return new Table { - - return new Table - { - { "success", false }, - { "message", e.Message }, - { "log", e.Log.ToDynamicValue() } - }; - } + { "success", true }, + { "chunk", rootChunk } + }; } - - [RuntimeModuleFunction("reflect")] - [EvilDocFunction( - "Retrieves metadata information of the given Function.", - Returns = "A Table containing the reflected Function's metadata.", - ReturnType = DynamicValueType.Table - )] - [EvilDocArgument( - "function", - "The Function whose information is to be retrieved.", - DynamicValueType.Chunk - )] - private static DynamicValue Reflect(Fiber _, params DynamicValue[] args) + catch (CompilerException e) { - args.ExpectExactly(1) - .ExpectChunkAt(0, out var function); - - var attrs = new Array(function.Attributes.Count); - for (var i = 0; i < function.Attributes.Count; i++) - { - attrs[i] = function.Attributes[i].ToDynamicValue(); - } - + return new Table { - { "name", function.Name }, - { "attributes", attrs }, - { "local_info", BuildLocalInfo(function) }, - { "param_info", BuildParameterInfo(function) } + { "success", false }, + { "message", e.Message }, + { "log", e.Log.ToDynamicValue() } }; } + } + + [RuntimeModuleFunction("reflect")] + [EvilDocFunction( + "Retrieves metadata information of the given Function.", + Returns = "A Table containing the reflected Function's metadata.", + ReturnType = DynamicValueType.Table + )] + [EvilDocArgument( + "function", + "The Function whose information is to be retrieved.", + DynamicValueType.Chunk + )] + private static DynamicValue Reflect(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectChunkAt(0, out var function); - private static Array BuildLocalInfo(Chunk chunk) + var attrs = new Array(function.Attributes.Count); + for (var i = 0; i < function.Attributes.Count; i++) { - var array = new Array(chunk.LocalCount); + attrs[i] = function.Attributes[i].ToDynamicValue(); + } - for (var i = 0; i < chunk.LocalCount; i++) - { - var local = new Table { { "id", i } }; + return new Table + { + { "name", function.Name }, + { "attributes", attrs }, + { "local_info", BuildLocalInfo(function) }, + { "param_info", BuildParameterInfo(function) } + }; + } - if (chunk.DebugDatabase.TryGetLocalName(i, out var localName)) - { - local["name"] = localName; - } + private static Array BuildLocalInfo(Chunk chunk) + { + var array = new Array(chunk.LocalCount); - if (chunk.DebugDatabase.TryGetLocalRwState(i, out var rw)) - { - local["is_rw"] = rw; - } + for (var i = 0; i < chunk.LocalCount; i++) + { + var local = new Table { { "id", i } }; - array[i] = local; + if (chunk.DebugDatabase.TryGetLocalName(i, out var localName)) + { + local["name"] = localName; } - return array; + if (chunk.DebugDatabase.TryGetLocalRwState(i, out var rw)) + { + local["is_rw"] = rw; + } + + array[i] = local; } - private static Array BuildParameterInfo(Chunk chunk) - { - var array = new Array(chunk.ParameterCount); + return array; + } - for (var i = 0; i < chunk.ParameterCount; i++) - { - var param = new Table { { "id", i } }; + private static Array BuildParameterInfo(Chunk chunk) + { + var array = new Array(chunk.ParameterCount); - if (chunk.DebugDatabase.TryGetParameterName(i, out var parameterName)) - { - param["name"] = parameterName; - } + for (var i = 0; i < chunk.ParameterCount; i++) + { + var param = new Table { { "id", i } }; - if (chunk.ParameterInitializers.ContainsKey(i)) - { - param["default_value"] = chunk.ParameterInitializers[i]; - } + if (chunk.DebugDatabase.TryGetParameterName(i, out var parameterName)) + { + param["name"] = parameterName; + } - if (chunk.DebugDatabase.TryGetParameterRwState(i, out var rw)) - { - param["is_rw"] = rw; - } + if (chunk.ParameterInitializers.ContainsKey(i)) + { + param["default_value"] = chunk.ParameterInitializers[i]; + } - array[i] = param; + if (chunk.DebugDatabase.TryGetParameterRwState(i, out var rw)) + { + param["is_rw"] = rw; } - return array; + array[i] = param; } + + return array; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Modules/FsModule.Directory.cs b/VirtualMachine/EVIL.Ceres.Runtime/Modules/FsModule.Directory.cs index 4e343e3c..556e4e24 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Modules/FsModule.Directory.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Modules/FsModule.Directory.cs @@ -1,3 +1,7 @@ +namespace EVIL.Ceres.Runtime.Modules; + +using Array = EVIL.Ceres.ExecutionEngine.Collections.Array; + using System; using System.IO; using EVIL.Ceres.ExecutionEngine.Collections; @@ -5,219 +9,215 @@ using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.Ceres.Runtime.Extensions; using EVIL.CommonTypes.TypeSystem; -using Array = EVIL.Ceres.ExecutionEngine.Collections.Array; -namespace EVIL.Ceres.Runtime.Modules +public partial class FsModule { - public partial class FsModule + [RuntimeModuleFunction("dir.exists")] + [EvilDocFunction( + "Checks if a directory exists at the given path.", + Returns = "`true` if directory exists, `false` otherwise.", + ReturnType = DynamicValueType.Boolean + )] + [EvilDocArgument("path", "A path at which to check the existence of a directory.", DynamicValueType.String)] + private static DynamicValue DirectoryExists(Fiber _, params DynamicValue[] args) { - [RuntimeModuleFunction("dir.exists")] - [EvilDocFunction( - "Checks if a directory exists at the given path.", - Returns = "`true` if directory exists, `false` otherwise.", - ReturnType = DynamicValueType.Boolean - )] - [EvilDocArgument("path", "A path at which to check the existence of a directory.", DynamicValueType.String)] - private static DynamicValue DirectoryExists(Fiber _, params DynamicValue[] args) - { - args.ExpectStringAt(0, out var path); - return Directory.Exists(path); - } + args.ExpectStringAt(0, out var path); + return Directory.Exists(path); + } - [RuntimeModuleFunction("dir.create")] - [EvilDocFunction( - "Creates a directory and all subdirectories at a given path if they don't already exist.", - Returns = "A Table containing the last directory information or `nil` if it was a failure. \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.Table - )] - [EvilDocArgument("path", "A path to create the directory at.", DynamicValueType.String)] - private static DynamicValue DirectoryCreate(Fiber _, params DynamicValue[] args) + [RuntimeModuleFunction("dir.create")] + [EvilDocFunction( + "Creates a directory and all subdirectories at a given path if they don't already exist.", + Returns = "A Table containing the last directory information or `nil` if it was a failure. \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.Table + )] + [EvilDocArgument("path", "A path to create the directory at.", DynamicValueType.String)] + private static DynamicValue DirectoryCreate(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var path); + + try { - args.ExpectStringAt(0, out var path); + var info = Directory.CreateDirectory(path); - try - { - var info = Directory.CreateDirectory(path); - - ClearError(); - return new Table - { - ["name"] = info.Name, - ["path"] = info.FullName - }; - } - catch (Exception e) + ClearError(); + return new Table { - SetError(e.Message); - return DynamicValue.Nil; - } + ["name"] = info.Name, + ["path"] = info.FullName + }; } - - [RuntimeModuleFunction("dir.delete")] - [EvilDocFunction( - "Deletes a directory and all of its contents recursively __without confirmation__.", - Returns = "`true` if the operation was successful, `false` otherwise. \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.Boolean - )] - [EvilDocArgument("path", "A path specifying the directory to be deleted.", DynamicValueType.String)] - private static DynamicValue DirectoryDelete(Fiber _, params DynamicValue[] args) + catch (Exception e) { - args.ExpectStringAt(0, out var path); + SetError(e.Message); + return DynamicValue.Nil; + } + } - try - { - Directory.Delete(path, true); + [RuntimeModuleFunction("dir.delete")] + [EvilDocFunction( + "Deletes a directory and all of its contents recursively __without confirmation__.", + Returns = "`true` if the operation was successful, `false` otherwise. \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.Boolean + )] + [EvilDocArgument("path", "A path specifying the directory to be deleted.", DynamicValueType.String)] + private static DynamicValue DirectoryDelete(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var path); + + try + { + Directory.Delete(path, true); - ClearError(); - return true; - } - catch (Exception e) - { - SetError(e.Message); - return false; - } + ClearError(); + return true; } - - [RuntimeModuleFunction("dir.get_files")] - [EvilDocFunction( - "Attempts to retrieve a list of files present in the directory specified by the given path.", - Returns = "An Array containing the list of full paths to files in the specified directory, or `nil` on failure. \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.Array - )] - [EvilDocArgument("path", "A path specifying the directory to list the files of.", DynamicValueType.String)] - [EvilDocArgument( - "search_pattern", - "An pattern to match the paths with while listing the files. Wildcard '*' is supported.", - DynamicValueType.String, - DefaultValue = "*" - )] - private static DynamicValue DirectoryGetFiles(Fiber _, params DynamicValue[] args) + catch (Exception e) { - args.ExpectStringAt(0, out var path) - .OptionalStringAt(1, "*", out var searchPattern); + SetError(e.Message); + return false; + } + } - try - { - var files = Directory.GetFiles(path, searchPattern); - var array = new Array(files.Length); + [RuntimeModuleFunction("dir.get_files")] + [EvilDocFunction( + "Attempts to retrieve a list of files present in the directory specified by the given path.", + Returns = "An Array containing the list of full paths to files in the specified directory, or `nil` on failure. \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.Array + )] + [EvilDocArgument("path", "A path specifying the directory to list the files of.", DynamicValueType.String)] + [EvilDocArgument( + "search_pattern", + "An pattern to match the paths with while listing the files. Wildcard '*' is supported.", + DynamicValueType.String, + DefaultValue = "*" + )] + private static DynamicValue DirectoryGetFiles(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var path) + .OptionalStringAt(1, "*", out var searchPattern); - for (var i = 0; i < files.Length; i++) - array[i] = files[i].Replace('\\', '/'); + try + { + var files = Directory.GetFiles(path, searchPattern); + var array = new Array(files.Length); - ClearError(); - return array; - } - catch (Exception e) - { - SetError(e.Message); - return DynamicValue.Nil; - } - } + for (var i = 0; i < files.Length; i++) + array[i] = files[i].Replace('\\', '/'); - [RuntimeModuleFunction("dir.get_dirs")] - [EvilDocFunction( - "Attempts to retrieve a list of sub-directories present in the directory specified by the given path.", - Returns = "An Array containing the list of full paths to sub-directories in the specified directory, or `nil` on failure. \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.Array - )] - [EvilDocArgument("path", "A path specifying the directory to list the sub-directories of.", DynamicValueType.String)] - [EvilDocArgument( - "search_pattern", - "A pattern to match the paths with while listing the sub-directories. Wildcard '*' is supported.", - DynamicValueType.String, - DefaultValue = "*" - )] - private static DynamicValue DirectoryGetDirectories(Fiber _, params DynamicValue[] args) + ClearError(); + return array; + } + catch (Exception e) { - args.ExpectStringAt(0, out var path) - .OptionalStringAt(1, "*", out var searchPattern); + SetError(e.Message); + return DynamicValue.Nil; + } + } - try - { - var dirs = Directory.GetDirectories(path, searchPattern); - var array = new Array(dirs.Length); + [RuntimeModuleFunction("dir.get_dirs")] + [EvilDocFunction( + "Attempts to retrieve a list of sub-directories present in the directory specified by the given path.", + Returns = "An Array containing the list of full paths to sub-directories in the specified directory, or `nil` on failure. \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.Array + )] + [EvilDocArgument("path", "A path specifying the directory to list the sub-directories of.", DynamicValueType.String)] + [EvilDocArgument( + "search_pattern", + "A pattern to match the paths with while listing the sub-directories. Wildcard '*' is supported.", + DynamicValueType.String, + DefaultValue = "*" + )] + private static DynamicValue DirectoryGetDirectories(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var path) + .OptionalStringAt(1, "*", out var searchPattern); - for (var i = 0; i < dirs.Length; i++) - array[i] = dirs[i].Replace('\\', '/'); + try + { + var dirs = Directory.GetDirectories(path, searchPattern); + var array = new Array(dirs.Length); - ClearError(); - return array; - } - catch (Exception e) - { - SetError(e.Message); - return DynamicValue.Nil; - } - } + for (var i = 0; i < dirs.Length; i++) + array[i] = dirs[i].Replace('\\', '/'); - [RuntimeModuleFunction("dir.copy")] - [EvilDocFunction( - "Attempts to recursively copy a directory from the source path into the target path.", - Returns = "`true` on operation success, `false` when the operation fails. \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.Boolean - )] - [EvilDocArgument("source_path", "A path specifying the directory whose contents of are to be copied.", DynamicValueType.String)] - [EvilDocArgument("target_path", "A path specifying the directory to copy the contents of source directory into.", DynamicValueType.String)] - [EvilDocArgument( - "overwrite_existing", - "`true` to overwrite existing files if found, `false` to fail if a file exists at the target path.", - DynamicValueType.Boolean, - DefaultValue = "false" - )] - private static DynamicValue DirectoryCopy(Fiber _, params DynamicValue[] args) + ClearError(); + return array; + } + catch (Exception e) { - args.ExpectStringAt(0, out var sourcePath) - .ExpectStringAt(1, out var targetPath) - .OptionalBooleanAt(2, false, out var overwriteExisting); + SetError(e.Message); + return DynamicValue.Nil; + } + } - try - { - var sourceDirectoryInfo = new DirectoryInfo(sourcePath); - var targetDirectoryInfo = new DirectoryInfo(targetPath); + [RuntimeModuleFunction("dir.copy")] + [EvilDocFunction( + "Attempts to recursively copy a directory from the source path into the target path.", + Returns = "`true` on operation success, `false` when the operation fails. \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.Boolean + )] + [EvilDocArgument("source_path", "A path specifying the directory whose contents of are to be copied.", DynamicValueType.String)] + [EvilDocArgument("target_path", "A path specifying the directory to copy the contents of source directory into.", DynamicValueType.String)] + [EvilDocArgument( + "overwrite_existing", + "`true` to overwrite existing files if found, `false` to fail if a file exists at the target path.", + DynamicValueType.Boolean, + DefaultValue = "false" + )] + private static DynamicValue DirectoryCopy(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var sourcePath) + .ExpectStringAt(1, out var targetPath) + .OptionalBooleanAt(2, false, out var overwriteExisting); - CopyDirectoryRecursively(sourceDirectoryInfo, targetDirectoryInfo, overwriteExisting); + try + { + var sourceDirectoryInfo = new DirectoryInfo(sourcePath); + var targetDirectoryInfo = new DirectoryInfo(targetPath); - ClearError(); - return true; - } - catch (Exception e) - { - SetError(e.Message); - return false; - } - } + CopyDirectoryRecursively(sourceDirectoryInfo, targetDirectoryInfo, overwriteExisting); - [RuntimeModuleFunction("dir.move")] - [EvilDocFunction( - "Attempts to move a directory from the source path to the target path.", - Returns = "`true` on operation success, `false` when the operation fails. \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.Boolean - )] - [EvilDocArgument("source_path", "A path specifying the directory to be moved.", DynamicValueType.String)] - [EvilDocArgument("target_path", "A path to which the directory will be moved.", DynamicValueType.String)] - private static DynamicValue DirectoryMove(Fiber _, params DynamicValue[] args) + ClearError(); + return true; + } + catch (Exception e) { - args.ExpectStringAt(0, out var sourcePath) - .ExpectStringAt(1, out var targetPath); + SetError(e.Message); + return false; + } + } - try - { - Directory.Move(sourcePath, targetPath); + [RuntimeModuleFunction("dir.move")] + [EvilDocFunction( + "Attempts to move a directory from the source path to the target path.", + Returns = "`true` on operation success, `false` when the operation fails. \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.Boolean + )] + [EvilDocArgument("source_path", "A path specifying the directory to be moved.", DynamicValueType.String)] + [EvilDocArgument("target_path", "A path to which the directory will be moved.", DynamicValueType.String)] + private static DynamicValue DirectoryMove(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var sourcePath) + .ExpectStringAt(1, out var targetPath); - ClearError(); - return true; - } - catch (Exception e) - { - SetError(e.Message); - return false; - } + try + { + Directory.Move(sourcePath, targetPath); + + ClearError(); + return true; + } + catch (Exception e) + { + SetError(e.Message); + return false; } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Modules/FsModule.File.cs b/VirtualMachine/EVIL.Ceres.Runtime/Modules/FsModule.File.cs index deec4912..cfe3dd97 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Modules/FsModule.File.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Modules/FsModule.File.cs @@ -1,3 +1,9 @@ +namespace EVIL.Ceres.Runtime.Modules; + +using static EVIL.Ceres.ExecutionEngine.TypeSystem.DynamicValue; + +using Array = EVIL.Ceres.ExecutionEngine.Collections.Array; + using System; using System.IO; using System.Linq; @@ -6,539 +12,534 @@ using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.Ceres.Runtime.Extensions; using EVIL.CommonTypes.TypeSystem; -using static EVIL.Ceres.ExecutionEngine.TypeSystem.DynamicValue; -using Array = EVIL.Ceres.ExecutionEngine.Collections.Array; -namespace EVIL.Ceres.Runtime.Modules +public partial class FsModule { - public partial class FsModule + [RuntimeModuleFunction("file.exists")] + [EvilDocFunction( + "Checks if a file exists at the given path.", + Returns = "`true` if a file exists at the provided path, `false` otherwise.", + ReturnType = DynamicValueType.Boolean + )] + [EvilDocArgument( + "path", + "A path at which to check the existence of a file.", + DynamicValueType.Boolean + )] + private static DynamicValue FileExists(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var path); + return File.Exists(path); + } + + [RuntimeModuleFunction("file.delete")] + [EvilDocFunction( + "Deletes a file at the given path.", + Returns = "`true` if the operation succeeded, `false` otherwise. \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.Boolean + )] + [EvilDocArgument("path", "A path specifying the file to be deleted.", DynamicValueType.String)] + private static DynamicValue FileDelete(Fiber _, params DynamicValue[] args) { - [RuntimeModuleFunction("file.exists")] - [EvilDocFunction( - "Checks if a file exists at the given path.", - Returns = "`true` if a file exists at the provided path, `false` otherwise.", - ReturnType = DynamicValueType.Boolean - )] - [EvilDocArgument( - "path", - "A path at which to check the existence of a file.", - DynamicValueType.Boolean - )] - private static DynamicValue FileExists(Fiber _, params DynamicValue[] args) + args.ExpectStringAt(0, out var path); + + try { - args.ExpectStringAt(0, out var path); - return File.Exists(path); + ClearError(); + File.Delete(path); + return true; } - - [RuntimeModuleFunction("file.delete")] - [EvilDocFunction( - "Deletes a file at the given path.", - Returns = "`true` if the operation succeeded, `false` otherwise. \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.Boolean - )] - [EvilDocArgument("path", "A path specifying the file to be deleted.", DynamicValueType.String)] - private static DynamicValue FileDelete(Fiber _, params DynamicValue[] args) + catch (Exception e) { - args.ExpectStringAt(0, out var path); - - try - { - ClearError(); - File.Delete(path); - return true; - } - catch (Exception e) - { - SetError(e.Message); - return false; - } + SetError(e.Message); + return false; } + } - [RuntimeModuleFunction("file.copy")] - [EvilDocFunction( - "Copies a file from one path to another.", - Returns = "`true` if the operation succeeded, `false` otherwise. \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.Boolean - )] - [EvilDocArgument("source_path", "A path specifying the file to be copied.", DynamicValueType.String)] - [EvilDocArgument("target_path", "A path specifying the location to which the source file should be copied.", DynamicValueType.String)] - [EvilDocArgument( - "overwrite_existing", - "`true` to overwrite an existing file if found, `false` to fail when that happens.", - DynamicValueType.Boolean, - DefaultValue = "false" - )] - private static DynamicValue FileCopy(Fiber _, params DynamicValue[] args) - { - args.ExpectStringAt(0, out var sourcePath) - .ExpectStringAt(1, out var targetPath) - .OptionalBooleanAt(2, false, out var overwriteExisting); + [RuntimeModuleFunction("file.copy")] + [EvilDocFunction( + "Copies a file from one path to another.", + Returns = "`true` if the operation succeeded, `false` otherwise. \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.Boolean + )] + [EvilDocArgument("source_path", "A path specifying the file to be copied.", DynamicValueType.String)] + [EvilDocArgument("target_path", "A path specifying the location to which the source file should be copied.", DynamicValueType.String)] + [EvilDocArgument( + "overwrite_existing", + "`true` to overwrite an existing file if found, `false` to fail when that happens.", + DynamicValueType.Boolean, + DefaultValue = "false" + )] + private static DynamicValue FileCopy(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var sourcePath) + .ExpectStringAt(1, out var targetPath) + .OptionalBooleanAt(2, false, out var overwriteExisting); - try - { - ClearError(); - File.Copy(sourcePath, targetPath, overwriteExisting); - return true; - } - catch (Exception e) - { - SetError(e.Message); - return false; - } + try + { + ClearError(); + File.Copy(sourcePath, targetPath, overwriteExisting); + return true; } - - [RuntimeModuleFunction("file.move")] - [EvilDocFunction( - "Moves a file from one path to another.", - Returns = "`true` if the operation succeeded, `false` otherwise. \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.Boolean - )] - [EvilDocArgument("source_path", "A path specifying the file to be moved.", DynamicValueType.String)] - [EvilDocArgument("target_path", "A path specifying the location to which the source file should be moved.", DynamicValueType.String)] - [EvilDocArgument( - "overwrite_existing", - "`true` to overwrite an existing file if found, `false` to fail when that happens.", - DynamicValueType.Boolean, - DefaultValue = "false" - )] - private static DynamicValue FileMove(Fiber _, params DynamicValue[] args) + catch (Exception e) { - args.ExpectStringAt(0, out var sourcePath) - .ExpectStringAt(1, out var targetPath) - .OptionalBooleanAt(2, false, out var overwriteExisting); - - try - { - ClearError(); - File.Move(sourcePath, targetPath, overwriteExisting); - return true; - } - catch (Exception e) - { - SetError(e.Message); - return false; - } + SetError(e.Message); + return false; } + } - [RuntimeModuleFunction("file.get_lines")] - [EvilDocFunction( - "Reads lines of text from a file.", - Returns = "An Array containing the lines read from the specified file, or `nil` if the operation fails. \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.Array - )] - [EvilDocArgument("path", "A path specifying the file to read the lines of text from.", DynamicValueType.String)] - [EvilDocArgument( - "encoding", - "A name of the encoding to read the file as.", - DynamicValueType.String, - DefaultValue = "utf-8" - )] - private static DynamicValue FileGetLines(Fiber _, params DynamicValue[] args) + [RuntimeModuleFunction("file.move")] + [EvilDocFunction( + "Moves a file from one path to another.", + Returns = "`true` if the operation succeeded, `false` otherwise. \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.Boolean + )] + [EvilDocArgument("source_path", "A path specifying the file to be moved.", DynamicValueType.String)] + [EvilDocArgument("target_path", "A path specifying the location to which the source file should be moved.", DynamicValueType.String)] + [EvilDocArgument( + "overwrite_existing", + "`true` to overwrite an existing file if found, `false` to fail when that happens.", + DynamicValueType.Boolean, + DefaultValue = "false" + )] + private static DynamicValue FileMove(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var sourcePath) + .ExpectStringAt(1, out var targetPath) + .OptionalBooleanAt(2, false, out var overwriteExisting); + + try + { + ClearError(); + File.Move(sourcePath, targetPath, overwriteExisting); + return true; + } + catch (Exception e) { - args.ExpectStringAt(0, out var path) - .OptionalStringAt(1, "utf-8", out var encoding); + SetError(e.Message); + return false; + } + } - try - { - ClearError(); + [RuntimeModuleFunction("file.get_lines")] + [EvilDocFunction( + "Reads lines of text from a file.", + Returns = "An Array containing the lines read from the specified file, or `nil` if the operation fails. \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.Array + )] + [EvilDocArgument("path", "A path specifying the file to read the lines of text from.", DynamicValueType.String)] + [EvilDocArgument( + "encoding", + "A name of the encoding to read the file as.", + DynamicValueType.String, + DefaultValue = "utf-8" + )] + private static DynamicValue FileGetLines(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var path) + .OptionalStringAt(1, "utf-8", out var encoding); - var lines = File.ReadLines(path, Encoding.GetEncoding(encoding)).ToArray(); - var array = new Array(lines.Length); + try + { + ClearError(); - for (var i = 0; i < lines.Length; i++) - array[i] = lines[i]; + var lines = File.ReadLines(path, Encoding.GetEncoding(encoding)).ToArray(); + var array = new Array(lines.Length); - return array; - } - catch (Exception e) - { - SetError(e.Message); - return Nil; - } - } + for (var i = 0; i < lines.Length; i++) + array[i] = lines[i]; - [RuntimeModuleFunction("file.get_text")] - [EvilDocFunction( - "Reads a file and returns its contents as a String using the provided encoding, or `nil` if the operation fails.", - Returns = "Contents of the read file.", - ReturnType = DynamicValueType.String - )] - [EvilDocArgument("path", "A path specifying the file to read the text from.", DynamicValueType.String)] - [EvilDocArgument( - "encoding", - "A name of the encoding to read the file as.", - DynamicValueType.String, - DefaultValue = "utf-8" - )] - private static DynamicValue FileGetText(Fiber _, params DynamicValue[] args) + return array; + } + catch (Exception e) { - args.ExpectStringAt(0, out var path) - .OptionalStringAt(1, "utf-8", out var encoding); + SetError(e.Message); + return Nil; + } + } - try - { - ClearError(); - return File.ReadAllText(path, Encoding.GetEncoding(encoding)); - } - catch (Exception e) - { - SetError(e.Message); - return Nil; - } + [RuntimeModuleFunction("file.get_text")] + [EvilDocFunction( + "Reads a file and returns its contents as a String using the provided encoding, or `nil` if the operation fails.", + Returns = "Contents of the read file.", + ReturnType = DynamicValueType.String + )] + [EvilDocArgument("path", "A path specifying the file to read the text from.", DynamicValueType.String)] + [EvilDocArgument( + "encoding", + "A name of the encoding to read the file as.", + DynamicValueType.String, + DefaultValue = "utf-8" + )] + private static DynamicValue FileGetText(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var path) + .OptionalStringAt(1, "utf-8", out var encoding); + + try + { + ClearError(); + return File.ReadAllText(path, Encoding.GetEncoding(encoding)); + } + catch (Exception e) + { + SetError(e.Message); + return Nil; } + } - [RuntimeModuleFunction("file.open")] - [EvilDocFunction( - "Attempts to open a file stream given a file path and an optional file mode string. \n\n" + - "**File modes** \n" + - "> `r` \n" + - "> Open existing, fail if doesn't exist, read-only.\n\n" + - "> `r+` \n" + - "> Open existing, fail if doesn't exist, read-write.\n\n" + - "> `w` \n" + - "> Create new, overwrite if exists, write-only.\n\n" + - "> `w+` \n" + - "> Create new, overwrite if exists, read-write.\n\n" + - "> `a` \n" + - "> Open or create new file, write-only, seek to end.\n\n" + - "> `a+` \n" + - "> Open or create new file, read-write.\n\n" + - "> `t` \n" + - "> Truncate file, fail if doesn't exist, write-only.\n\n" + - "> `rw` \n" + - "> Same as `a+`.\n\n" + - "> `wr` \n" + - "> Same as `a+`.\n\n", - Returns = "A NativeObject wrapping a stream handle or `nil` if the operation fails. \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.NativeObject - )] - [EvilDocArgument("path", "A path specifying the file to open or create.", DynamicValueType.String)] - [EvilDocArgument( - "mode", - "A string specifying the mode of the resulting file stream.", - DynamicValueType.String, - DefaultValue = "rw" - )] - private static DynamicValue FileOpen(Fiber _, params DynamicValue[] args) - { - args.ExpectStringAt(0, out var path) - .OptionalStringAt(1, "rw", out var mode); + [RuntimeModuleFunction("file.open")] + [EvilDocFunction( + "Attempts to open a file stream given a file path and an optional file mode string. \n\n" + + "**File modes** \n" + + "> `r` \n" + + "> Open existing, fail if doesn't exist, read-only.\n\n" + + "> `r+` \n" + + "> Open existing, fail if doesn't exist, read-write.\n\n" + + "> `w` \n" + + "> Create new, overwrite if exists, write-only.\n\n" + + "> `w+` \n" + + "> Create new, overwrite if exists, read-write.\n\n" + + "> `a` \n" + + "> Open or create new file, write-only, seek to end.\n\n" + + "> `a+` \n" + + "> Open or create new file, read-write.\n\n" + + "> `t` \n" + + "> Truncate file, fail if doesn't exist, write-only.\n\n" + + "> `rw` \n" + + "> Same as `a+`.\n\n" + + "> `wr` \n" + + "> Same as `a+`.\n\n", + Returns = "A NativeObject wrapping a stream handle or `nil` if the operation fails. \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.NativeObject + )] + [EvilDocArgument("path", "A path specifying the file to open or create.", DynamicValueType.String)] + [EvilDocArgument( + "mode", + "A string specifying the mode of the resulting file stream.", + DynamicValueType.String, + DefaultValue = "rw" + )] + private static DynamicValue FileOpen(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var path) + .OptionalStringAt(1, "rw", out var mode); - try - { - ClearError(); + try + { + ClearError(); - var (access, fileMode) = AccessAndModeFromString(mode); - var stream = File.Open(path, fileMode, access, FileShare.ReadWrite); + var (access, fileMode) = AccessAndModeFromString(mode); + var stream = File.Open(path, fileMode, access, FileShare.ReadWrite); - return FromObject(stream); - } - catch (Exception e) - { - SetError(e.Message); - return Nil; - } + return FromObject(stream); } - - [RuntimeModuleFunction("file.close")] - [EvilDocFunction( - "Attempts to close a previously opened file stream.", - Returns = "`true` if closed successfully, `false` on failure. \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.Boolean - )] - [EvilDocArgument("stream", "A handle to the previously opened file stream.", DynamicValueType.NativeObject)] - private static DynamicValue FileClose(Fiber _, params DynamicValue[] args) + catch (Exception e) { - args.ExpectNativeObjectAt(0, out Stream stream); + SetError(e.Message); + return Nil; + } + } - try - { - ClearError(); + [RuntimeModuleFunction("file.close")] + [EvilDocFunction( + "Attempts to close a previously opened file stream.", + Returns = "`true` if closed successfully, `false` on failure. \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.Boolean + )] + [EvilDocArgument("stream", "A handle to the previously opened file stream.", DynamicValueType.NativeObject)] + private static DynamicValue FileClose(Fiber _, params DynamicValue[] args) + { + args.ExpectNativeObjectAt(0, out Stream stream); + + try + { + ClearError(); - stream.Close(); - stream.Dispose(); - return true; - } - catch (Exception e) - { - SetError(e.Message); - return false; - } + stream.Close(); + stream.Dispose(); + return true; } - - [RuntimeModuleFunction("file.seek")] - [EvilDocFunction( - "Sets the position within the given file stream based on the given offset and origin. \n\n" + - "**Seek origins** \n" + - "> `fs.origin.BEGIN = 0` \n" + - "> The seek operation starts from offset 0 and moves forwards.\n\n" + - "> `fs.origin.CURRENT = 1` \n" + - "> The seek operation starts from the current position and moves forwards.\n\n" + - "> `fs.origin.END = 2` \n" + - "> The seek operation starts from the end and moves backwards.\n\n", - Returns = "The new position within the given stream or `-1` on failure. \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("stream", "A handle to the file stream to seek through.", DynamicValueType.NativeObject)] - [EvilDocArgument("offset", "An integer specifying the new position within the given stream.", DynamicValueType.Number)] - [EvilDocArgument( - "seek_origin", - "An integer specifying the origin of the seek operation.", - DynamicValueType.Number, - DefaultValue = "fs.origin.BEGIN" - )] - private static DynamicValue FileSeek(Fiber _, params DynamicValue[] args) + catch (Exception e) { - args.ExpectNativeObjectAt(0, out Stream stream) - .ExpectIntegerAt(1, out var offset) - .OptionalIntegerAt(2, (long)SeekOrigin.Begin, out var seekOrigin); + SetError(e.Message); + return false; + } + } - try - { - ClearError(); - return stream.Seek(offset, (SeekOrigin)seekOrigin); - } - catch (Exception e) - { - SetError(e.Message); - return -1; - } + [RuntimeModuleFunction("file.seek")] + [EvilDocFunction( + "Sets the position within the given file stream based on the given offset and origin. \n\n" + + "**Seek origins** \n" + + "> `fs.origin.BEGIN = 0` \n" + + "> The seek operation starts from offset 0 and moves forwards.\n\n" + + "> `fs.origin.CURRENT = 1` \n" + + "> The seek operation starts from the current position and moves forwards.\n\n" + + "> `fs.origin.END = 2` \n" + + "> The seek operation starts from the end and moves backwards.\n\n", + Returns = "The new position within the given stream or `-1` on failure. \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("stream", "A handle to the file stream to seek through.", DynamicValueType.NativeObject)] + [EvilDocArgument("offset", "An integer specifying the new position within the given stream.", DynamicValueType.Number)] + [EvilDocArgument( + "seek_origin", + "An integer specifying the origin of the seek operation.", + DynamicValueType.Number, + DefaultValue = "fs.origin.BEGIN" + )] + private static DynamicValue FileSeek(Fiber _, params DynamicValue[] args) + { + args.ExpectNativeObjectAt(0, out Stream stream) + .ExpectIntegerAt(1, out var offset) + .OptionalIntegerAt(2, (long)SeekOrigin.Begin, out var seekOrigin); + + try + { + ClearError(); + return stream.Seek(offset, (SeekOrigin)seekOrigin); } - - [RuntimeModuleFunction("file.tell")] - [EvilDocFunction( - "Gets current position within the given file stream.", - Returns = "Current position within the given file stream, or `-1` on failure. \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("stream", "A handle to an open file stream.", DynamicValueType.NativeObject)] - private static DynamicValue FileTell(Fiber _, params DynamicValue[] args) + catch (Exception e) { - args.ExpectNativeObjectAt(0, out Stream stream); + SetError(e.Message); + return -1; + } + } + + [RuntimeModuleFunction("file.tell")] + [EvilDocFunction( + "Gets current position within the given file stream.", + Returns = "Current position within the given file stream, or `-1` on failure. \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("stream", "A handle to an open file stream.", DynamicValueType.NativeObject)] + private static DynamicValue FileTell(Fiber _, params DynamicValue[] args) + { + args.ExpectNativeObjectAt(0, out Stream stream); - try - { - ClearError(); - return stream.Position; - } - catch (Exception e) - { - SetError(e.Message); - return -1; - } + try + { + ClearError(); + return stream.Position; + } + catch (Exception e) + { + SetError(e.Message); + return -1; } + } - [RuntimeModuleFunction("file.write")] - [EvilDocFunction( - "Writes the provided data to the given file stream using the specified encoding.", - Returns = "`true` if write operation was successful, `false` otherwise. \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.Boolean - )] - [EvilDocArgument("stream", "A handle to an open file stream.", DynamicValueType.NativeObject)] - [EvilDocArgument("data", "An array of bytes to be written to the given file stream.", DynamicValueType.Array)] - [EvilDocArgument( - "offset", - "An integer specifying a zero-based offset in the data aray at which to begin copying bytes to the given stream.", - DynamicValueType.Number, - DefaultValue = "0" - )] - [EvilDocArgument( - "count", - "An integer specifying the number of bytes to be written to the given stream.", - DynamicValueType.Number, - DefaultValue = "#data" - )] - [EvilDocArgument( - "auto_flush", - "`true` to flush the stream immediately after writing the data, `false` to defer until the stream is closed.", - DynamicValueType.Boolean, - DefaultValue = "true" - )] - private static DynamicValue FileWrite(Fiber _, params DynamicValue[] args) + [RuntimeModuleFunction("file.write")] + [EvilDocFunction( + "Writes the provided data to the given file stream using the specified encoding.", + Returns = "`true` if write operation was successful, `false` otherwise. \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.Boolean + )] + [EvilDocArgument("stream", "A handle to an open file stream.", DynamicValueType.NativeObject)] + [EvilDocArgument("data", "An array of bytes to be written to the given file stream.", DynamicValueType.Array)] + [EvilDocArgument( + "offset", + "An integer specifying a zero-based offset in the data aray at which to begin copying bytes to the given stream.", + DynamicValueType.Number, + DefaultValue = "0" + )] + [EvilDocArgument( + "count", + "An integer specifying the number of bytes to be written to the given stream.", + DynamicValueType.Number, + DefaultValue = "#data" + )] + [EvilDocArgument( + "auto_flush", + "`true` to flush the stream immediately after writing the data, `false` to defer until the stream is closed.", + DynamicValueType.Boolean, + DefaultValue = "true" + )] + private static DynamicValue FileWrite(Fiber _, params DynamicValue[] args) + { + args.ExpectNativeObjectAt(0, out Stream stream) + .ExpectArrayAt(1, out var data) + .OptionalIntegerAt(2, 0, out var offset) + .OptionalIntegerAt(3, data.Length, out var count) + .OptionalBooleanAt(4, true, out var autoFlush); + + try { - args.ExpectNativeObjectAt(0, out Stream stream) - .ExpectArrayAt(1, out var data) - .OptionalIntegerAt(2, 0, out var offset) - .OptionalIntegerAt(3, data.Length, out var count) - .OptionalBooleanAt(4, true, out var autoFlush); + ClearError(); - try + var bytes = new byte[data.Length]; + for (var i = 0; i < data.Length; i++) { - ClearError(); - - var bytes = new byte[data.Length]; - for (var i = 0; i < data.Length; i++) + if (data[i].Type != DynamicValueType.Number) { - if (data[i].Type != DynamicValueType.Number) - { - throw new InvalidDataException( - "Only byte arrays can be written to a file stream." - ); - } - - bytes[i] = (byte)data[i].Number; + throw new InvalidDataException( + "Only byte arrays can be written to a file stream." + ); } - stream.Write(bytes, (int)offset, (int)count); + bytes[i] = (byte)data[i].Number; + } - if (autoFlush) - { - stream.Flush(); - } + stream.Write(bytes, (int)offset, (int)count); - return true; - } - catch (Exception e) + if (autoFlush) { - SetError(e.Message); - return false; + stream.Flush(); } + + return true; } - - [RuntimeModuleFunction("file.write_s")] - [EvilDocFunction( - "Writes the provided string to the given file stream using the specified encoding.", - Returns = "`true` if the operation was successful, `false` if it failed \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.Boolean - )] - [EvilDocArgument("stream", "A handle to an open file stream.", DynamicValueType.NativeObject)] - [EvilDocArgument("string", "A string to be written to the file stream.", DynamicValueType.String)] - [EvilDocArgument("encoding", "Encoding to be used when writing the string to the stream.", DynamicValueType.String)] - [EvilDocArgument( - "auto_flush", - "`true` to flush the stream immediately after writing the data, `false` to defer until the stream is closed.", - DynamicValueType.String, - DefaultValue = "utf-8" - )] - private static DynamicValue FileWriteString(Fiber _, params DynamicValue[] args) + catch (Exception e) { - args.ExpectNativeObjectAt(0, out Stream stream) - .ExpectStringAt(1, out var str) - .OptionalStringAt(2, "utf-8", out var encoding) - .OptionalBooleanAt(3, true, out var autoFlush); - - try - { - ClearError(); + SetError(e.Message); + return false; + } + } + + [RuntimeModuleFunction("file.write_s")] + [EvilDocFunction( + "Writes the provided string to the given file stream using the specified encoding.", + Returns = "`true` if the operation was successful, `false` if it failed \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.Boolean + )] + [EvilDocArgument("stream", "A handle to an open file stream.", DynamicValueType.NativeObject)] + [EvilDocArgument("string", "A string to be written to the file stream.", DynamicValueType.String)] + [EvilDocArgument("encoding", "Encoding to be used when writing the string to the stream.", DynamicValueType.String)] + [EvilDocArgument( + "auto_flush", + "`true` to flush the stream immediately after writing the data, `false` to defer until the stream is closed.", + DynamicValueType.String, + DefaultValue = "utf-8" + )] + private static DynamicValue FileWriteString(Fiber _, params DynamicValue[] args) + { + args.ExpectNativeObjectAt(0, out Stream stream) + .ExpectStringAt(1, out var str) + .OptionalStringAt(2, "utf-8", out var encoding) + .OptionalBooleanAt(3, true, out var autoFlush); - stream.Write( - Encoding.GetEncoding( - encoding - ).GetBytes(str) - ); + try + { + ClearError(); - if (autoFlush) - { - stream.Flush(); - } + stream.Write( + Encoding.GetEncoding( + encoding + ).GetBytes(str) + ); - return true; - } - catch (Exception e) + if (autoFlush) { - SetError(e.Message); - return false; + stream.Flush(); } + + return true; } + catch (Exception e) + { + SetError(e.Message); + return false; + } + } - [RuntimeModuleFunction("file.read")] - [EvilDocFunction( - "Reads bytes of data from an open stream into the provided array.", - Returns = "The amount of bytes that has been read from the stream or `-1` on failure. \n" + - "Check `fs.error` for failure details. \n" + - "> **NOTE** \n" + - "> The returned value may be smaller than the requested amount of data if the stream ends early.", - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("stream", "A handle to an open file stream.", DynamicValueType.NativeObject)] - [EvilDocArgument("data", "An array to read the data into.", DynamicValueType.Array)] - [EvilDocArgument( - "offset", - "An integer specifying a zero-based byte offset in the provided data array at which to begin storing the data read from the given stream.", - DynamicValueType.Number, - DefaultValue = "0" - )] - [EvilDocArgument( - "count", - "An integer specifying the amount of data to be read from the file stream.", - DynamicValueType.Number, - DefaultValue = "#data" - )] - private static DynamicValue FileRead(Fiber _, params DynamicValue[] args) + [RuntimeModuleFunction("file.read")] + [EvilDocFunction( + "Reads bytes of data from an open stream into the provided array.", + Returns = "The amount of bytes that has been read from the stream or `-1` on failure. \n" + + "Check `fs.error` for failure details. \n" + + "> **NOTE** \n" + + "> The returned value may be smaller than the requested amount of data if the stream ends early.", + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("stream", "A handle to an open file stream.", DynamicValueType.NativeObject)] + [EvilDocArgument("data", "An array to read the data into.", DynamicValueType.Array)] + [EvilDocArgument( + "offset", + "An integer specifying a zero-based byte offset in the provided data array at which to begin storing the data read from the given stream.", + DynamicValueType.Number, + DefaultValue = "0" + )] + [EvilDocArgument( + "count", + "An integer specifying the amount of data to be read from the file stream.", + DynamicValueType.Number, + DefaultValue = "#data" + )] + private static DynamicValue FileRead(Fiber _, params DynamicValue[] args) + { + args.ExpectNativeObjectAt(0, out Stream stream) + .ExpectArrayAt(1, out var data) + .OptionalIntegerAt(2, 0, out var offset) + .OptionalIntegerAt(3, data.Length, out var count); + + try { - args.ExpectNativeObjectAt(0, out Stream stream) - .ExpectArrayAt(1, out var data) - .OptionalIntegerAt(2, 0, out var offset) - .OptionalIntegerAt(3, data.Length, out var count); + ClearError(); - try + var length = 0; + while (length < count) { - ClearError(); + if (offset + length >= data.Length) + { + break; + } - var length = 0; - while (length < count) + var fragment = stream.ReadByte(); + if (fragment < 0) { - if (offset + length >= data.Length) - { - break; - } - - var fragment = stream.ReadByte(); - if (fragment < 0) - { - break; - } - - data[offset + length] = fragment; - length++; + break; } - - return length; - } - catch (Exception e) - { - SetError(e.Message); - return -1; + + data[offset + length] = fragment; + length++; } + + return length; } - - [RuntimeModuleFunction("file.read_b")] - [EvilDocFunction( - "Reads a single byte from an open file stream.", - Returns = "A byte value that has been read from the provided file stream, or `-1` on either failure or end-of-stream. \n" + - "Check `fs.error` for failure details and to distinguish a failure from an end-of-stream condition.", - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument( - "stream", - "A handle to an open file stream.", - DynamicValueType.NativeObject - )] - private static DynamicValue FileReadByte(Fiber _, params DynamicValue[] args) + catch (Exception e) { - args.ExpectNativeObjectAt(0, out Stream stream); + SetError(e.Message); + return -1; + } + } + + [RuntimeModuleFunction("file.read_b")] + [EvilDocFunction( + "Reads a single byte from an open file stream.", + Returns = "A byte value that has been read from the provided file stream, or `-1` on either failure or end-of-stream. \n" + + "Check `fs.error` for failure details and to distinguish a failure from an end-of-stream condition.", + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument( + "stream", + "A handle to an open file stream.", + DynamicValueType.NativeObject + )] + private static DynamicValue FileReadByte(Fiber _, params DynamicValue[] args) + { + args.ExpectNativeObjectAt(0, out Stream stream); - try - { - ClearError(); - return stream.ReadByte(); - } - catch (Exception e) - { - SetError(e.Message); - return -1; - } + try + { + ClearError(); + return stream.ReadByte(); + } + catch (Exception e) + { + SetError(e.Message); + return -1; } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Modules/FsModule.Path.cs b/VirtualMachine/EVIL.Ceres.Runtime/Modules/FsModule.Path.cs index 7ee70b84..faf88cde 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Modules/FsModule.Path.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Modules/FsModule.Path.cs @@ -1,327 +1,328 @@ +namespace EVIL.Ceres.Runtime.Modules; + +using static EVIL.Ceres.ExecutionEngine.TypeSystem.DynamicValue; + +using Array = EVIL.Ceres.ExecutionEngine.Collections.Array; + using System; using System.IO; using EVIL.Ceres.ExecutionEngine.Concurrency; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.Ceres.Runtime.Extensions; using EVIL.CommonTypes.TypeSystem; -using static EVIL.Ceres.ExecutionEngine.TypeSystem.DynamicValue; -using Array = EVIL.Ceres.ExecutionEngine.Collections.Array; -namespace EVIL.Ceres.Runtime.Modules +public partial class FsModule { - public partial class FsModule - { - [RuntimeModuleGetter("path.sep")] - [EvilDocProperty( - EvilDocPropertyMode.Get, - "A platform-specific character used to separate path strings.", - ReturnType = DynamicValueType.String - )] - private static DynamicValue GetPathSeparator(DynamicValue _) - => Path.PathSeparator; + [RuntimeModuleGetter("path.sep")] + [EvilDocProperty( + EvilDocPropertyMode.Get, + "A platform-specific character used to separate path strings.", + ReturnType = DynamicValueType.String + )] + private static DynamicValue GetPathSeparator(DynamicValue _) + => Path.PathSeparator; - [RuntimeModuleGetter("path.alt_sep")] - [EvilDocProperty( - EvilDocPropertyMode.Get, - "An alternate platform-specific character used to separate path strings.", - ReturnType = DynamicValueType.String - )] - private static DynamicValue GetAltPathSeparator(DynamicValue _) - => Path.AltDirectorySeparatorChar; + [RuntimeModuleGetter("path.alt_sep")] + [EvilDocProperty( + EvilDocPropertyMode.Get, + "An alternate platform-specific character used to separate path strings.", + ReturnType = DynamicValueType.String + )] + private static DynamicValue GetAltPathSeparator(DynamicValue _) + => Path.AltDirectorySeparatorChar; - [RuntimeModuleGetter("path.bad_path_chars")] - [EvilDocProperty( - EvilDocPropertyMode.Get, - "An array containing characters that are not allowed in paths.", - ReturnType = DynamicValueType.Array - )] - private static DynamicValue GetRestrictedPathChars(DynamicValue _) - { - var invalidPathChars = Path.GetInvalidPathChars(); - var array = new Array(invalidPathChars.Length); + [RuntimeModuleGetter("path.bad_path_chars")] + [EvilDocProperty( + EvilDocPropertyMode.Get, + "An array containing characters that are not allowed in paths.", + ReturnType = DynamicValueType.Array + )] + private static DynamicValue GetRestrictedPathChars(DynamicValue _) + { + var invalidPathChars = Path.GetInvalidPathChars(); + var array = new ExecutionEngine.Collections.Array(invalidPathChars.Length); - for (var i = 0; i < invalidPathChars.Length; i++) - array[i] = invalidPathChars[i]; + for (var i = 0; i < invalidPathChars.Length; i++) + array[i] = invalidPathChars[i]; - return array; - } + return array; + } - [RuntimeModuleGetter("path.bad_fname_chars")] - [EvilDocProperty( - EvilDocPropertyMode.Get, - "An array containing characters that are not allowed in file names.", - ReturnType = DynamicValueType.Array - )] - private static DynamicValue GetRestrictedNameChars(DynamicValue _) - { - var invalidNameChars = Path.GetInvalidFileNameChars(); - var array = new Array(invalidNameChars.Length); + [RuntimeModuleGetter("path.bad_fname_chars")] + [EvilDocProperty( + EvilDocPropertyMode.Get, + "An array containing characters that are not allowed in file names.", + ReturnType = DynamicValueType.Array + )] + private static DynamicValue GetRestrictedNameChars(DynamicValue _) + { + var invalidNameChars = Path.GetInvalidFileNameChars(); + var array = new Array(invalidNameChars.Length); - for (var i = 0; i < invalidNameChars.Length; i++) - array[i] = invalidNameChars[i]; + for (var i = 0; i < invalidNameChars.Length; i++) + array[i] = invalidNameChars[i]; - return array; - } + return array; + } - [RuntimeModuleGetter("path.temp_dir")] - [EvilDocProperty( - EvilDocPropertyMode.Get, - "The path of the current user's temporary directory, or `nil` on failure. \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.String - )] - private static DynamicValue PathGetTempDirPath(DynamicValue _) + [RuntimeModuleGetter("path.temp_dir")] + [EvilDocProperty( + EvilDocPropertyMode.Get, + "The path of the current user's temporary directory, or `nil` on failure. \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.String + )] + private static DynamicValue PathGetTempDirPath(DynamicValue _) + { + try { - try - { - ClearError(); - return Path.GetTempPath(); - } - catch (Exception e) - { - SetError(e.Message); - return Nil; - } + ClearError(); + return Path.GetTempPath(); } - - [RuntimeModuleGetter("path.rand_fname")] - [EvilDocProperty( - EvilDocPropertyMode.Get, - "Each indexing attempt of this property will return a randomly generated name for a file system entity.", - ReturnType = DynamicValueType.String - )] - private static DynamicValue PathGetRandomFileName(DynamicValue _) - => Path.GetRandomFileName(); - - [RuntimeModuleFunction("path.cmb")] - [EvilDocFunction( - "Combines the provided strings into a path.", - Returns = "The combined paths, or `nil` on failure. \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.Number, - IsVariadic = true - )] - [EvilDocArgument( - "...", - "___At least 2___ strings to be combined into a path.", - DynamicValueType.String - )] - private static DynamicValue PathCombine(Fiber _, params DynamicValue[] args) + catch (Exception e) { - args.ExpectAtLeast(2); + SetError(e.Message); + return Nil; + } + } - var pathSegments = new string[args.Length]; - for (var i = 0; i < args.Length; i++) - { - args.ExpectStringAt(i, out pathSegments[i]); - } + [RuntimeModuleGetter("path.rand_fname")] + [EvilDocProperty( + EvilDocPropertyMode.Get, + "Each indexing attempt of this property will return a randomly generated name for a file system entity.", + ReturnType = DynamicValueType.String + )] + private static DynamicValue PathGetRandomFileName(DynamicValue _) + => Path.GetRandomFileName(); - try - { - ClearError(); - return Path.Combine(pathSegments).Replace('\\', '/'); - } - catch (Exception e) - { - SetError(e.Message); - return Nil; - } - } + [RuntimeModuleFunction("path.cmb")] + [EvilDocFunction( + "Combines the provided strings into a path.", + Returns = "The combined paths, or `nil` on failure. \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.Number, + IsVariadic = true + )] + [EvilDocArgument( + "...", + "___At least 2___ strings to be combined into a path.", + DynamicValueType.String + )] + private static DynamicValue PathCombine(Fiber _, params DynamicValue[] args) + { + args.ExpectAtLeast(2); - [RuntimeModuleFunction("path.get_fname")] - [EvilDocFunction( - "Returns the file name with or without extension from the specified path.", - Returns = "The string after the last directory separator in the provided path. \n" + - "Will return an empty string if the last character is a directory separator. \n" + - "Will return `nil` on failure - check `fs.error` for failure details.", - ReturnType = DynamicValueType.String - )] - [EvilDocArgument( - "without_extension", - "`true` to get the file name without extension, `false` to preserve it.", - DynamicValueType.Boolean, - DefaultValue = "false" - )] - private static DynamicValue PathGetFileName(Fiber _, params DynamicValue[] args) + var pathSegments = new string[args.Length]; + for (var i = 0; i < args.Length; i++) { - args.ExpectStringAt(0, out var path) - .OptionalBooleanAt(1, false, out var withoutExtension); - - try - { - ClearError(); + args.ExpectStringAt(i, out pathSegments[i]); + } - if (withoutExtension) - { - return Path.GetFileNameWithoutExtension(path); - } - else - { - return Path.GetFileName(path); - } - } - catch (Exception e) - { - SetError(e.Message); - return Nil; - } + try + { + ClearError(); + return Path.Combine(pathSegments).Replace('\\', '/'); } + catch (Exception e) + { + SetError(e.Message); + return Nil; + } + } - [RuntimeModuleFunction("path.get_dname")] - [EvilDocFunction( - "Attempts to retrieve the path leading up to the parent directory of the last file system entity described by the given path.", - Returns = "The parent directory of the last file system entity (e.g. `/var/lib/file` -> `/var/lib`), or `nil on failure.", - ReturnType = DynamicValueType.String - )] - [EvilDocArgument("path", "A path to be transformed.", DynamicValueType.String)] - private static DynamicValue PathGetDirectoryName(Fiber _, params DynamicValue[] args) + [RuntimeModuleFunction("path.get_fname")] + [EvilDocFunction( + "Returns the file name with or without extension from the specified path.", + Returns = "The string after the last directory separator in the provided path. \n" + + "Will return an empty string if the last character is a directory separator. \n" + + "Will return `nil` on failure - check `fs.error` for failure details.", + ReturnType = DynamicValueType.String + )] + [EvilDocArgument( + "without_extension", + "`true` to get the file name without extension, `false` to preserve it.", + DynamicValueType.Boolean, + DefaultValue = "false" + )] + private static DynamicValue PathGetFileName(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var path) + .OptionalBooleanAt(1, false, out var withoutExtension); + + try { - args.ExpectStringAt(0, out var path); + ClearError(); - try + if (withoutExtension) { - ClearError(); - return Path.GetDirectoryName(path)!.Replace('\\', '/'); + return Path.GetFileNameWithoutExtension(path); } - catch (Exception e) + else { - SetError(e.Message); - return Nil; + return Path.GetFileName(path); } } - - [RuntimeModuleFunction("path.exists")] - [EvilDocFunction( - "Checks if the given path leads to a valid file system entity.", - Returns = "`true` if the given path leads to any valid file system entity. `false` otherwise, or when the operation fails. \n" + - "`fs.error` is not set by this function, even on failure.", - ReturnType = DynamicValueType.Boolean - )] - [EvilDocArgument("path", "The path to be checked.")] - private static DynamicValue PathExists(Fiber _, params DynamicValue[] args) + catch (Exception e) { - args.ExpectStringAt(0, out var path); + SetError(e.Message); + return Nil; + } + } + + [RuntimeModuleFunction("path.get_dname")] + [EvilDocFunction( + "Attempts to retrieve the path leading up to the parent directory of the last file system entity described by the given path.", + Returns = "The parent directory of the last file system entity (e.g. `/var/lib/file` -> `/var/lib`), or `nil on failure.", + ReturnType = DynamicValueType.String + )] + [EvilDocArgument("path", "A path to be transformed.", DynamicValueType.String)] + private static DynamicValue PathGetDirectoryName(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var path); + try + { ClearError(); - return Path.Exists(path); + return Path.GetDirectoryName(path)!.Replace('\\', '/'); } - - [RuntimeModuleFunction("path.get_ext")] - [EvilDocFunction( - "Attempts to extract the extension part of the given path.", - Returns = "The extension part of a given path, an empty string if no extension is present, or `nil` when the operation fails. \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.String)] - [EvilDocArgument("path", "A path from which to extract the extension part.", DynamicValueType.String)] - [EvilDocArgument( - "with_dot", - "`true` to include the dot with the extension, `false` to trim it away.", - DynamicValueType.Boolean, - DefaultValue = "true" - )] - private static DynamicValue PathGetExtension(Fiber _, params DynamicValue[] args) + catch (Exception e) { - args.ExpectStringAt(0, out var path) - .OptionalBooleanAt(1, true, out var withDot); - - try - { - ClearError(); - - var ext = Path.GetExtension(path); + SetError(e.Message); + return Nil; + } + } - if (!withDot) - { - ext = ext.TrimStart('.'); - } + [RuntimeModuleFunction("path.exists")] + [EvilDocFunction( + "Checks if the given path leads to a valid file system entity.", + Returns = "`true` if the given path leads to any valid file system entity. `false` otherwise, or when the operation fails. \n" + + "`fs.error` is not set by this function, even on failure.", + ReturnType = DynamicValueType.Boolean + )] + [EvilDocArgument("path", "The path to be checked.")] + private static DynamicValue PathExists(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var path); - return ext; - } - catch (Exception e) - { - SetError(e.Message); - return Nil; - } - } + ClearError(); + return Path.Exists(path); + } - [RuntimeModuleFunction("path.has_ext")] - [EvilDocFunction( - "Checks if the provided path contains extension information.", - Returns = "`true` if the path ends with a `.` followed by at least 1 character, `false` if not and `nil` when the operation fails. \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.Boolean - )] - [EvilDocArgument("path", "A path to be checked.", DynamicValueType.String)] - private static DynamicValue PathHasExtension(Fiber _, params DynamicValue[] args) + [RuntimeModuleFunction("path.get_ext")] + [EvilDocFunction( + "Attempts to extract the extension part of the given path.", + Returns = "The extension part of a given path, an empty string if no extension is present, or `nil` when the operation fails. \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.String)] + [EvilDocArgument("path", "A path from which to extract the extension part.", DynamicValueType.String)] + [EvilDocArgument( + "with_dot", + "`true` to include the dot with the extension, `false` to trim it away.", + DynamicValueType.Boolean, + DefaultValue = "true" + )] + private static DynamicValue PathGetExtension(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var path) + .OptionalBooleanAt(1, true, out var withDot); + + try { - args.ExpectStringAt(0, out var path); + ClearError(); + + var ext = Path.GetExtension(path); - try - { - ClearError(); - return Path.HasExtension(path); - } - catch (Exception e) + if (!withDot) { - SetError(e.Message); - return Nil; + ext = ext.TrimStart('.'); } + + return ext; } - - [RuntimeModuleFunction("path.chg_ext")] - [EvilDocFunction( - "Changes the extension of the given path.", - Returns = "The modified path. If the path has no extension it will be appended. \n" + - "Will return `nil` when the operation fails. Check `fs.error` for failure details.", - ReturnType = DynamicValueType.String - )] - [EvilDocArgument("path", "The path to be modified.", DynamicValueType.String)] - [EvilDocArgument( - "new_ext", - "An extension (either dot-prefixed or not) to be applied to the given path. " + - "Specify `nil` to remove an existing path extension instead.", - DynamicValueType.String, - CanBeNil = true - )] - private static DynamicValue PathChangeExtension(Fiber _, params DynamicValue[] args) + catch (Exception e) { - args.ExpectStringAt(0, out var path) - .ExpectStringAt(1, out var newExt, allowNil: true); + SetError(e.Message); + return Nil; + } + } + + [RuntimeModuleFunction("path.has_ext")] + [EvilDocFunction( + "Checks if the provided path contains extension information.", + Returns = "`true` if the path ends with a `.` followed by at least 1 character, `false` if not and `nil` when the operation fails. \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.Boolean + )] + [EvilDocArgument("path", "A path to be checked.", DynamicValueType.String)] + private static DynamicValue PathHasExtension(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var path); - try - { - ClearError(); - return Path.ChangeExtension(path, newExt); - } - catch (Exception e) - { - SetError(e.Message); - return Nil; - } + try + { + ClearError(); + return Path.HasExtension(path); } + catch (Exception e) + { + SetError(e.Message); + return Nil; + } + } - [RuntimeModuleFunction("path.get_full")] - [EvilDocFunction( - "Attempts to retrieve an absolute path for the given path string.", - Returns = "The fully qualified location of the provided path, e.g. `/var/lib/file.txt`, or `nil` when the operation fails. \n" + - "Check `fs.error` for failure details.", - ReturnType = DynamicValueType.String - )] - [EvilDocArgument("path", "A file or directory path of which to retrieve an absolute path for.", DynamicValueType.String)] - private static DynamicValue PathGetFullPath(Fiber _, params DynamicValue[] args) + [RuntimeModuleFunction("path.chg_ext")] + [EvilDocFunction( + "Changes the extension of the given path.", + Returns = "The modified path. If the path has no extension it will be appended. \n" + + "Will return `nil` when the operation fails. Check `fs.error` for failure details.", + ReturnType = DynamicValueType.String + )] + [EvilDocArgument("path", "The path to be modified.", DynamicValueType.String)] + [EvilDocArgument( + "new_ext", + "An extension (either dot-prefixed or not) to be applied to the given path. " + + "Specify `nil` to remove an existing path extension instead.", + DynamicValueType.String, + CanBeNil = true + )] + private static DynamicValue PathChangeExtension(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var path) + .ExpectStringAt(1, out var newExt, allowNil: true); + + try + { + ClearError(); + return Path.ChangeExtension(path, newExt); + } + catch (Exception e) { - args.ExpectStringAt(0, out var path); + SetError(e.Message); + return Nil; + } + } + + [RuntimeModuleFunction("path.get_full")] + [EvilDocFunction( + "Attempts to retrieve an absolute path for the given path string.", + Returns = "The fully qualified location of the provided path, e.g. `/var/lib/file.txt`, or `nil` when the operation fails. \n" + + "Check `fs.error` for failure details.", + ReturnType = DynamicValueType.String + )] + [EvilDocArgument("path", "A file or directory path of which to retrieve an absolute path for.", DynamicValueType.String)] + private static DynamicValue PathGetFullPath(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var path); - try - { - ClearError(); - return Path.GetFullPath(path); - } - catch (Exception e) - { - SetError(e.Message); - return Nil; - } + try + { + ClearError(); + return Path.GetFullPath(path); + } + catch (Exception e) + { + SetError(e.Message); + return Nil; } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Modules/FsModule.Utilities.cs b/VirtualMachine/EVIL.Ceres.Runtime/Modules/FsModule.Utilities.cs index cb616951..fe8cf6f7 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Modules/FsModule.Utilities.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Modules/FsModule.Utilities.cs @@ -1,54 +1,53 @@ +namespace EVIL.Ceres.Runtime.Modules; + using System; using System.IO; -namespace EVIL.Ceres.Runtime.Modules +public partial class FsModule { - public partial class FsModule + private static void CopyDirectoryRecursively(DirectoryInfo source, DirectoryInfo target, bool overwriteExisting) { - private static void CopyDirectoryRecursively(DirectoryInfo source, DirectoryInfo target, bool overwriteExisting) - { - Directory.CreateDirectory(target.FullName); - - foreach (var fileInfo in source.GetFiles()) - { - fileInfo.CopyTo( - Path.Combine(target.FullName, fileInfo.Name), - overwriteExisting - ); - } + Directory.CreateDirectory(target.FullName); - foreach (var sourceSubDir in source.GetDirectories()) - { - var nextTargetSubDir = target.CreateSubdirectory(sourceSubDir.Name); - CopyDirectoryRecursively(sourceSubDir, nextTargetSubDir, overwriteExisting); - } + foreach (var fileInfo in source.GetFiles()) + { + fileInfo.CopyTo( + Path.Combine(target.FullName, fileInfo.Name), + overwriteExisting + ); } - private static (FileAccess Access, FileMode FileMode) AccessAndModeFromString(string modeString) + foreach (var sourceSubDir in source.GetDirectories()) { - var (access, fileMode) = ((FileAccess)0, (FileMode)0); - var hasPlus = modeString.Contains('+'); - modeString = modeString.Replace("+", ""); + var nextTargetSubDir = target.CreateSubdirectory(sourceSubDir.Name); + CopyDirectoryRecursively(sourceSubDir, nextTargetSubDir, overwriteExisting); + } + } + + private static (FileAccess Access, FileMode FileMode) AccessAndModeFromString(string modeString) + { + var (access, fileMode) = ((FileAccess)0, (FileMode)0); + var hasPlus = modeString.Contains('+'); + modeString = modeString.Replace("+", ""); - (access, fileMode) = modeString switch - { - "r" when hasPlus => (FileAccess.ReadWrite, FileMode.Open), - "r" => (FileAccess.Read, FileMode.Open), + (access, fileMode) = modeString switch + { + "r" when hasPlus => (FileAccess.ReadWrite, FileMode.Open), + "r" => (FileAccess.Read, FileMode.Open), - "w" when hasPlus => (FileAccess.ReadWrite, FileMode.Create), - "w" => (FileAccess.Write, FileMode.Create), + "w" when hasPlus => (FileAccess.ReadWrite, FileMode.Create), + "w" => (FileAccess.Write, FileMode.Create), - "a" when hasPlus => (FileAccess.ReadWrite, FileMode.OpenOrCreate), - "a" => (FileAccess.Write, FileMode.Append), + "a" when hasPlus => (FileAccess.ReadWrite, FileMode.OpenOrCreate), + "a" => (FileAccess.Write, FileMode.Append), - "t" => (FileAccess.Write, FileMode.Truncate), - "rw" => (FileAccess.ReadWrite, FileMode.OpenOrCreate), - "wr" => (FileAccess.ReadWrite, FileMode.OpenOrCreate), + "t" => (FileAccess.Write, FileMode.Truncate), + "rw" => (FileAccess.ReadWrite, FileMode.OpenOrCreate), + "wr" => (FileAccess.ReadWrite, FileMode.OpenOrCreate), - _ => throw new ArgumentException($"Invalid file mode '{modeString}'.") - }; + _ => throw new ArgumentException($"Invalid file mode '{modeString}'.") + }; - return (access, fileMode); - } + return (access, fileMode); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Modules/FsModule.cs b/VirtualMachine/EVIL.Ceres.Runtime/Modules/FsModule.cs index 57d650ae..4f038153 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Modules/FsModule.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Modules/FsModule.cs @@ -1,42 +1,42 @@ +namespace EVIL.Ceres.Runtime.Modules; + +using static EVIL.Ceres.Runtime.EvilDocPropertyMode; +using static EVIL.CommonTypes.TypeSystem.DynamicValueType; + using System.IO; using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.TypeSystem; -using static EVIL.Ceres.Runtime.EvilDocPropertyMode; -using static EVIL.CommonTypes.TypeSystem.DynamicValueType; -namespace EVIL.Ceres.Runtime.Modules +public partial class FsModule : RuntimeModule { - public partial class FsModule : RuntimeModule - { - public override string FullyQualifiedName => "fs"; + public override string FullyQualifiedName => "fs"; - private static DynamicValue _error = DynamicValue.Nil; + private static DynamicValue _error = DynamicValue.Nil; - private static readonly Table _origin = new Table() - { - { "BEGIN", (long)SeekOrigin.Begin }, - { "CURRENT", (long)SeekOrigin.Current }, - { "END", (long)SeekOrigin.End } - }.Freeze(); + private static readonly Table _origin = new Table() + { + { "BEGIN", (long)SeekOrigin.Begin }, + { "CURRENT", (long)SeekOrigin.Current }, + { "END", (long)SeekOrigin.End } + }.Freeze(); - public FsModule() - { - Set("origin", _origin); - } + public FsModule() + { + Set("origin", _origin); + } - [RuntimeModuleGetter("error")] - [EvilDocProperty(Get, - "Retrieves the error message set by the last file system function call, " + - "or `nil` if the last operation was successful.", - ReturnType = String - )] - private static DynamicValue GetError(DynamicValue _) - => _error; + [RuntimeModuleGetter("error")] + [EvilDocProperty(Get, + "Retrieves the error message set by the last file system function call, " + + "or `nil` if the last operation was successful.", + ReturnType = String + )] + private static DynamicValue GetError(DynamicValue _) + => _error; - private static void ClearError() - => _error = DynamicValue.Nil; + private static void ClearError() + => _error = DynamicValue.Nil; - private static void SetError(string error) - => _error = error; - } + private static void SetError(string error) + => _error = error; } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Modules/IoModule.cs b/VirtualMachine/EVIL.Ceres.Runtime/Modules/IoModule.cs index 63fb53a7..063832ee 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Modules/IoModule.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Modules/IoModule.cs @@ -1,4 +1,6 @@ -using System; +namespace EVIL.Ceres.Runtime.Modules; + +using System; using System.Linq; using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.Concurrency; @@ -6,96 +8,93 @@ using EVIL.Ceres.Runtime.Extensions; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.Runtime.Modules +public class IoModule : RuntimeModule { - public class IoModule : RuntimeModule - { - public override string FullyQualifiedName => "io"; - - [RuntimeModuleFunction("print")] - [EvilDocFunction( - "Writes string representations of the provided values, separated by the tabulator character, to the standard output stream.", - Returns = "Length of the printed string, including the tabulator characters, if any.", - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument( - "...", - "__At least 1__ value to be printed.", - CanBeNil = true - )] - private static DynamicValue Print(Fiber _, params DynamicValue[] args) - { - args.ExpectAtLeast(1); + public override string FullyQualifiedName => "io"; - var str = string.Join( - "\t", - args.Select(x => x.ConvertToString().String) - ); + [RuntimeModuleFunction("print")] + [EvilDocFunction( + "Writes string representations of the provided values, separated by the tabulator character, to the standard output stream.", + Returns = "Length of the printed string, including the tabulator characters, if any.", + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument( + "...", + "__At least 1__ value to be printed.", + CanBeNil = true + )] + private static DynamicValue Print(Fiber _, params DynamicValue[] args) + { + args.ExpectAtLeast(1); - Console.Write(str); - return str.Length; - } + var str = string.Join( + "\t", + args.Select(x => x.ConvertToString().String) + ); - [RuntimeModuleFunction("println")] - [EvilDocFunction( - "Writes string representations of the provided values, separated by the tabulator character, followed by the platform's new line sequence, to the standard output stream.", - Returns = - "Length of the printed string, including the tabulator characters, if any, and the new line sequence.", - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument( - "...", - "An arbitrary (can be none) amount of values to be printed.", - CanBeNil = true - )] - private static DynamicValue PrintLine(Fiber _, params DynamicValue[] args) - { - var str = string.Join( - "\t", - args.Select(x => x.ConvertToString().String) - ); + Console.Write(str); + return str.Length; + } - Console.Write(str); - Console.Write(Environment.NewLine); + [RuntimeModuleFunction("println")] + [EvilDocFunction( + "Writes string representations of the provided values, separated by the tabulator character, followed by the platform's new line sequence, to the standard output stream.", + Returns = + "Length of the printed string, including the tabulator characters, if any, and the new line sequence.", + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument( + "...", + "An arbitrary (can be none) amount of values to be printed.", + CanBeNil = true + )] + private static DynamicValue PrintLine(Fiber _, params DynamicValue[] args) + { + var str = string.Join( + "\t", + args.Select(x => x.ConvertToString().String) + ); - return str.Length + Environment.NewLine.Length; - } + Console.Write(str); + Console.Write(Environment.NewLine); - [RuntimeModuleFunction("readkey")] - [EvilDocFunction( - "Waits until the user presses a key.", - Returns = "A table representing information about the pressed key.", - ReturnType = DynamicValueType.Table - )] - [EvilDocArgument( - "echo_to_stdout", - "Whether to echo the pressed key to the standard output stream.", - DynamicValueType.Boolean, - CanBeNil = false, - DefaultValue = "true" - )] - private static DynamicValue ReadKey(Fiber _, params DynamicValue[] args) - { - args.ExpectAtMost(1) - .OptionalBooleanAt(0, true, out var echoToStdout); + return str.Length + Environment.NewLine.Length; + } - var key = Console.ReadKey(!echoToStdout); + [RuntimeModuleFunction("readkey")] + [EvilDocFunction( + "Waits until the user presses a key.", + Returns = "A table representing information about the pressed key.", + ReturnType = DynamicValueType.Table + )] + [EvilDocArgument( + "echo_to_stdout", + "Whether to echo the pressed key to the standard output stream.", + DynamicValueType.Boolean, + CanBeNil = false, + DefaultValue = "true" + )] + private static DynamicValue ReadKey(Fiber _, params DynamicValue[] args) + { + args.ExpectAtMost(1) + .OptionalBooleanAt(0, true, out var echoToStdout); - return new Table - { - { "keycode", (int)key.Key }, - { "char", key.KeyChar.ToString() }, - { "modifiers", (int)key.Modifiers } - }; - } + var key = Console.ReadKey(!echoToStdout); - [RuntimeModuleFunction("readln")] - [EvilDocFunction( - "Waits until the user inputs a string and accepts it with Return key", - Returns = "A string containing the input entered by the user, or `nil` if no more lines are available..", - ReturnType = DynamicValueType.String - )] - private static DynamicValue ReadLine(Fiber _, params DynamicValue[] __) - => Console.ReadLine() ?? DynamicValue.Nil; + return new Table + { + { "keycode", (int)key.Key }, + { "char", key.KeyChar.ToString() }, + { "modifiers", (int)key.Modifiers } + }; } + + [RuntimeModuleFunction("readln")] + [EvilDocFunction( + "Waits until the user inputs a string and accepts it with Return key", + Returns = "A string containing the input entered by the user, or `nil` if no more lines are available..", + ReturnType = DynamicValueType.String + )] + private static DynamicValue ReadLine(Fiber _, params DynamicValue[] __) + => Console.ReadLine() ?? DynamicValue.Nil; } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Modules/MathModule.cs b/VirtualMachine/EVIL.Ceres.Runtime/Modules/MathModule.cs index ac62cc86..1c60df55 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Modules/MathModule.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Modules/MathModule.cs @@ -1,610 +1,610 @@ -using System; +namespace EVIL.Ceres.Runtime.Modules; + +using static EVIL.Ceres.Runtime.EvilDocPropertyMode; + +using System; using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.Concurrency; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.Ceres.Runtime.Extensions; using EVIL.CommonTypes.TypeSystem; -using static EVIL.Ceres.Runtime.EvilDocPropertyMode; -namespace EVIL.Ceres.Runtime.Modules -{ - public sealed class MathModule : RuntimeModule - { - public override string FullyQualifiedName => "math"; - - private static readonly Table _randTable = new PropertyTable() - { - { "i32", (_) => Random.Shared.Next() }, - { "i64", (_) => Random.Shared.NextInt64() }, - { "f32", (_) => Random.Shared.NextSingle() }, - { "f64", (_) => Random.Shared.NextDouble() } - }.Freeze(); - - [RuntimeModuleGetter("max_val")] - [EvilDocProperty( - Get, - "Gets the highest possible value a Number type can hold.", - ReturnType = DynamicValueType.Number - )] - private static DynamicValue MaxValue(DynamicValue _) - => double.MaxValue; +public sealed class MathModule : RuntimeModule +{ + public override string FullyQualifiedName => "math"; + + private static readonly Table _randTable = new PropertyTable() + { + { "i32", (_) => Random.Shared.Next() }, + { "i64", (_) => Random.Shared.NextInt64() }, + { "f32", (_) => Random.Shared.NextSingle() }, + { "f64", (_) => Random.Shared.NextDouble() } + }.Freeze(); + + [RuntimeModuleGetter("max_val")] + [EvilDocProperty( + Get, + "Gets the highest possible value a Number type can hold.", + ReturnType = DynamicValueType.Number + )] + private static DynamicValue MaxValue(DynamicValue _) + => double.MaxValue; - [RuntimeModuleGetter("min_val")] - [EvilDocProperty( - Get, - "Gets the lowest possible value a Number type can hold.", - ReturnType = DynamicValueType.Number - )] - private static DynamicValue MinValue(DynamicValue _) - => double.MaxValue; + [RuntimeModuleGetter("min_val")] + [EvilDocProperty( + Get, + "Gets the lowest possible value a Number type can hold.", + ReturnType = DynamicValueType.Number + )] + private static DynamicValue MinValue(DynamicValue _) + => double.MaxValue; - [RuntimeModuleGetter("r")] - [EvilDocProperty( - Get, - "Gets a random value of the specified type. \n" + - "> `.i32` \n" + - "> Gets a random signed 32-bit integer. \n\n" + - "" + - "> `.i64` \n" + - "> Gets a random signed 64-bit integer. \n\n" + - "" + - "> `.f32` \n" + - "> Gets a random 32-bit floating point number. \n\n" + - "" + - ">`.f64` \n" + - "> Gets a random 64-bit floating point number. \n\n", - ReturnType = DynamicValueType.Table - )] - private static DynamicValue Rand(DynamicValue _) - => _randTable; - - [RuntimeModuleGetter("pi")] - [EvilDocProperty( - Get, - "Gets the value of the π constant.", - ReturnType = DynamicValueType.Number - )] - private static DynamicValue Pi(DynamicValue _) - => Math.PI; + [RuntimeModuleGetter("r")] + [EvilDocProperty( + Get, + "Gets a random value of the specified type. \n" + + "> `.i32` \n" + + "> Gets a random signed 32-bit integer. \n\n" + + "" + + "> `.i64` \n" + + "> Gets a random signed 64-bit integer. \n\n" + + "" + + "> `.f32` \n" + + "> Gets a random 32-bit floating point number. \n\n" + + "" + + ">`.f64` \n" + + "> Gets a random 64-bit floating point number. \n\n", + ReturnType = DynamicValueType.Table + )] + private static DynamicValue Rand(DynamicValue _) + => _randTable; + + [RuntimeModuleGetter("pi")] + [EvilDocProperty( + Get, + "Gets the value of the π constant.", + ReturnType = DynamicValueType.Number + )] + private static DynamicValue Pi(DynamicValue _) + => Math.PI; - [RuntimeModuleGetter("e")] - [EvilDocProperty( - Get, - "Gets the value of the e constant.", - ReturnType = DynamicValueType.Number - )] - private static DynamicValue E(DynamicValue _) - => Math.E; - - [RuntimeModuleGetter("tau")] - [EvilDocProperty( - Get, - "Gets the value of the τ constant.", - ReturnType = DynamicValueType.Number - )] - private static DynamicValue Tau(DynamicValue _) - => Math.Tau; - - [RuntimeModuleFunction("abs")] - [EvilDocFunction( - "Calculates the absolute value of a Number.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "A value whose absolute value to calculate.", DynamicValueType.Number)] - private static DynamicValue Abs(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); - - return Math.Abs(value); - } - - [RuntimeModuleFunction("acos")] - [EvilDocFunction( - "Calculates the angle (radians) whose cosine is the specified Number.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "A cosine whose angle to calculate.", DynamicValueType.Number)] - private static DynamicValue Acos(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); - - return Math.Acos(value); - } - - [RuntimeModuleFunction("acosh")] - [EvilDocFunction( - "Calculates the angle (radians) whose hyperbolic cosine is the specified Number.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "A hyperbolic cosine whose angle to calculate.", DynamicValueType.Number)] - private static DynamicValue Acosh(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); - - return Math.Acosh(value); - } - - [RuntimeModuleFunction("asin")] - [EvilDocFunction( - "Calculates the angle (radians) whose sine is the specified Number.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "A sine whose angle to calculate.", DynamicValueType.Number)] - private static DynamicValue Asin(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); - - return Math.Asin(value); - } - - [RuntimeModuleFunction("asinh")] - [EvilDocFunction( - "Calculates the angle (radians) whose hyperbolic sine is the specified Number.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "A hyperbolic sine whose angle to calculate.", DynamicValueType.Number)] - private static DynamicValue Asinh(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); - - return Math.Asinh(value); - } - - [RuntimeModuleFunction("atan")] - [EvilDocFunction( - "Calculates the angle (radians) whose tangent is the specified Number.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "A tangent whose angle to calculate.", DynamicValueType.Number)] - private static DynamicValue Atan(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); - - return Math.Atan(value); - } - - [RuntimeModuleFunction("atanh")] - [EvilDocFunction( - "Calculates the angle (radians) whose hyperbolic tangent is the specified Number.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "A hyperbolic tangent whose angle to calculate.", DynamicValueType.Number)] - private static DynamicValue Atanh(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); - - return Math.Atanh(value); - } - - [RuntimeModuleFunction("atan2")] - [EvilDocFunction( - "Calculates the angle (radians) whose tangent is the quotient of two provided coordinates.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("x", "The X-component of the coordinate.", DynamicValueType.Number)] - [EvilDocArgument("y", "The Y-component of the coordinate.", DynamicValueType.Number)] - private static DynamicValue Atan2(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(2) - .ExpectNumberAt(0, out var x) - .ExpectNumberAt(1, out var y); - - return Math.Atan2(y, x); - } - - [RuntimeModuleFunction("cbrt")] - [EvilDocFunction( - "Calculates the cube root of the specified Number.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "A value whose cube root to calculate.", DynamicValueType.Number)] - private static DynamicValue Cbrt(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); - - return Math.Cbrt(value); - } - - [RuntimeModuleFunction("ceil")] - [EvilDocFunction( - "Calculates the smallest integer that's greater than or equal to the specified Number.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "A value whose ceiling to calculate.", DynamicValueType.Number)] - private static DynamicValue Ceiling(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); - - return Math.Ceiling(value); - } - - [RuntimeModuleFunction("clamp")] - [EvilDocFunction( - "Clamps the provided value to the _inclusive_ range specified by `min` and `max` parameters.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "A value to be clamped.", DynamicValueType.Number)] - [EvilDocArgument("min", "A lower inclusive bound of the clamping operation. ", DynamicValueType.Number)] - [EvilDocArgument("max", "An upper inclusive bound of the clamping operation. ", DynamicValueType.Number)] - private static DynamicValue Clamp(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(3) - .ExpectNumberAt(0, out var value) - .ExpectNumberAt(1, out var min) - .ExpectNumberAt(2, out var max); - - return Math.Clamp(value, min, max); - } - - [RuntimeModuleFunction("cos")] - [EvilDocFunction( - "Calculates the cosine of the given angle.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "An angle (radians) whose cosine to calculate.", DynamicValueType.Number)] - private static DynamicValue Cos(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); - - return Math.Cos(value); - } - - [RuntimeModuleFunction("cosh")] - [EvilDocFunction( - "Calculates the hyperbolic cosine of the given angle.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "An angle (radians) whose hyperbolic cosine to calculate.", DynamicValueType.Number)] - private static DynamicValue Cosh(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); - - return Math.Cosh(value); - } - - [RuntimeModuleFunction("exp")] - [EvilDocFunction( - "Calculates `math.e` raised to the given power.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "A power to which `math.e` should be raised.", DynamicValueType.Number)] - private static DynamicValue Exp(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); - - return Math.Exp(value); - } - - [RuntimeModuleFunction("floor")] - [EvilDocFunction( - "Calculates the largest integer that's less than or equal to the specified Number.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "A value whose floor to calculate.", DynamicValueType.Number)] - private static DynamicValue Floor(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); - - return Math.Floor(value); - } - - [RuntimeModuleFunction("lerp")] - [EvilDocFunction( - "Calculates a value linearly interpolated between two values for the given interpolant.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("a", "Start value, returned when `t == 0`.", DynamicValueType.Number)] - [EvilDocArgument("b", "End value, returned when `t == 1`.", DynamicValueType.Number)] - [EvilDocArgument("t", "Position on the line between `a` and `b`. The interpolant is expressed as a number in range of [0.0 - 1.0].", DynamicValueType.Number)] - private static DynamicValue Lerp(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(3) - .ExpectNumberAt(0, out var a) - .ExpectNumberAt(1, out var b) - .ExpectNumberAt(2, out var t); - - t = Math.Clamp(t, 0.0, 1.0); - return a * (1 - t) + b * t; - } - - [RuntimeModuleFunction("log")] - [EvilDocFunction( - "Calculates the logarithm of a specified number in a specified base.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "A value whose logarithm to calculate.", DynamicValueType.Number)] - [EvilDocArgument("base", "Base of the logarithm", DynamicValueType.Number)] - private static DynamicValue Log(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(2) - .ExpectNumberAt(0, out var value) - .ExpectNumberAt(1, out var @base); - - return Math.Log(value, @base); - } - - [RuntimeModuleFunction("log2")] - [EvilDocFunction( - "Calculates the base 2 logarithm of a specified number.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "A value whose logarithm to calculate.", DynamicValueType.Number)] - private static DynamicValue Log2(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); - - return Math.Log2(value); - } - - [RuntimeModuleFunction("log10")] - [EvilDocFunction( - "Calculates the base 10 logarithm of a specified number.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "A value whose logarithm to calculate.", DynamicValueType.Number)] - private static DynamicValue Log10(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); - - return Math.Log10(value); - } - - [RuntimeModuleFunction("max")] - [EvilDocFunction( - "Returns the larger of the provided values.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("a", "First value to be checked.", DynamicValueType.Number)] - [EvilDocArgument("a", "Second value to be checked.", DynamicValueType.Number)] - private static DynamicValue Max(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(2) - .ExpectNumberAt(0, out var a) - .ExpectNumberAt(1, out var b); - - return Math.Max(a, b); - } - - [RuntimeModuleFunction("min")] - [EvilDocFunction( - "Returns the smaller of the provided values.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("a", "First value to be checked.", DynamicValueType.Number)] - [EvilDocArgument("a", "Second value to be checked.", DynamicValueType.Number)] - private static DynamicValue Min(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(2) - .ExpectNumberAt(0, out var a) - .ExpectNumberAt(1, out var b); - - return Math.Min(a, b); - } - - [RuntimeModuleFunction("pow")] - [EvilDocFunction( - "Calculates `x` raised to the power of `y`.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("x", "Base of the power.", DynamicValueType.Number)] - [EvilDocArgument("y", "Exponent of the power.", DynamicValueType.Number)] - private static DynamicValue Pow(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(2) - .ExpectNumberAt(0, out var x) - .ExpectNumberAt(1, out var y); - - return Math.Pow(x, y); - } - - [RuntimeModuleFunction("round")] - [EvilDocFunction( - "Rounds `x` to the specified number of decimal digits.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("x", "Number to be rounded.", DynamicValueType.Number)] - [EvilDocArgument("digits", "A number specifying the number of digits to round `x` to.", DynamicValueType.Number)] - private static DynamicValue Round(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(2) - .ExpectNumberAt(0, out var x) - .ExpectIntegerAt(1, out var digits); - - return Math.Round(x, (int)digits); - } - - [RuntimeModuleFunction("sign")] - [EvilDocFunction( - "Returns a value denoting the sign of the specified value.", - Returns = "`-1` if the value was negative, `0` if the value was 0, `1` if the value was positive.", - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "The value whose sign is to be evaluated.", DynamicValueType.Number)] - private static DynamicValue Sign(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); + [RuntimeModuleGetter("e")] + [EvilDocProperty( + Get, + "Gets the value of the e constant.", + ReturnType = DynamicValueType.Number + )] + private static DynamicValue E(DynamicValue _) + => Math.E; + + [RuntimeModuleGetter("tau")] + [EvilDocProperty( + Get, + "Gets the value of the τ constant.", + ReturnType = DynamicValueType.Number + )] + private static DynamicValue Tau(DynamicValue _) + => Math.Tau; + + [RuntimeModuleFunction("abs")] + [EvilDocFunction( + "Calculates the absolute value of a Number.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "A value whose absolute value to calculate.", DynamicValueType.Number)] + private static DynamicValue Abs(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); + + return Math.Abs(value); + } + + [RuntimeModuleFunction("acos")] + [EvilDocFunction( + "Calculates the angle (radians) whose cosine is the specified Number.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "A cosine whose angle to calculate.", DynamicValueType.Number)] + private static DynamicValue Acos(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); + + return Math.Acos(value); + } + + [RuntimeModuleFunction("acosh")] + [EvilDocFunction( + "Calculates the angle (radians) whose hyperbolic cosine is the specified Number.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "A hyperbolic cosine whose angle to calculate.", DynamicValueType.Number)] + private static DynamicValue Acosh(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); + + return Math.Acosh(value); + } + + [RuntimeModuleFunction("asin")] + [EvilDocFunction( + "Calculates the angle (radians) whose sine is the specified Number.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "A sine whose angle to calculate.", DynamicValueType.Number)] + private static DynamicValue Asin(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); + + return Math.Asin(value); + } + + [RuntimeModuleFunction("asinh")] + [EvilDocFunction( + "Calculates the angle (radians) whose hyperbolic sine is the specified Number.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "A hyperbolic sine whose angle to calculate.", DynamicValueType.Number)] + private static DynamicValue Asinh(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); + + return Math.Asinh(value); + } + + [RuntimeModuleFunction("atan")] + [EvilDocFunction( + "Calculates the angle (radians) whose tangent is the specified Number.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "A tangent whose angle to calculate.", DynamicValueType.Number)] + private static DynamicValue Atan(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); + + return Math.Atan(value); + } + + [RuntimeModuleFunction("atanh")] + [EvilDocFunction( + "Calculates the angle (radians) whose hyperbolic tangent is the specified Number.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "A hyperbolic tangent whose angle to calculate.", DynamicValueType.Number)] + private static DynamicValue Atanh(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); + + return Math.Atanh(value); + } + + [RuntimeModuleFunction("atan2")] + [EvilDocFunction( + "Calculates the angle (radians) whose tangent is the quotient of two provided coordinates.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("x", "The X-component of the coordinate.", DynamicValueType.Number)] + [EvilDocArgument("y", "The Y-component of the coordinate.", DynamicValueType.Number)] + private static DynamicValue Atan2(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(2) + .ExpectNumberAt(0, out var x) + .ExpectNumberAt(1, out var y); + + return Math.Atan2(y, x); + } + + [RuntimeModuleFunction("cbrt")] + [EvilDocFunction( + "Calculates the cube root of the specified Number.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "A value whose cube root to calculate.", DynamicValueType.Number)] + private static DynamicValue Cbrt(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); + + return Math.Cbrt(value); + } + + [RuntimeModuleFunction("ceil")] + [EvilDocFunction( + "Calculates the smallest integer that's greater than or equal to the specified Number.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "A value whose ceiling to calculate.", DynamicValueType.Number)] + private static DynamicValue Ceiling(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); + + return Math.Ceiling(value); + } + + [RuntimeModuleFunction("clamp")] + [EvilDocFunction( + "Clamps the provided value to the _inclusive_ range specified by `min` and `max` parameters.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "A value to be clamped.", DynamicValueType.Number)] + [EvilDocArgument("min", "A lower inclusive bound of the clamping operation. ", DynamicValueType.Number)] + [EvilDocArgument("max", "An upper inclusive bound of the clamping operation. ", DynamicValueType.Number)] + private static DynamicValue Clamp(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(3) + .ExpectNumberAt(0, out var value) + .ExpectNumberAt(1, out var min) + .ExpectNumberAt(2, out var max); + + return Math.Clamp(value, min, max); + } + + [RuntimeModuleFunction("cos")] + [EvilDocFunction( + "Calculates the cosine of the given angle.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "An angle (radians) whose cosine to calculate.", DynamicValueType.Number)] + private static DynamicValue Cos(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); + + return Math.Cos(value); + } + + [RuntimeModuleFunction("cosh")] + [EvilDocFunction( + "Calculates the hyperbolic cosine of the given angle.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "An angle (radians) whose hyperbolic cosine to calculate.", DynamicValueType.Number)] + private static DynamicValue Cosh(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); + + return Math.Cosh(value); + } + + [RuntimeModuleFunction("exp")] + [EvilDocFunction( + "Calculates `math.e` raised to the given power.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "A power to which `math.e` should be raised.", DynamicValueType.Number)] + private static DynamicValue Exp(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); + + return Math.Exp(value); + } + + [RuntimeModuleFunction("floor")] + [EvilDocFunction( + "Calculates the largest integer that's less than or equal to the specified Number.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "A value whose floor to calculate.", DynamicValueType.Number)] + private static DynamicValue Floor(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); + + return Math.Floor(value); + } + + [RuntimeModuleFunction("lerp")] + [EvilDocFunction( + "Calculates a value linearly interpolated between two values for the given interpolant.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("a", "Start value, returned when `t == 0`.", DynamicValueType.Number)] + [EvilDocArgument("b", "End value, returned when `t == 1`.", DynamicValueType.Number)] + [EvilDocArgument("t", "Position on the line between `a` and `b`. The interpolant is expressed as a number in range of [0.0 - 1.0].", DynamicValueType.Number)] + private static DynamicValue Lerp(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(3) + .ExpectNumberAt(0, out var a) + .ExpectNumberAt(1, out var b) + .ExpectNumberAt(2, out var t); + + t = Math.Clamp(t, 0.0, 1.0); + return a * (1 - t) + b * t; + } + + [RuntimeModuleFunction("log")] + [EvilDocFunction( + "Calculates the logarithm of a specified number in a specified base.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "A value whose logarithm to calculate.", DynamicValueType.Number)] + [EvilDocArgument("base", "Base of the logarithm", DynamicValueType.Number)] + private static DynamicValue Log(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(2) + .ExpectNumberAt(0, out var value) + .ExpectNumberAt(1, out var @base); + + return Math.Log(value, @base); + } + + [RuntimeModuleFunction("log2")] + [EvilDocFunction( + "Calculates the base 2 logarithm of a specified number.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "A value whose logarithm to calculate.", DynamicValueType.Number)] + private static DynamicValue Log2(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); + + return Math.Log2(value); + } + + [RuntimeModuleFunction("log10")] + [EvilDocFunction( + "Calculates the base 10 logarithm of a specified number.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "A value whose logarithm to calculate.", DynamicValueType.Number)] + private static DynamicValue Log10(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); + + return Math.Log10(value); + } + + [RuntimeModuleFunction("max")] + [EvilDocFunction( + "Returns the larger of the provided values.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("a", "First value to be checked.", DynamicValueType.Number)] + [EvilDocArgument("a", "Second value to be checked.", DynamicValueType.Number)] + private static DynamicValue Max(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(2) + .ExpectNumberAt(0, out var a) + .ExpectNumberAt(1, out var b); + + return Math.Max(a, b); + } + + [RuntimeModuleFunction("min")] + [EvilDocFunction( + "Returns the smaller of the provided values.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("a", "First value to be checked.", DynamicValueType.Number)] + [EvilDocArgument("a", "Second value to be checked.", DynamicValueType.Number)] + private static DynamicValue Min(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(2) + .ExpectNumberAt(0, out var a) + .ExpectNumberAt(1, out var b); + + return Math.Min(a, b); + } + + [RuntimeModuleFunction("pow")] + [EvilDocFunction( + "Calculates `x` raised to the power of `y`.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("x", "Base of the power.", DynamicValueType.Number)] + [EvilDocArgument("y", "Exponent of the power.", DynamicValueType.Number)] + private static DynamicValue Pow(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(2) + .ExpectNumberAt(0, out var x) + .ExpectNumberAt(1, out var y); + + return Math.Pow(x, y); + } + + [RuntimeModuleFunction("round")] + [EvilDocFunction( + "Rounds `x` to the specified number of decimal digits.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("x", "Number to be rounded.", DynamicValueType.Number)] + [EvilDocArgument("digits", "A number specifying the number of digits to round `x` to.", DynamicValueType.Number)] + private static DynamicValue Round(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(2) + .ExpectNumberAt(0, out var x) + .ExpectIntegerAt(1, out var digits); + + return Math.Round(x, (int)digits); + } + + [RuntimeModuleFunction("sign")] + [EvilDocFunction( + "Returns a value denoting the sign of the specified value.", + Returns = "`-1` if the value was negative, `0` if the value was 0, `1` if the value was positive.", + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "The value whose sign is to be evaluated.", DynamicValueType.Number)] + private static DynamicValue Sign(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); - return Math.Sign(value); - } - - [RuntimeModuleFunction("sin")] - [EvilDocFunction( - "Calculates the sine of the given angle.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "An angle (radians) whose sine to calculate.", DynamicValueType.Number)] - private static DynamicValue Sin(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); + return Math.Sign(value); + } + + [RuntimeModuleFunction("sin")] + [EvilDocFunction( + "Calculates the sine of the given angle.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "An angle (radians) whose sine to calculate.", DynamicValueType.Number)] + private static DynamicValue Sin(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); - return Math.Sin(value); - } - - [RuntimeModuleFunction("sincos")] - [EvilDocFunction( - "Calculates sine and cosine of the given angle.", - Returns = "A Table containing `sin` and `cos` fields with respective calclation results.", - ReturnType = DynamicValueType.Table - )] - [EvilDocArgument("value", "An angle (radians) whose sine and cosine to calculate.", DynamicValueType.Number)] - private static DynamicValue SinCos(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); + return Math.Sin(value); + } + + [RuntimeModuleFunction("sincos")] + [EvilDocFunction( + "Calculates sine and cosine of the given angle.", + Returns = "A Table containing `sin` and `cos` fields with respective calclation results.", + ReturnType = DynamicValueType.Table + )] + [EvilDocArgument("value", "An angle (radians) whose sine and cosine to calculate.", DynamicValueType.Number)] + private static DynamicValue SinCos(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); - var result = Math.SinCos(value); - - return new Table - { - { "sin", result.Sin }, - { "cos", result.Cos } - }; - } - - [RuntimeModuleFunction("sinh")] - [EvilDocFunction( - "Calculates the hyperbolic sine of the given angle.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "An angle (radians) whose hyperbolic sine to calculate.", DynamicValueType.Number)] - private static DynamicValue Sinh(Fiber _, params DynamicValue[] args) + var result = Math.SinCos(value); + + return new Table { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); + { "sin", result.Sin }, + { "cos", result.Cos } + }; + } + + [RuntimeModuleFunction("sinh")] + [EvilDocFunction( + "Calculates the hyperbolic sine of the given angle.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "An angle (radians) whose hyperbolic sine to calculate.", DynamicValueType.Number)] + private static DynamicValue Sinh(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); - return Math.Sinh(value); - } - - [RuntimeModuleFunction("sqrt")] - [EvilDocFunction( - "Calculates the square root of the given value.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "A number whose square root to calculate.", DynamicValueType.Number)] - private static DynamicValue Sqrt(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); + return Math.Sinh(value); + } + + [RuntimeModuleFunction("sqrt")] + [EvilDocFunction( + "Calculates the square root of the given value.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "A number whose square root to calculate.", DynamicValueType.Number)] + private static DynamicValue Sqrt(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); - return Math.Sqrt(value); - } - - [RuntimeModuleFunction("tan")] - [EvilDocFunction( - "Calculates the tangent of the given angle.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "An angle (radians) whose tangent to calculate.", DynamicValueType.Number)] - private static DynamicValue Tan(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); + return Math.Sqrt(value); + } + + [RuntimeModuleFunction("tan")] + [EvilDocFunction( + "Calculates the tangent of the given angle.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "An angle (radians) whose tangent to calculate.", DynamicValueType.Number)] + private static DynamicValue Tan(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); - return Math.Tan(value); - } - - [RuntimeModuleFunction("tanh")] - [EvilDocFunction( - "Calculates the hyperbolic tangent of the given angle.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "An angle (radians) whose hyperbolic tangent to calculate.", DynamicValueType.Number)] - private static DynamicValue Tanh(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); + return Math.Tan(value); + } + + [RuntimeModuleFunction("tanh")] + [EvilDocFunction( + "Calculates the hyperbolic tangent of the given angle.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "An angle (radians) whose hyperbolic tangent to calculate.", DynamicValueType.Number)] + private static DynamicValue Tanh(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); - return Math.Tanh(value); - } - - [RuntimeModuleFunction("trunc")] - [EvilDocFunction( - "Truncates the specified number to its integral part.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("value", "A number that is to be truncated.", DynamicValueType.Number)] - private static DynamicValue Trunc(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var value); + return Math.Tanh(value); + } + + [RuntimeModuleFunction("trunc")] + [EvilDocFunction( + "Truncates the specified number to its integral part.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("value", "A number that is to be truncated.", DynamicValueType.Number)] + private static DynamicValue Trunc(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var value); - return Math.Truncate(value); - } - - [RuntimeModuleFunction("rad2deg")] - [EvilDocFunction( - "Converts an angle expressed in radians to an angle expressed in degrees.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("radians", "The angle expressed in radians to be converted to degrees.", DynamicValueType.Number)] - private static DynamicValue Rad2Deg(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var radians); + return Math.Truncate(value); + } + + [RuntimeModuleFunction("rad2deg")] + [EvilDocFunction( + "Converts an angle expressed in radians to an angle expressed in degrees.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("radians", "The angle expressed in radians to be converted to degrees.", DynamicValueType.Number)] + private static DynamicValue Rad2Deg(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var radians); - return radians * (180.0 / Math.PI); - } - - [RuntimeModuleFunction("deg2rad")] - [EvilDocFunction( - "Converts an angle expressed in degrees to an angle expressed in radians.", - Returns = null, - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("degrees", "The angle expressed in degrees to be converted to radians.", DynamicValueType.Number)] - private static DynamicValue Deg2Rad(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectNumberAt(0, out var degrees); + return radians * (180.0 / Math.PI); + } + + [RuntimeModuleFunction("deg2rad")] + [EvilDocFunction( + "Converts an angle expressed in degrees to an angle expressed in radians.", + Returns = null, + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("degrees", "The angle expressed in degrees to be converted to radians.", DynamicValueType.Number)] + private static DynamicValue Deg2Rad(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectNumberAt(0, out var degrees); - return degrees * (Math.PI / 180.0); - } + return degrees * (Math.PI / 180.0); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Modules/StringModule.cs b/VirtualMachine/EVIL.Ceres.Runtime/Modules/StringModule.cs index 0f541bd2..2975c6d0 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Modules/StringModule.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Modules/StringModule.cs @@ -1,4 +1,10 @@ -using System; +namespace EVIL.Ceres.Runtime.Modules; + +using static EVIL.Ceres.ExecutionEngine.TypeSystem.DynamicValue; + +using Array = EVIL.Ceres.ExecutionEngine.Collections.Array; + +using System; using System.Globalization; using System.Linq; using System.Security.Cryptography; @@ -9,611 +15,606 @@ using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.Ceres.Runtime.Extensions; using EVIL.CommonTypes.TypeSystem; -using static EVIL.Ceres.ExecutionEngine.TypeSystem.DynamicValue; -using Array = EVIL.Ceres.ExecutionEngine.Collections.Array; -namespace EVIL.Ceres.Runtime.Modules +public sealed class StringModule : RuntimeModule { - public sealed class StringModule : RuntimeModule + public override string FullyQualifiedName => "str"; + + [RuntimeModuleGetter("empty")] + [EvilDocProperty(EvilDocPropertyMode.Get, "An empty string.", ReturnType = DynamicValueType.String)] + private static DynamicValue EmptyString(DynamicValue _) + => string.Empty; + + [RuntimeModuleFunction("chr")] + [EvilDocFunction( + "Converts a character code into its String representation.", + Returns = "The converted character code expressed as a String, or `nil` on error.", + ReturnType = DynamicValueType.String + )] + [EvilDocArgument("char_code", "A character code to be converted into a String.", DynamicValueType.String)] + private static DynamicValue ToCharacter(Fiber _, params DynamicValue[] args) { - public override string FullyQualifiedName => "str"; - - [RuntimeModuleGetter("empty")] - [EvilDocProperty(EvilDocPropertyMode.Get, "An empty string.", ReturnType = DynamicValueType.String)] - private static DynamicValue EmptyString(DynamicValue _) - => string.Empty; - - [RuntimeModuleFunction("chr")] - [EvilDocFunction( - "Converts a character code into its String representation.", - Returns = "The converted character code expressed as a String, or `nil` on error.", - ReturnType = DynamicValueType.String - )] - [EvilDocArgument("char_code", "A character code to be converted into a String.", DynamicValueType.String)] - private static DynamicValue ToCharacter(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectIntegerAt(0, out var charCode); - - if (charCode < 0 || charCode >= ushort.MaxValue) - { - return Nil; - } + args.ExpectExactly(1) + .ExpectIntegerAt(0, out var charCode); - return ((char)charCode).ToString(); - } - - [RuntimeModuleFunction("code")] - [EvilDocFunction( - "Converts a character to its 16-bit Unicode character code representation.", - Returns = "A 16-bit Unicode character code.", - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("chr", "A single-character string whose character code to retrieve.", DynamicValueType.String)] - private static DynamicValue ToCharacterCode(Fiber _, params DynamicValue[] args) + if (charCode < 0 || charCode >= ushort.MaxValue) { - args.ExpectExactly(1) - .ExpectCharAt(0, out var chr); - - return (ushort)chr; + return Nil; } - [RuntimeModuleFunction("replace")] - [EvilDocFunction( - "Replaces a provided String within the provided String with another String.", - Returns = "The modified string.", - ReturnType = DynamicValueType.String - )] - [EvilDocArgument("str", "A String to be modified.", DynamicValueType.String)] - [EvilDocArgument("to_replace", "A String to look for in order to replace.", DynamicValueType.String)] - [EvilDocArgument("with", "A String to serve as a replacement.", DynamicValueType.String)] - private static DynamicValue Replace(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(3) - .ExpectStringAt(0, out var str) - .ExpectStringAt(1, out var toReplace) - .ExpectStringAt(2, out var with); + return ((char)charCode).ToString(); + } + + [RuntimeModuleFunction("code")] + [EvilDocFunction( + "Converts a character to its 16-bit Unicode character code representation.", + Returns = "A 16-bit Unicode character code.", + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("chr", "A single-character string whose character code to retrieve.", DynamicValueType.String)] + private static DynamicValue ToCharacterCode(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectCharAt(0, out var chr); - return str.Replace(toReplace, with); - } + return (ushort)chr; + } - [RuntimeModuleFunction("bytes")] - [EvilDocFunction( - "Converts a String to its byte representation in the specified encoding.", - Returns = "An Array of bytes representing the provided String in the specified encoding.", - ReturnType = DynamicValueType.Array - )] - [EvilDocArgument("str", "A String that is to be converted.", DynamicValueType.String)] - [EvilDocArgument( - "encoding", - "Encoding to be used when converting the String to bytes.", - DynamicValueType.String, - DefaultValue = "utf-8" - )] - private static DynamicValue ToBytes(Fiber _, params DynamicValue[] args) - { - args.ExpectStringAt(0, out var str) - .OptionalStringAt(1, "utf-8", out var encoding); + [RuntimeModuleFunction("replace")] + [EvilDocFunction( + "Replaces a provided String within the provided String with another String.", + Returns = "The modified string.", + ReturnType = DynamicValueType.String + )] + [EvilDocArgument("str", "A String to be modified.", DynamicValueType.String)] + [EvilDocArgument("to_replace", "A String to look for in order to replace.", DynamicValueType.String)] + [EvilDocArgument("with", "A String to serve as a replacement.", DynamicValueType.String)] + private static DynamicValue Replace(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(3) + .ExpectStringAt(0, out var str) + .ExpectStringAt(1, out var toReplace) + .ExpectStringAt(2, out var with); - var bytes = Encoding.GetEncoding(encoding).GetBytes(str); - var array = new Array(bytes.Length); + return str.Replace(toReplace, with); + } - for (var i = 0; i < bytes.Length; i++) - { - array[i] = bytes[i]; - } + [RuntimeModuleFunction("bytes")] + [EvilDocFunction( + "Converts a String to its byte representation in the specified encoding.", + Returns = "An Array of bytes representing the provided String in the specified encoding.", + ReturnType = DynamicValueType.Array + )] + [EvilDocArgument("str", "A String that is to be converted.", DynamicValueType.String)] + [EvilDocArgument( + "encoding", + "Encoding to be used when converting the String to bytes.", + DynamicValueType.String, + DefaultValue = "utf-8" + )] + private static DynamicValue ToBytes(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var str) + .OptionalStringAt(1, "utf-8", out var encoding); - return array; - } + var bytes = Encoding.GetEncoding(encoding).GetBytes(str); + var array = new ExecutionEngine.Collections.Array(bytes.Length); - [RuntimeModuleFunction("explode")] - [EvilDocFunction( - "Puts each character of the provided String into an Array.", - Returns = "An Array containing every character of the provided String.", - ReturnType = DynamicValueType.Array - )] - [EvilDocArgument("str", "A String to explode.", DynamicValueType.String)] - private static DynamicValue Explode(Fiber _, params DynamicValue[] args) + for (var i = 0; i < bytes.Length; i++) { - args.ExpectExactly(1) - .ExpectStringAt(0, out var str); + array[i] = bytes[i]; + } - var array = Array.FromString(str); + return array; + } - for (var i = 0; i < array.Length; i++) + [RuntimeModuleFunction("explode")] + [EvilDocFunction( + "Puts each character of the provided String into an Array.", + Returns = "An Array containing every character of the provided String.", + ReturnType = DynamicValueType.Array + )] + [EvilDocArgument("str", "A String to explode.", DynamicValueType.String)] + private static DynamicValue Explode(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectStringAt(0, out var str); + + var array = ExecutionEngine.Collections.Array.FromString(str); + + for (var i = 0; i < array.Length; i++) + { + if (array[i] == "💣") { - if (array[i] == "💣") - { - array[i] = "💥"; - } + array[i] = "💥"; } - - return array; } - - [RuntimeModuleFunction("spl")] - [EvilDocFunction( - "Splits the provided String into segments by the given separator.", - Returns = "Segments of the provided String after splitting by the given separator.", - ReturnType = DynamicValueType.Array - )] - [EvilDocArgument("str", "A String to split.", DynamicValueType.String)] - [EvilDocArgument("delim", "A String to split `str` by.", DynamicValueType.String)] - [EvilDocArgument( - "skip_empty", - "Whether to skip empty strings resulting from the split operation.", - DynamicValueType.Boolean, - DefaultValue = "false" - )] - private static DynamicValue Split(Fiber _, params DynamicValue[] args) - { - args.ExpectAtLeast(2) - .ExpectStringAt(0, out var str) - .ExpectStringAt(1, out var separator) - .OptionalBooleanAt(2, false, out var skipEmpty); - var segments = str.Split(separator); - var array = new Array(0); + return array; + } + + [RuntimeModuleFunction("spl")] + [EvilDocFunction( + "Splits the provided String into segments by the given separator.", + Returns = "Segments of the provided String after splitting by the given separator.", + ReturnType = DynamicValueType.Array + )] + [EvilDocArgument("str", "A String to split.", DynamicValueType.String)] + [EvilDocArgument("delim", "A String to split `str` by.", DynamicValueType.String)] + [EvilDocArgument( + "skip_empty", + "Whether to skip empty strings resulting from the split operation.", + DynamicValueType.Boolean, + DefaultValue = "false" + )] + private static DynamicValue Split(Fiber _, params DynamicValue[] args) + { + args.ExpectAtLeast(2) + .ExpectStringAt(0, out var str) + .ExpectStringAt(1, out var separator) + .OptionalBooleanAt(2, false, out var skipEmpty); - for (var i = 0; i < segments.Length; i++) - { - if (string.IsNullOrEmpty(segments[i]) && skipEmpty) - continue; + var segments = str.Split(separator); + var array = new Array(0); - array.Push(segments[i]); - } + for (var i = 0; i < segments.Length; i++) + { + if (string.IsNullOrEmpty(segments[i]) && skipEmpty) + continue; - return array; + array.Push(segments[i]); } - [RuntimeModuleFunction("join")] - [EvilDocFunction( - "Concatenates the provided values into a String using the provided separator. " + - "The values provided will be converted to their String representations.", - Returns = "A concatenated String with the given separator inserted between each provided value.", - ReturnType = DynamicValueType.String, - IsVariadic = true - )] - [EvilDocArgument("separator", "A separator to be inserted between each given value during concatenation.", DynamicValueType.String)] - [EvilDocArgument("...", "An arbitrary amount of values to be concatenated into a String.")] - private static DynamicValue Join(Fiber _, params DynamicValue[] args) - { - args.ExpectAtLeast(1) - .ExpectStringAt(0, out var separator); + return array; + } - return string.Join(separator, args.Skip(1).Select(x => x.ConvertToString().String!)); - } + [RuntimeModuleFunction("join")] + [EvilDocFunction( + "Concatenates the provided values into a String using the provided separator. " + + "The values provided will be converted to their String representations.", + Returns = "A concatenated String with the given separator inserted between each provided value.", + ReturnType = DynamicValueType.String, + IsVariadic = true + )] + [EvilDocArgument("separator", "A separator to be inserted between each given value during concatenation.", DynamicValueType.String)] + [EvilDocArgument("...", "An arbitrary amount of values to be concatenated into a String.")] + private static DynamicValue Join(Fiber _, params DynamicValue[] args) + { + args.ExpectAtLeast(1) + .ExpectStringAt(0, out var separator); - [RuntimeModuleFunction("repeat")] - [EvilDocFunction( - "Repeats the provided String `count` times.", - Returns = "A String containing `str` repeated `count` times.", - ReturnType = DynamicValueType.String - )] - [EvilDocArgument("str", "A String to be repeated.", DynamicValueType.String)] - [EvilDocArgument("count", "An integer specifying the amount of times to repeat `str`.", DynamicValueType.Number)] - private static DynamicValue Repeat(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(2) - .ExpectStringAt(0, out var str) - .ExpectIntegerAt(1, out var count); + return string.Join(separator, args.Skip(1).Select(x => x.ConvertToString().String!)); + } - var sb = new StringBuilder(); - for (var i = 0; i < (int)count; i++) - sb.Append(str); + [RuntimeModuleFunction("repeat")] + [EvilDocFunction( + "Repeats the provided String `count` times.", + Returns = "A String containing `str` repeated `count` times.", + ReturnType = DynamicValueType.String + )] + [EvilDocArgument("str", "A String to be repeated.", DynamicValueType.String)] + [EvilDocArgument("count", "An integer specifying the amount of times to repeat `str`.", DynamicValueType.Number)] + private static DynamicValue Repeat(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(2) + .ExpectStringAt(0, out var str) + .ExpectIntegerAt(1, out var count); - return sb.ToString(); - } + var sb = new StringBuilder(); + for (var i = 0; i < (int)count; i++) + sb.Append(str); - [RuntimeModuleFunction("index_of")] - [EvilDocFunction( - "Finds the zero-based starting index of the first occurrence of `needle` in `haystack`.", - Returns = "The starting index of the first occurrence of `needle` in `haystack`, or `-1` if not found.", - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("haystack", "A String to be searched through.", DynamicValueType.String)] - [EvilDocArgument("needle", "A String to seek for.", DynamicValueType.String)] - private static DynamicValue IndexOf(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(2) - .ExpectStringAt(0, out var haystack) - .ExpectStringAt(1, out var needle); + return sb.ToString(); + } + + [RuntimeModuleFunction("index_of")] + [EvilDocFunction( + "Finds the zero-based starting index of the first occurrence of `needle` in `haystack`.", + Returns = "The starting index of the first occurrence of `needle` in `haystack`, or `-1` if not found.", + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("haystack", "A String to be searched through.", DynamicValueType.String)] + [EvilDocArgument("needle", "A String to seek for.", DynamicValueType.String)] + private static DynamicValue IndexOf(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(2) + .ExpectStringAt(0, out var haystack) + .ExpectStringAt(1, out var needle); - return haystack.IndexOf(needle, StringComparison.InvariantCulture); - } + return haystack.IndexOf(needle, StringComparison.InvariantCulture); + } - [RuntimeModuleFunction("last_index_of")] - [EvilDocFunction( - "Finds the zero-based starting index of the last occurrence of `needle` in `haystack`.", - Returns = "The starting index of the last occurrence of `needle` in `haystack`, or `-1` if not found.", - ReturnType = DynamicValueType.Number - )] - [EvilDocArgument("haystack", "A String to be searched through.", DynamicValueType.String)] - [EvilDocArgument("needle", "A String to seek for.", DynamicValueType.String)] - private static DynamicValue LastIndexOf(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(2) - .ExpectStringAt(0, out var haystack) - .ExpectStringAt(1, out var needle); + [RuntimeModuleFunction("last_index_of")] + [EvilDocFunction( + "Finds the zero-based starting index of the last occurrence of `needle` in `haystack`.", + Returns = "The starting index of the last occurrence of `needle` in `haystack`, or `-1` if not found.", + ReturnType = DynamicValueType.Number + )] + [EvilDocArgument("haystack", "A String to be searched through.", DynamicValueType.String)] + [EvilDocArgument("needle", "A String to seek for.", DynamicValueType.String)] + private static DynamicValue LastIndexOf(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(2) + .ExpectStringAt(0, out var haystack) + .ExpectStringAt(1, out var needle); - return haystack.LastIndexOf(needle, StringComparison.InvariantCulture); - } + return haystack.LastIndexOf(needle, StringComparison.InvariantCulture); + } - [RuntimeModuleFunction("is_whitespace")] - [EvilDocFunction( - "Checks if the provided String consists only of whitespace charracters.", - Returns = "`true` if the provided String consists only of whitespace characterrs, `false` otherwise.", - ReturnType = DynamicValueType.Boolean)] - [EvilDocArgument("str", "A String to be checked.", DynamicValueType.String)] - private static DynamicValue IsWhiteSpace(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectStringAt(0, out var str); + [RuntimeModuleFunction("is_whitespace")] + [EvilDocFunction( + "Checks if the provided String consists only of whitespace charracters.", + Returns = "`true` if the provided String consists only of whitespace characterrs, `false` otherwise.", + ReturnType = DynamicValueType.Boolean)] + [EvilDocArgument("str", "A String to be checked.", DynamicValueType.String)] + private static DynamicValue IsWhiteSpace(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectStringAt(0, out var str); - return string.IsNullOrWhiteSpace(str); - } + return string.IsNullOrWhiteSpace(str); + } - [RuntimeModuleFunction("lpad")] - [EvilDocFunction( - "Pads a shorter `str` so that its length matches `total_width` by appeding `padding_char` to its left side.", - Returns = "A String padded in the way described above.", - ReturnType = DynamicValueType.String - )] - [EvilDocArgument("str", "A String to be padded.", DynamicValueType.String)] - [EvilDocArgument("padding_char", "A character to be used for padding.", DynamicValueType.String)] - [EvilDocArgument("total_width", "Total length of the string to be matched.", DynamicValueType.Number)] - private static DynamicValue LeftPad(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(3) - .ExpectStringAt(0, out var str) - .ExpectCharAt(1, out var paddingChar) - .ExpectIntegerAt(2, out var totalWidth); + [RuntimeModuleFunction("lpad")] + [EvilDocFunction( + "Pads a shorter `str` so that its length matches `total_width` by appeding `padding_char` to its left side.", + Returns = "A String padded in the way described above.", + ReturnType = DynamicValueType.String + )] + [EvilDocArgument("str", "A String to be padded.", DynamicValueType.String)] + [EvilDocArgument("padding_char", "A character to be used for padding.", DynamicValueType.String)] + [EvilDocArgument("total_width", "Total length of the string to be matched.", DynamicValueType.Number)] + private static DynamicValue LeftPad(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(3) + .ExpectStringAt(0, out var str) + .ExpectCharAt(1, out var paddingChar) + .ExpectIntegerAt(2, out var totalWidth); - return str.PadLeft((int)totalWidth, paddingChar); - } + return str.PadLeft((int)totalWidth, paddingChar); + } - [RuntimeModuleFunction("rpad")] - [EvilDocFunction( - "Pads a shorter `str` so that its length matches `total_width` by appeding `padding_char` to its right side.", - Returns = "A String padded in the way described above.", - ReturnType = DynamicValueType.String - )] - [EvilDocArgument("str", "A String to be padded.", DynamicValueType.String)] - [EvilDocArgument("padding_char", "A character to be used for padding.", DynamicValueType.String)] - [EvilDocArgument("total_width", "Total length of the string to be matched.", DynamicValueType.Number)] - private static DynamicValue RightPad(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(3) - .ExpectStringAt(0, out var str) - .ExpectCharAt(1, out var pad) - .ExpectIntegerAt(2, out var totalWidth); + [RuntimeModuleFunction("rpad")] + [EvilDocFunction( + "Pads a shorter `str` so that its length matches `total_width` by appeding `padding_char` to its right side.", + Returns = "A String padded in the way described above.", + ReturnType = DynamicValueType.String + )] + [EvilDocArgument("str", "A String to be padded.", DynamicValueType.String)] + [EvilDocArgument("padding_char", "A character to be used for padding.", DynamicValueType.String)] + [EvilDocArgument("total_width", "Total length of the string to be matched.", DynamicValueType.Number)] + private static DynamicValue RightPad(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(3) + .ExpectStringAt(0, out var str) + .ExpectCharAt(1, out var pad) + .ExpectIntegerAt(2, out var totalWidth); - return str.PadRight((int)totalWidth, pad); - } + return str.PadRight((int)totalWidth, pad); + } - [RuntimeModuleFunction("trim")] - [EvilDocFunction( - "Removes the provided characters from both ends of the given String.", - Returns = "A String with the provided characters removed from both ends of the given String.", - ReturnType = DynamicValueType.String, - IsVariadic = true - )] - [EvilDocArgument("str", "A String to be trimmed.", DynamicValueType.String)] - [EvilDocArgument("...", "Zero or more single-character Strings. If none are provided, whitespace are assumed.", DynamicValueType.String)] - private static DynamicValue Trim(Fiber _, params DynamicValue[] args) - { - args.ExpectAtLeast(1) - .ExpectStringAt(0, out var str); + [RuntimeModuleFunction("trim")] + [EvilDocFunction( + "Removes the provided characters from both ends of the given String.", + Returns = "A String with the provided characters removed from both ends of the given String.", + ReturnType = DynamicValueType.String, + IsVariadic = true + )] + [EvilDocArgument("str", "A String to be trimmed.", DynamicValueType.String)] + [EvilDocArgument("...", "Zero or more single-character Strings. If none are provided, whitespace are assumed.", DynamicValueType.String)] + private static DynamicValue Trim(Fiber _, params DynamicValue[] args) + { + args.ExpectAtLeast(1) + .ExpectStringAt(0, out var str); - var chars = new char[args.Length - 1]; - if (args.Length > 1) + var chars = new char[args.Length - 1]; + if (args.Length > 1) + { + for (var i = 1; i < args.Length; i++) { - for (var i = 1; i < args.Length; i++) - { - args.ExpectCharAt(i, out chars[i - 1]); - } + args.ExpectCharAt(i, out chars[i - 1]); } - - return str.Trim(chars.ToArray()); } + + return str.Trim(chars.ToArray()); + } - [RuntimeModuleFunction("ltrim")] - [EvilDocFunction( - "Removes the provided characters from the start of the given String.", - Returns = "A String with the provided characters removed from the start of the given String.", - ReturnType = DynamicValueType.String, - IsVariadic = true - )] - [EvilDocArgument("str", "A String to be trimmed.", DynamicValueType.String)] - [EvilDocArgument("...", "__At least one__ single-character String.", DynamicValueType.String)] - private static DynamicValue LeftTrim(Fiber _, params DynamicValue[] args) - { - args.ExpectAtLeast(1) - .ExpectStringAt(0, out var str); + [RuntimeModuleFunction("ltrim")] + [EvilDocFunction( + "Removes the provided characters from the start of the given String.", + Returns = "A String with the provided characters removed from the start of the given String.", + ReturnType = DynamicValueType.String, + IsVariadic = true + )] + [EvilDocArgument("str", "A String to be trimmed.", DynamicValueType.String)] + [EvilDocArgument("...", "__At least one__ single-character String.", DynamicValueType.String)] + private static DynamicValue LeftTrim(Fiber _, params DynamicValue[] args) + { + args.ExpectAtLeast(1) + .ExpectStringAt(0, out var str); - var chars = new char[args.Length - 1]; - if (args.Length > 1) + var chars = new char[args.Length - 1]; + if (args.Length > 1) + { + for (var i = 1; i < args.Length; i++) { - for (var i = 1; i < args.Length; i++) - { - args.ExpectCharAt(i, out chars[i - 1]); - } + args.ExpectCharAt(i, out chars[i - 1]); } - - return str.TrimStart(chars.ToArray()); } + + return str.TrimStart(chars.ToArray()); + } - [RuntimeModuleFunction("rtrim")] - [EvilDocFunction( - "Removes the provided characters from the end of the given String.", - Returns = "A String with the provided characters removed from the end of the given String.", - ReturnType = DynamicValueType.String, - IsVariadic = true - )] - [EvilDocArgument("str", "A String to be trimmed.", DynamicValueType.String)] - [EvilDocArgument("...", "__At least one__ single-character String.", DynamicValueType.String)] - private static DynamicValue RightTrim(Fiber _, params DynamicValue[] args) - { - args.ExpectAtLeast(1) - .ExpectStringAt(0, out var str); + [RuntimeModuleFunction("rtrim")] + [EvilDocFunction( + "Removes the provided characters from the end of the given String.", + Returns = "A String with the provided characters removed from the end of the given String.", + ReturnType = DynamicValueType.String, + IsVariadic = true + )] + [EvilDocArgument("str", "A String to be trimmed.", DynamicValueType.String)] + [EvilDocArgument("...", "__At least one__ single-character String.", DynamicValueType.String)] + private static DynamicValue RightTrim(Fiber _, params DynamicValue[] args) + { + args.ExpectAtLeast(1) + .ExpectStringAt(0, out var str); - var chars = new char[args.Length - 1]; - if (args.Length > 1) + var chars = new char[args.Length - 1]; + if (args.Length > 1) + { + for (var i = 1; i < args.Length; i++) { - for (var i = 1; i < args.Length; i++) - { - args.ExpectCharAt(i, out chars[i - 1]); - } + args.ExpectCharAt(i, out chars[i - 1]); } - - return str.TrimEnd(chars.ToArray()); } + + return str.TrimEnd(chars.ToArray()); + } - [RuntimeModuleFunction("ucase")] - [EvilDocFunction( - "Converts all characters in the provided String to upper case and returns the result.", - Returns = "The upper-case version of the provided String.", - ReturnType = DynamicValueType.String - )] - [EvilDocArgument("str", "A String to be converted.", DynamicValueType.String)] - private static DynamicValue UpperCase(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectStringAt(0, out var str); + [RuntimeModuleFunction("ucase")] + [EvilDocFunction( + "Converts all characters in the provided String to upper case and returns the result.", + Returns = "The upper-case version of the provided String.", + ReturnType = DynamicValueType.String + )] + [EvilDocArgument("str", "A String to be converted.", DynamicValueType.String)] + private static DynamicValue UpperCase(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectStringAt(0, out var str); - return str.ToUpper(CultureInfo.InvariantCulture); - } + return str.ToUpper(CultureInfo.InvariantCulture); + } - [RuntimeModuleFunction("lcase")] - [EvilDocFunction( - "Converts all characters in the provided String to lower case and returns the result.", - Returns = "The lower-case version of the provided String.", - ReturnType = DynamicValueType.String - )] - [EvilDocArgument("str", "A String to be converted.", DynamicValueType.String)] - private static DynamicValue LowerCase(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectStringAt(0, out var source); + [RuntimeModuleFunction("lcase")] + [EvilDocFunction( + "Converts all characters in the provided String to lower case and returns the result.", + Returns = "The lower-case version of the provided String.", + ReturnType = DynamicValueType.String + )] + [EvilDocArgument("str", "A String to be converted.", DynamicValueType.String)] + private static DynamicValue LowerCase(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectStringAt(0, out var source); - return source.ToLower(CultureInfo.InvariantCulture); - } + return source.ToLower(CultureInfo.InvariantCulture); + } - [RuntimeModuleFunction("sub")] - [EvilDocFunction( - "Finds a portion of the provided String using a provided start index and optionally an end index.", - Returns = "A portion of the provided String using the provided indices, or `nil` on failure.", - ReturnType = DynamicValueType.String - )] - [EvilDocArgument("str", "A String to search for the substring in.", DynamicValueType.String)] - [EvilDocArgument("start_index", "Starting index of the substring within the provided String.", DynamicValueType.Number)] - [EvilDocArgument( - "end_index", - "Ending index of the substring within the provided String.", - DynamicValueType.Number, - DefaultValue = "-1" - )] - [EvilDocArgument( - "end_inclusive", - "Specifies whether the ending index is inclusive (i.e. the character at it should be included in the returned substring) or not.", - DynamicValueType.Boolean, - DefaultValue = "false" - )] - private static DynamicValue Substring(Fiber _, params DynamicValue[] args) + [RuntimeModuleFunction("sub")] + [EvilDocFunction( + "Finds a portion of the provided String using a provided start index and optionally an end index.", + Returns = "A portion of the provided String using the provided indices, or `nil` on failure.", + ReturnType = DynamicValueType.String + )] + [EvilDocArgument("str", "A String to search for the substring in.", DynamicValueType.String)] + [EvilDocArgument("start_index", "Starting index of the substring within the provided String.", DynamicValueType.Number)] + [EvilDocArgument( + "end_index", + "Ending index of the substring within the provided String.", + DynamicValueType.Number, + DefaultValue = "-1" + )] + [EvilDocArgument( + "end_inclusive", + "Specifies whether the ending index is inclusive (i.e. the character at it should be included in the returned substring) or not.", + DynamicValueType.Boolean, + DefaultValue = "false" + )] + private static DynamicValue Substring(Fiber _, params DynamicValue[] args) + { + args.ExpectAtLeast(2) + .ExpectAtMost(4) + .ExpectStringAt(0, out var str) + .ExpectIntegerAt(1, out var startIndex) + .OptionalIntegerAt(2, defaultValue: -1, out var endIndex) + .OptionalBooleanAt(3, defaultValue: false, out var endInclusive); + + if (endIndex >= 0) { - args.ExpectAtLeast(2) - .ExpectAtMost(4) - .ExpectStringAt(0, out var str) - .ExpectIntegerAt(1, out var startIndex) - .OptionalIntegerAt(2, defaultValue: -1, out var endIndex) - .OptionalBooleanAt(3, defaultValue: false, out var endInclusive); - - if (endIndex >= 0) + if (startIndex > endIndex) + return Nil; + + try { - if (startIndex > endIndex) - return Nil; + var end = (int)(endIndex - startIndex + 1); - try + if (!endInclusive) { - var end = (int)(endIndex - startIndex + 1); - - if (!endInclusive) - { - end--; - } - - if (end >= str.Length) - { - end = str.Length - (int)startIndex; - } - - return str.Substring( - (int)startIndex, - end - ); + end--; } - catch + + if (end >= str.Length) { - return Nil; + end = str.Length - (int)startIndex; } + + return str.Substring( + (int)startIndex, + end + ); } - else + catch { - try - { - return str.Substring((int)startIndex); - } - catch - { - return Nil; - } + return Nil; } } - - [RuntimeModuleFunction("starts_with")] - [EvilDocFunction( - "Checks if the provided String starts with the other provided String.", - Returns = "A Boolean value indicating whether the provided String starts with the other provided String.", - ReturnType = DynamicValueType.Boolean - )] - [EvilDocArgument("str", "A String to check.", DynamicValueType.String)] - [EvilDocArgument("start", "A String to be matched with the start of `str`.", DynamicValueType.String)] - private static DynamicValue StartsWith(Fiber _, params DynamicValue[] args) + else { - args.ExpectExactly(2) - .ExpectStringAt(0, out var str) - .ExpectStringAt(1, out var start); - - return str.StartsWith(start); + try + { + return str.Substring((int)startIndex); + } + catch + { + return Nil; + } } + } - [RuntimeModuleFunction("ends_with")] - [EvilDocFunction( - "Checks if the provided String ends with the other provided String.", - Returns = "A Boolean value indicating whether the provided String ends with the other provided String.", - ReturnType = DynamicValueType.Boolean - )] - [EvilDocArgument("str", "A String to check.", DynamicValueType.String)] - [EvilDocArgument("start", "A String to be matched with the end of `str`.", DynamicValueType.String)] - private static DynamicValue EndsWith(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(2) - .ExpectStringAt(0, out var str) - .ExpectStringAt(1, out var end); + [RuntimeModuleFunction("starts_with")] + [EvilDocFunction( + "Checks if the provided String starts with the other provided String.", + Returns = "A Boolean value indicating whether the provided String starts with the other provided String.", + ReturnType = DynamicValueType.Boolean + )] + [EvilDocArgument("str", "A String to check.", DynamicValueType.String)] + [EvilDocArgument("start", "A String to be matched with the start of `str`.", DynamicValueType.String)] + private static DynamicValue StartsWith(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(2) + .ExpectStringAt(0, out var str) + .ExpectStringAt(1, out var start); - return str.EndsWith(end); - } + return str.StartsWith(start); + } + + [RuntimeModuleFunction("ends_with")] + [EvilDocFunction( + "Checks if the provided String ends with the other provided String.", + Returns = "A Boolean value indicating whether the provided String ends with the other provided String.", + ReturnType = DynamicValueType.Boolean + )] + [EvilDocArgument("str", "A String to check.", DynamicValueType.String)] + [EvilDocArgument("start", "A String to be matched with the end of `str`.", DynamicValueType.String)] + private static DynamicValue EndsWith(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(2) + .ExpectStringAt(0, out var str) + .ExpectStringAt(1, out var end); + + return str.EndsWith(end); + } - [RuntimeModuleFunction("rmatch")] - [EvilDocFunction( - "Matches the provided String against a regular expression.", - Returns = "An Array containing matches for the provided regex, assuming any have been found, or `nil` on failure. \n" + - "" + - "If the returned Array is not empty, it will contain one or more tables structured as follows: \n" + - "```\n" + - "{\n" + - " success: Boolean\n" + - " name: String\n" + - " value: String\n" + - " starts_at: Number\n" + - " length: Number\n" + - " groups: Table\n" + - "}\n" + - "```\n" + - "" + - "If the match contains any groups, the `groups` Array will contain one or more tables structured as follows: \n" + - "```\n" + - "{\n" + - " success: Boolean\n" + - " name: String\n" + - " value: String\n" + - " starts_at: Number\n" + - " length: Number\n" + - "}\n" + - "```\n", - ReturnType = DynamicValueType.Array - )] - [EvilDocArgument("str", "A String to be matched.", DynamicValueType.String)] - [EvilDocArgument("regex", "A String containing the regular expression to match `str` against.", DynamicValueType.String)] - private static DynamicValue RegexMatch(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(2) - .ExpectStringAt(0, out var str) - .ExpectStringAt(1, out var regex); + [RuntimeModuleFunction("rmatch")] + [EvilDocFunction( + "Matches the provided String against a regular expression.", + Returns = "An Array containing matches for the provided regex, assuming any have been found, or `nil` on failure. \n" + + "" + + "If the returned Array is not empty, it will contain one or more tables structured as follows: \n" + + "```\n" + + "{\n" + + " success: Boolean\n" + + " name: String\n" + + " value: String\n" + + " starts_at: Number\n" + + " length: Number\n" + + " groups: Table\n" + + "}\n" + + "```\n" + + "" + + "If the match contains any groups, the `groups` Array will contain one or more tables structured as follows: \n" + + "```\n" + + "{\n" + + " success: Boolean\n" + + " name: String\n" + + " value: String\n" + + " starts_at: Number\n" + + " length: Number\n" + + "}\n" + + "```\n", + ReturnType = DynamicValueType.Array + )] + [EvilDocArgument("str", "A String to be matched.", DynamicValueType.String)] + [EvilDocArgument("regex", "A String containing the regular expression to match `str` against.", DynamicValueType.String)] + private static DynamicValue RegexMatch(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(2) + .ExpectStringAt(0, out var str) + .ExpectStringAt(1, out var regex); - if (!Regex.IsMatch(str, regex)) - return Nil; + if (!Regex.IsMatch(str, regex)) + return Nil; - var matches = Regex.Matches(str, regex); - var array = new Array(matches.Count); - for (var i = 0; i < matches.Count; i++) - { - var match = matches[i]; - var groups = new Table(); + var matches = Regex.Matches(str, regex); + var array = new Array(matches.Count); + for (var i = 0; i < matches.Count; i++) + { + var match = matches[i]; + var groups = new Table(); - var matchTable = new Table - { - { "success", match.Success }, - { "name", match.Name }, - { "value", match.Value }, - { "starts_at", match.Index }, - { "length", match.Length }, - { "groups", groups }, - { "group_count", match.Groups.Count } - }; + var matchTable = new Table + { + { "success", match.Success }, + { "name", match.Name }, + { "value", match.Value }, + { "starts_at", match.Index }, + { "length", match.Length }, + { "groups", groups }, + { "group_count", match.Groups.Count } + }; - for (var j = 0; j < match.Groups.Count; j++) - { - var group = match.Groups[j]; + for (var j = 0; j < match.Groups.Count; j++) + { + var group = match.Groups[j]; - var groupTable = new Table() - { - { "id", j }, - { "name", group.Name }, - { "value", group.Value }, - { "starts_at", group.Index }, - { "length", group.Length } - }.Freeze(true); - - groups[j] = groupTable; - groups[group.Name] = groupTable; - } - - matchTable.Freeze(true); - array[i] = matchTable; + var groupTable = new Table() + { + { "id", j }, + { "name", group.Name }, + { "value", group.Value }, + { "starts_at", group.Index }, + { "length", group.Length } + }.Freeze(true); + + groups[j] = groupTable; + groups[group.Name] = groupTable; } - return array; + matchTable.Freeze(true); + array[i] = matchTable; } - [RuntimeModuleFunction("md5")] - [EvilDocFunction( - "Calculates a checksum of the provided String, applying the provided encoding.", - Returns = "A String containing the computed checksum of the provided String.", - ReturnType = DynamicValueType.String - )] - [EvilDocArgument("text", "A String whose checksum to compute.", DynamicValueType.String)] - [EvilDocArgument( - "encoding", - "Name of the encoding to be used during computation.", - DynamicValueType.String, - DefaultValue = "utf-8" - )] - private static DynamicValue Md5(Fiber _, params DynamicValue[] args) - { - args.ExpectStringAt(0, out var text) - .OptionalStringAt(1, "utf-8", out var encoding); + return array; + } - var bytes = Encoding.GetEncoding(encoding).GetBytes(text); - var hash = MD5.HashData(bytes); + [RuntimeModuleFunction("md5")] + [EvilDocFunction( + "Calculates a checksum of the provided String, applying the provided encoding.", + Returns = "A String containing the computed checksum of the provided String.", + ReturnType = DynamicValueType.String + )] + [EvilDocArgument("text", "A String whose checksum to compute.", DynamicValueType.String)] + [EvilDocArgument( + "encoding", + "Name of the encoding to be used during computation.", + DynamicValueType.String, + DefaultValue = "utf-8" + )] + private static DynamicValue Md5(Fiber _, params DynamicValue[] args) + { + args.ExpectStringAt(0, out var text) + .OptionalStringAt(1, "utf-8", out var encoding); - var sb = new StringBuilder(); - for (var i = 0; i < hash.Length; i++) - { - sb.Append(hash[i].ToString("x2")); - } + var bytes = Encoding.GetEncoding(encoding).GetBytes(text); + var hash = MD5.HashData(bytes); - return sb.ToString(); + var sb = new StringBuilder(); + for (var i = 0; i < hash.Length; i++) + { + sb.Append(hash[i].ToString("x2")); } + + return sb.ToString(); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Modules/TableModule.cs b/VirtualMachine/EVIL.Ceres.Runtime/Modules/TableModule.cs index 5c2a9abe..a4531d54 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Modules/TableModule.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Modules/TableModule.cs @@ -1,238 +1,237 @@ -using EVIL.Ceres.ExecutionEngine.Collections; +namespace EVIL.Ceres.Runtime.Modules; + +using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.Concurrency; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.Ceres.Runtime.Extensions; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.Runtime.Modules +public class TableModule : RuntimeModule { - public class TableModule : RuntimeModule - { - public override string FullyQualifiedName => "tbl"; + public override string FullyQualifiedName => "tbl"; - [RuntimeModuleFunction("clear")] - [EvilDocFunction( - "Removes all values from the provided table." - )] - private static DynamicValue Clear(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectTableAt(0, out var table); + [RuntimeModuleFunction("clear")] + [EvilDocFunction( + "Removes all values from the provided table." + )] + private static DynamicValue Clear(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectTableAt(0, out var table); - table.Clear(); + table.Clear(); - return DynamicValue.Nil; - } + return DynamicValue.Nil; + } - [RuntimeModuleFunction("rawset")] - [EvilDocFunction( - "Sets the given Table's key to the provided value, ignoring any script-defined `__set` meta-table entries.", - Returns = "The value that has been set.", - IsAnyReturn = true - )] - [EvilDocArgument("table", "A Table whose key is to be set.", DynamicValueType.Table)] - [EvilDocArgument("key", "A key to use when setting the value.", CanBeNil = true)] - [EvilDocArgument("value", "A value to set the Table's key to.", CanBeNil = true)] - private static DynamicValue RawSet(Fiber _, params DynamicValue[] args) - { - args.ExpectTableAt(0, out var table) - .ExpectAnyAt(1, out var key) - .ExpectAnyAt(2, out var value); + [RuntimeModuleFunction("rawset")] + [EvilDocFunction( + "Sets the given Table's key to the provided value, ignoring any script-defined `__set` meta-table entries.", + Returns = "The value that has been set.", + IsAnyReturn = true + )] + [EvilDocArgument("table", "A Table whose key is to be set.", DynamicValueType.Table)] + [EvilDocArgument("key", "A key to use when setting the value.", CanBeNil = true)] + [EvilDocArgument("value", "A value to set the Table's key to.", CanBeNil = true)] + private static DynamicValue RawSet(Fiber _, params DynamicValue[] args) + { + args.ExpectTableAt(0, out var table) + .ExpectAnyAt(1, out var key) + .ExpectAnyAt(2, out var value); - table[key] = value; - return value; - } + table[key] = value; + return value; + } - [RuntimeModuleFunction("rawget")] - [EvilDocFunction( - "Gets the given Table's key to the provided value, ignoring any script-defined `__get` meta-table entries.", - Returns = "The value that resides in the provided Table under the given key.", - IsAnyReturn = true - )] - [EvilDocArgument("table", "A Table whose value to retrieve.", DynamicValueType.Table)] - [EvilDocArgument("key", "A key to use when retrieving the value.", CanBeNil = true)] - private static DynamicValue RawGet(Fiber _, params DynamicValue[] args) - { - args.ExpectTableAt(0, out var table) - .ExpectAnyAt(1, out var key); + [RuntimeModuleFunction("rawget")] + [EvilDocFunction( + "Gets the given Table's key to the provided value, ignoring any script-defined `__get` meta-table entries.", + Returns = "The value that resides in the provided Table under the given key.", + IsAnyReturn = true + )] + [EvilDocArgument("table", "A Table whose value to retrieve.", DynamicValueType.Table)] + [EvilDocArgument("key", "A key to use when retrieving the value.", CanBeNil = true)] + private static DynamicValue RawGet(Fiber _, params DynamicValue[] args) + { + args.ExpectTableAt(0, out var table) + .ExpectAnyAt(1, out var key); - return table[key]; - } + return table[key]; + } - [RuntimeModuleFunction("freeze")] - [EvilDocFunction( - "Freezes the provided Table so that no keys can be set or removed.", - Returns = "The frozen Table. This value is returned by reference.", - ReturnType = DynamicValueType.Table - )] - [EvilDocArgument("table", "A Table to be frozen.", DynamicValueType.Table)] - private static DynamicValue Freeze(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectTableAt(0, out var table); + [RuntimeModuleFunction("freeze")] + [EvilDocFunction( + "Freezes the provided Table so that no keys can be set or removed.", + Returns = "The frozen Table. This value is returned by reference.", + ReturnType = DynamicValueType.Table + )] + [EvilDocArgument("table", "A Table to be frozen.", DynamicValueType.Table)] + private static DynamicValue Freeze(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectTableAt(0, out var table); - table.Freeze(); + table.Freeze(); - return table; - } + return table; + } - [RuntimeModuleFunction("unfreeze")] - [EvilDocFunction( - "Unfreezes the provided Table so that keys can be set or removed.", - Returns = "The unfrozen Table. This value is returned by reference.", - ReturnType = DynamicValueType.Table - )] - [EvilDocArgument("table", "A Table to be unfrozen.", DynamicValueType.Table)] - private static DynamicValue Unfreeze(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectTableAt(0, out var table); + [RuntimeModuleFunction("unfreeze")] + [EvilDocFunction( + "Unfreezes the provided Table so that keys can be set or removed.", + Returns = "The unfrozen Table. This value is returned by reference.", + ReturnType = DynamicValueType.Table + )] + [EvilDocArgument("table", "A Table to be unfrozen.", DynamicValueType.Table)] + private static DynamicValue Unfreeze(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectTableAt(0, out var table); - table.Unfreeze(); + table.Unfreeze(); - return table; - } + return table; + } - [RuntimeModuleFunction("is_frozen")] - [EvilDocFunction( - "Checks if the given Table is frozen.", - Returns = "`true` if the provided Table is frozen, `false` otherwise.", - ReturnType = DynamicValueType.Boolean - )] - [EvilDocArgument("table", "A Table whose freeze status to check.", DynamicValueType.Table)] - private static DynamicValue /*IsFrozen is already a symbol...*/ _IsFrozen(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectTableAt(0, out var table); + [RuntimeModuleFunction("is_frozen")] + [EvilDocFunction( + "Checks if the given Table is frozen.", + Returns = "`true` if the provided Table is frozen, `false` otherwise.", + ReturnType = DynamicValueType.Boolean + )] + [EvilDocArgument("table", "A Table whose freeze status to check.", DynamicValueType.Table)] + private static DynamicValue /*IsFrozen is already a symbol...*/ _IsFrozen(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectTableAt(0, out var table); - return table.IsFrozen; - } + return table.IsFrozen; + } - [RuntimeModuleFunction("keys")] - [EvilDocFunction( - "Retrieves all keys present in the given Table.", - Returns = "An Array containing all keys in the provided Table, in no particular order.", - ReturnType = DynamicValueType.Array - )] - [EvilDocArgument("table", "A Table whose keys to retrieve.", DynamicValueType.Table)] - private static DynamicValue Keys(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectTableAt(0, out var table); + [RuntimeModuleFunction("keys")] + [EvilDocFunction( + "Retrieves all keys present in the given Table.", + Returns = "An Array containing all keys in the provided Table, in no particular order.", + ReturnType = DynamicValueType.Array + )] + [EvilDocArgument("table", "A Table whose keys to retrieve.", DynamicValueType.Table)] + private static DynamicValue Keys(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectTableAt(0, out var table); - return table.GetKeys(); - } + return table.GetKeys(); + } - [RuntimeModuleFunction("values")] - [EvilDocFunction( - "Retrieves all values present in the given Table.", - Returns = "An Array containing all values in the provided Table, in no particular order.", - ReturnType = DynamicValueType.Array - )] - [EvilDocArgument("table", "A Table whose keys to retrieve.", DynamicValueType.Table)] - private static DynamicValue Values(Fiber _, params DynamicValue[] args) - { - args.ExpectExactly(1) - .ExpectTableAt(0, out var table); + [RuntimeModuleFunction("values")] + [EvilDocFunction( + "Retrieves all values present in the given Table.", + Returns = "An Array containing all values in the provided Table, in no particular order.", + ReturnType = DynamicValueType.Array + )] + [EvilDocArgument("table", "A Table whose keys to retrieve.", DynamicValueType.Table)] + private static DynamicValue Values(Fiber _, params DynamicValue[] args) + { + args.ExpectExactly(1) + .ExpectTableAt(0, out var table); - return table.GetValues(); - } + return table.GetValues(); + } - [RuntimeModuleFunction("cpy")] - [EvilDocFunction( - "Copies the given Table, returning a new instance.", - Returns = "A new Table containing the values from the original one.", - ReturnType = DynamicValueType.Table - )] - [EvilDocArgument("table", "A Table to be copied.", DynamicValueType.Table)] - [EvilDocArgument( - "deep", - "Whether the copy should be deep (nested Tables are also completely copied) " + - "or shallow (nested Table references are copied).", - DynamicValueType.Boolean, - DefaultValue = "false" - )] - private static DynamicValue Copy(Fiber _, params DynamicValue[] args) - { - args.ExpectTableAt(0, out var table) - .OptionalBooleanAt(1, false, out var deep); + [RuntimeModuleFunction("cpy")] + [EvilDocFunction( + "Copies the given Table, returning a new instance.", + Returns = "A new Table containing the values from the original one.", + ReturnType = DynamicValueType.Table + )] + [EvilDocArgument("table", "A Table to be copied.", DynamicValueType.Table)] + [EvilDocArgument( + "deep", + "Whether the copy should be deep (nested Tables are also completely copied) " + + "or shallow (nested Table references are copied).", + DynamicValueType.Boolean, + DefaultValue = "false" + )] + private static DynamicValue Copy(Fiber _, params DynamicValue[] args) + { + args.ExpectTableAt(0, out var table) + .OptionalBooleanAt(1, false, out var deep); - return deep - ? table.DeepCopy() - : table.ShallowCopy(); - } + return deep + ? table.DeepCopy() + : table.ShallowCopy(); + } - [RuntimeModuleFunction("invert")] - [EvilDocFunction( - "Copies a Table in a way that its values become its keys and vice-versa.", - Returns = "A shallow copy of the provided Table with its values and keys swapped.", - ReturnType = DynamicValueType.Table - )] - [EvilDocArgument("tbl", "A Table to be inverted.", DynamicValueType.Table)] - private static DynamicValue Invert(Fiber _, params DynamicValue[] args) - { - args.ExpectTableAt(0, out var tbl); + [RuntimeModuleFunction("invert")] + [EvilDocFunction( + "Copies a Table in a way that its values become its keys and vice-versa.", + Returns = "A shallow copy of the provided Table with its values and keys swapped.", + ReturnType = DynamicValueType.Table + )] + [EvilDocArgument("tbl", "A Table to be inverted.", DynamicValueType.Table)] + private static DynamicValue Invert(Fiber _, params DynamicValue[] args) + { + args.ExpectTableAt(0, out var tbl); - var newTable = new Table(); + var newTable = new Table(); - foreach (var (key, value) in tbl) - { - newTable[value] = key; - } - - return newTable; + foreach (var (key, value) in tbl) + { + newTable[value] = key; } + + return newTable; + } - [RuntimeModuleFunction("set_mt")] - [EvilDocFunction("Sets a meta-table for the provided Table.", ReturnType = DynamicValueType.Nil)] - [EvilDocArgument("table", "A Table whose meta-table to modify.", DynamicValueType.Table, CanBeNil = false)] - [EvilDocArgument("mt", "A Table whose meta-table to modify.", DynamicValueType.Table, CanBeNil = false)] - private static DynamicValue SetMetaTable(Fiber fiber, params DynamicValue[] args) - { - args.ExpectTableAt(0, out var table) - .ExpectTableAt(1, out var mt); + [RuntimeModuleFunction("set_mt")] + [EvilDocFunction("Sets a meta-table for the provided Table.", ReturnType = DynamicValueType.Nil)] + [EvilDocArgument("table", "A Table whose meta-table to modify.", DynamicValueType.Table, CanBeNil = false)] + [EvilDocArgument("mt", "A Table whose meta-table to modify.", DynamicValueType.Table, CanBeNil = false)] + private static DynamicValue SetMetaTable(Fiber fiber, params DynamicValue[] args) + { + args.ExpectTableAt(0, out var table) + .ExpectTableAt(1, out var mt); - if (table.MetaTable != null) + if (table.MetaTable != null) + { + if (table.MetaTable["__metatable"] != DynamicValue.Nil) { - if (table.MetaTable["__metatable"] != DynamicValue.Nil) - { - return fiber.ThrowFromNative("Unable to set a protected metatable."); - } + return fiber.ThrowFromNative("Unable to set a protected metatable."); } - - table.MetaTable = mt; - return table; } + + table.MetaTable = mt; + return table; + } - [RuntimeModuleFunction("get_mt")] - [EvilDocFunction( - "Gets a meta-table for the provided Table.", - Returns = "A Table acting as the current meta-table for the provided Table, or Nil if it wasn't set.", - ReturnType = DynamicValueType.Table - )] - [EvilDocArgument( - "table", - "A table whose meta-table to retrieve.", - DynamicValueType.Table, - CanBeNil = false - )] - private static DynamicValue GetMetaTable(Fiber _, params DynamicValue[] args) + [RuntimeModuleFunction("get_mt")] + [EvilDocFunction( + "Gets a meta-table for the provided Table.", + Returns = "A Table acting as the current meta-table for the provided Table, or Nil if it wasn't set.", + ReturnType = DynamicValueType.Table + )] + [EvilDocArgument( + "table", + "A table whose meta-table to retrieve.", + DynamicValueType.Table, + CanBeNil = false + )] + private static DynamicValue GetMetaTable(Fiber _, params DynamicValue[] args) + { + args.ExpectTableAt(0, out var table); + + if (table.MetaTable != null) { - args.ExpectTableAt(0, out var table); + var metaField = table.MetaTable["__metatable"]; - if (table.MetaTable != null) + if (metaField != DynamicValue.Nil) { - var metaField = table.MetaTable["__metatable"]; - - if (metaField != DynamicValue.Nil) - { - return metaField; - } - - return table.MetaTable; + return metaField; } - - return DynamicValue.Nil; + + return table.MetaTable; } + + return DynamicValue.Nil; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/Modules/TimeModule.cs b/VirtualMachine/EVIL.Ceres.Runtime/Modules/TimeModule.cs index 3e39a06b..c5f3921a 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/Modules/TimeModule.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/Modules/TimeModule.cs @@ -1,99 +1,98 @@ -using System; +namespace EVIL.Ceres.Runtime.Modules; + +using System; using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.Ceres.Runtime.Extensions; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.Runtime.Modules +public sealed class TimeModule : RuntimeModule { - public sealed class TimeModule : RuntimeModule - { - public override string FullyQualifiedName => "time"; + public override string FullyQualifiedName => "time"; - [RuntimeModuleGetter("now")] - [EvilDocProperty( - EvilDocPropertyMode.Get, - "Retrieves the current date and time as a Table containing specific details. \n\n" + - "The returned Table will use the following layout: \n" + - "```\n" + - "{\n" + - " day: Number\n" + - " month: Number\n" + - " year: Number\n" + - " hour: Number\n" + - " minute: Number\n" + - " second: Number\n" + - " millisecond: Number\n" + - " microsecond: Number\n" + - " nanosecond: Number\n" + - " ticks: Number\n" + - " day_of_year: Number\n" + - " day_of_week: Number\n" + - " day_of_week_name: String\n" + - " as_stamp_ms: Function\n" + - " as_stamp_secs: Function\n" + - "}\n" + - "```\n" + - "`as_stamp_ms` and `as_stamp_secs` functions work analogously to `stamp.ms` and `stamp.secs`.", - ReturnType = DynamicValueType.Table - )] - private static DynamicValue GetNow(DynamicValue key) - => CreateDateTimeTable(DateTime.Now); + [RuntimeModuleGetter("now")] + [EvilDocProperty( + EvilDocPropertyMode.Get, + "Retrieves the current date and time as a Table containing specific details. \n\n" + + "The returned Table will use the following layout: \n" + + "```\n" + + "{\n" + + " day: Number\n" + + " month: Number\n" + + " year: Number\n" + + " hour: Number\n" + + " minute: Number\n" + + " second: Number\n" + + " millisecond: Number\n" + + " microsecond: Number\n" + + " nanosecond: Number\n" + + " ticks: Number\n" + + " day_of_year: Number\n" + + " day_of_week: Number\n" + + " day_of_week_name: String\n" + + " as_stamp_ms: Function\n" + + " as_stamp_secs: Function\n" + + "}\n" + + "```\n" + + "`as_stamp_ms` and `as_stamp_secs` functions work analogously to `stamp.ms` and `stamp.secs`.", + ReturnType = DynamicValueType.Table + )] + private static DynamicValue GetNow(DynamicValue key) + => CreateDateTimeTable(DateTime.Now); - [RuntimeModuleGetter("stamp.ms")] - [EvilDocProperty( - EvilDocPropertyMode.Get, - "Retrieves the current time as a Unix timestamp in milliseconds.", - ReturnType = DynamicValueType.Number - )] - private static DynamicValue GetStampMillis(DynamicValue key) - => DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + [RuntimeModuleGetter("stamp.ms")] + [EvilDocProperty( + EvilDocPropertyMode.Get, + "Retrieves the current time as a Unix timestamp in milliseconds.", + ReturnType = DynamicValueType.Number + )] + private static DynamicValue GetStampMillis(DynamicValue key) + => DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - [RuntimeModuleGetter("stamp.secs")] - [EvilDocProperty( - EvilDocPropertyMode.Get, - "Retrieves the current time as a Unix timestamp in seconds.", - ReturnType = DynamicValueType.Number - )] - private static DynamicValue GetStampSeconds(DynamicValue key) - => DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + [RuntimeModuleGetter("stamp.secs")] + [EvilDocProperty( + EvilDocPropertyMode.Get, + "Retrieves the current time as a Unix timestamp in seconds.", + ReturnType = DynamicValueType.Number + )] + private static DynamicValue GetStampSeconds(DynamicValue key) + => DateTimeOffset.UtcNow.ToUnixTimeSeconds(); - private static Table CreateDateTimeTable(DateTime dt) + private static Table CreateDateTimeTable(DateTime dt) + { + var ret = new Table { - var ret = new Table + { "day", dt.Day }, + { "month", dt.Month }, + { "year", dt.Year }, + { "hour", dt.Hour }, + { "minute", dt.Minute }, + { "second", dt.Second }, + { "millisecond", dt.Millisecond }, + { "microsecond", dt.Microsecond }, + { "nanosecond", dt.Nanosecond }, + { "ticks", dt.Ticks }, + { "day_of_year", dt.DayOfYear }, + { "day_of_week", (int)dt.DayOfWeek }, + { "day_of_week_name", dt.DayOfWeek.ToString() }, { - { "day", dt.Day }, - { "month", dt.Month }, - { "year", dt.Year }, - { "hour", dt.Hour }, - { "minute", dt.Minute }, - { "second", dt.Second }, - { "millisecond", dt.Millisecond }, - { "microsecond", dt.Microsecond }, - { "nanosecond", dt.Nanosecond }, - { "ticks", dt.Ticks }, - { "day_of_year", dt.DayOfYear }, - { "day_of_week", (int)dt.DayOfWeek }, - { "day_of_week_name", dt.DayOfWeek.ToString() }, + "as_stamp_ms", + new((_, args) => { - "as_stamp_ms", - new((_, args) => - { - args.ExpectNone(); - return new DateTimeOffset(dt).ToUnixTimeMilliseconds(); - }) - }, + args.ExpectNone(); + return new DateTimeOffset(dt).ToUnixTimeMilliseconds(); + }) + }, + { + "as_stamp_secs", + new((_, args) => { - "as_stamp_secs", - new((_, args) => - { - args.ExpectNone(); - return new DateTimeOffset(dt).ToUnixTimeSeconds(); - }) - } - }; + args.ExpectNone(); + return new DateTimeOffset(dt).ToUnixTimeSeconds(); + }) + } + }; - return ret; - } + return ret; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/RuntimeModule.DocExtensions.cs b/VirtualMachine/EVIL.Ceres.Runtime/RuntimeModule.DocExtensions.cs index bc5bc78e..9651cb09 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/RuntimeModule.DocExtensions.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/RuntimeModule.DocExtensions.cs @@ -1,331 +1,330 @@ +namespace EVIL.Ceres.Runtime; + using System.Linq; using System.Reflection; using System.Text; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.Runtime +public static class RuntimeModuleDocExtensions { - public static class RuntimeModuleDocExtensions + public static string? DescribeProperty(this RuntimeModule module, MethodInfo methodInfo, bool blockQuote = true) { - public static string? DescribeProperty(this RuntimeModule module, MethodInfo methodInfo, bool blockQuote = true) - { - var sb = new StringBuilder(); + var sb = new StringBuilder(); - var runtimeModuleGetterAttribute = methodInfo.GetCustomAttribute(); - var evilDocPropertyAttribute = methodInfo.GetCustomAttribute(); + var runtimeModuleGetterAttribute = methodInfo.GetCustomAttribute(); + var evilDocPropertyAttribute = methodInfo.GetCustomAttribute(); - if (runtimeModuleGetterAttribute == null) - return null; + if (runtimeModuleGetterAttribute == null) + return null; - sb.AppendLine($"## {module.FullyQualifiedName}.{runtimeModuleGetterAttribute.SubNameSpace}"); + sb.AppendLine($"## {module.FullyQualifiedName}.{runtimeModuleGetterAttribute.SubNameSpace}"); - if (evilDocPropertyAttribute != null) - { - sb.AppendLine("**Synopsis** "); - sb.AppendLine($"**`{module.FullyQualifiedName}.{runtimeModuleGetterAttribute.SubNameSpace}`** "); + if (evilDocPropertyAttribute != null) + { + sb.AppendLine("**Synopsis** "); + sb.AppendLine($"**`{module.FullyQualifiedName}.{runtimeModuleGetterAttribute.SubNameSpace}`** "); - if (evilDocPropertyAttribute.Mode.HasFlag(EvilDocPropertyMode.Get)) + if (evilDocPropertyAttribute.Mode.HasFlag(EvilDocPropertyMode.Get)) + { + sb.Append($"**` :: get"); + if (evilDocPropertyAttribute.IsAnyGet) { - sb.Append($"**` :: get"); - if (evilDocPropertyAttribute.IsAnyGet) - { - sb.AppendLine($" -> Any`**\n "); - } - else - { - sb.AppendLine($" -> {GetTypeString(evilDocPropertyAttribute.ReturnType)}`**\n "); - } + sb.AppendLine($" -> Any`**\n "); } + else + { + sb.AppendLine($" -> {GetTypeString(evilDocPropertyAttribute.ReturnType)}`**\n "); + } + } - if (evilDocPropertyAttribute.Mode.HasFlag(EvilDocPropertyMode.Set)) + if (evilDocPropertyAttribute.Mode.HasFlag(EvilDocPropertyMode.Set)) + { + sb.Append($"**` ::set"); + if (evilDocPropertyAttribute.IsAnySet) { - sb.Append($"**` ::set"); - if (evilDocPropertyAttribute.IsAnySet) - { - sb.AppendLine($" <- Any`**\n "); - } - else + sb.AppendLine($" <- Any`**\n "); + } + else + { + if (evilDocPropertyAttribute.InputTypes.Any()) { - if (evilDocPropertyAttribute.InputTypes.Any()) + if (evilDocPropertyAttribute.InputTypes.Length > 1) { - if (evilDocPropertyAttribute.InputTypes.Length > 1) - { - sb.AppendLine( - $" <- ({string.Join(',', evilDocPropertyAttribute.InputTypes.Select(GetTypeString))})`**\n "); - } - else - { - sb.AppendLine($" <- {GetTypeString(evilDocPropertyAttribute.InputTypes[0])}`**\n "); - } + sb.AppendLine( + $" <- ({string.Join(',', evilDocPropertyAttribute.InputTypes.Select(GetTypeString))})`**\n "); + } + else + { + sb.AppendLine($" <- {GetTypeString(evilDocPropertyAttribute.InputTypes[0])}`**\n "); } } } - - sb.AppendLine("**Description** "); - sb.AppendLine(evilDocPropertyAttribute.Description); - sb.AppendLine(); - } - else - { - sb.AppendLine("This property has no available documentation."); } - if (!blockQuote) + sb.AppendLine("**Description** "); + sb.AppendLine(evilDocPropertyAttribute.Description); + sb.AppendLine(); + } + else + { + sb.AppendLine("This property has no available documentation."); + } + + if (!blockQuote) + { + return sb.ToString(); + } + else + { + var lines = sb.ToString() + .Split('\n') + .Select(x => x.Trim('\r')) + .ToList(); + + for (var i = 0; i < lines.Count; i++) { - return sb.ToString(); + lines[i] = $"> {lines[i]}"; } - else - { - var lines = sb.ToString() - .Split('\n') - .Select(x => x.Trim('\r')) - .ToList(); - - for (var i = 0; i < lines.Count; i++) - { - lines[i] = $"> {lines[i]}"; - } - lines.Add(""); - return string.Join('\n', lines); - } + lines.Add(""); + return string.Join('\n', lines); } + } - public static string? DescribeFunction(this RuntimeModule module, MethodInfo methodInfo, bool blockQuote = true) - { - var sb = new StringBuilder(); + public static string? DescribeFunction(this RuntimeModule module, MethodInfo methodInfo, bool blockQuote = true) + { + var sb = new StringBuilder(); - var runtimeModuleFunctionAttribute = methodInfo.GetCustomAttribute(); - var evilDocFunctionAttribute = methodInfo.GetCustomAttribute(); - var evilDocArgumentAttributes = methodInfo.GetCustomAttributes().ToArray(); - var evilDocThrowsAttributes = methodInfo.GetCustomAttributes().ToArray(); + var runtimeModuleFunctionAttribute = methodInfo.GetCustomAttribute(); + var evilDocFunctionAttribute = methodInfo.GetCustomAttribute(); + var evilDocArgumentAttributes = methodInfo.GetCustomAttributes().ToArray(); + var evilDocThrowsAttributes = methodInfo.GetCustomAttributes().ToArray(); - if (runtimeModuleFunctionAttribute == null) - return null; + if (runtimeModuleFunctionAttribute == null) + return null; - sb.AppendLine($"## {module.FullyQualifiedName}.{runtimeModuleFunctionAttribute.SubNameSpace}"); + sb.AppendLine($"## {module.FullyQualifiedName}.{runtimeModuleFunctionAttribute.SubNameSpace}"); - if (evilDocFunctionAttribute != null) + if (evilDocFunctionAttribute != null) + { + sb.AppendLine("**Synopsis** "); + sb.Append($"`{module.FullyQualifiedName}.{runtimeModuleFunctionAttribute.SubNameSpace}"); + sb.Append("("); { - sb.AppendLine("**Synopsis** "); - sb.Append($"`{module.FullyQualifiedName}.{runtimeModuleFunctionAttribute.SubNameSpace}"); - sb.Append("("); + for (var i = 0; i < evilDocArgumentAttributes.Length; i++) { - for (var i = 0; i < evilDocArgumentAttributes.Length; i++) + var argInfo = evilDocArgumentAttributes[i]; + + if (argInfo.Name == "...") { - var argInfo = evilDocArgumentAttributes[i]; + continue; + } - if (argInfo.Name == "...") - { - continue; - } + var argName = argInfo.Name; + if (argInfo.CanBeNil) + { + argName += "?"; + } - var argName = argInfo.Name; - if (argInfo.CanBeNil) + if (argInfo.DefaultValue != null) + { + var defaultValue = argInfo.DefaultValue; + if (argInfo.PrimaryType == DynamicValueType.String) { - argName += "?"; + defaultValue = $"\"{defaultValue}\""; } - if (argInfo.DefaultValue != null) - { - var defaultValue = argInfo.DefaultValue; - if (argInfo.PrimaryType == DynamicValueType.String) - { - defaultValue = $"\"{defaultValue}\""; - } - - sb.Append($"[{argName}] = {defaultValue}"); - } - else - { - sb.Append(argName); - } + sb.Append($"[{argName}] = {defaultValue}"); + } + else + { + sb.Append(argName); + } - if (i < evilDocArgumentAttributes.Length - 1 || evilDocFunctionAttribute.IsVariadic) - { - sb.Append(", "); - } + if (i < evilDocArgumentAttributes.Length - 1 || evilDocFunctionAttribute.IsVariadic) + { + sb.Append(", "); } } + } - if (evilDocFunctionAttribute.IsVariadic) - { - sb.Append("..."); - } + if (evilDocFunctionAttribute.IsVariadic) + { + sb.Append("..."); + } - sb.Append($") "); + sb.Append($") "); - if (evilDocFunctionAttribute.IsAnyReturn) - { - sb.AppendLine($" -> Any`\n "); - } - else - { - sb.AppendLine($" -> {GetTypeString(evilDocFunctionAttribute.ReturnType)}`\n "); - } + if (evilDocFunctionAttribute.IsAnyReturn) + { + sb.AppendLine($" -> Any`\n "); + } + else + { + sb.AppendLine($" -> {GetTypeString(evilDocFunctionAttribute.ReturnType)}`\n "); + } - sb.AppendLine("**Description** "); - sb.AppendLine(evilDocFunctionAttribute.Description); + sb.AppendLine("**Description** "); + sb.AppendLine(evilDocFunctionAttribute.Description); - if (!string.IsNullOrEmpty(evilDocFunctionAttribute.Returns)) - { - sb.AppendLine(); - sb.AppendLine("**Returns** "); - sb.AppendLine(evilDocFunctionAttribute.Returns); - } + if (!string.IsNullOrEmpty(evilDocFunctionAttribute.Returns)) + { + sb.AppendLine(); + sb.AppendLine("**Returns** "); + sb.AppendLine(evilDocFunctionAttribute.Returns); + } - if (evilDocArgumentAttributes.Any()) + if (evilDocArgumentAttributes.Any()) + { + sb.AppendLine(); + sb.AppendLine("**Arguments** "); + sb.AppendLine("| Name | Description | Type(s) | Can be `nil` | Optional | Default Value | "); + sb.AppendLine("| ---- | ----------- | ------- | ------------ | -------- | ------------- | "); + for (var i = 0; i < evilDocArgumentAttributes.Length; i++) { - sb.AppendLine(); - sb.AppendLine("**Arguments** "); - sb.AppendLine("| Name | Description | Type(s) | Can be `nil` | Optional | Default Value | "); - sb.AppendLine("| ---- | ----------- | ------- | ------------ | -------- | ------------- | "); - for (var i = 0; i < evilDocArgumentAttributes.Length; i++) - { - var argInfo = evilDocArgumentAttributes[i]; - var argType = argInfo.IsAnyType ? "Any" : GetTypeString(argInfo.PrimaryType); + var argInfo = evilDocArgumentAttributes[i]; + var argType = argInfo.IsAnyType ? "Any" : GetTypeString(argInfo.PrimaryType); - if (!argInfo.IsAnyType && argInfo.OtherTypes != null) + if (!argInfo.IsAnyType && argInfo.OtherTypes != null) + { + foreach (var otherType in argInfo.OtherTypes) { - foreach (var otherType in argInfo.OtherTypes) - { - argType += $", {GetTypeString(otherType)}"; - } + argType += $", {GetTypeString(otherType)}"; } + } - var defaultValue = "None"; + var defaultValue = "None"; - if (argInfo.DefaultValue != null) + if (argInfo.DefaultValue != null) + { + if (argInfo.PrimaryType == DynamicValueType.String) + { + defaultValue = $"`\"{argInfo.DefaultValue}\"`"; + } + else { - if (argInfo.PrimaryType == DynamicValueType.String) - { - defaultValue = $"`\"{argInfo.DefaultValue}\"`"; - } - else - { - defaultValue = $"`{argInfo.DefaultValue}`"; - } + defaultValue = $"`{argInfo.DefaultValue}`"; } + } - var optional = argInfo.DefaultValue == null ? "No" : "Yes"; - var canBeNil = argInfo.CanBeNil ? "Yes" : "No"; + var optional = argInfo.DefaultValue == null ? "No" : "Yes"; + var canBeNil = argInfo.CanBeNil ? "Yes" : "No"; - sb.AppendLine($"| `{argInfo.Name}` | {argInfo.Description} | `{argType}` | {canBeNil} | {optional} | {defaultValue} | "); - } + sb.AppendLine($"| `{argInfo.Name}` | {argInfo.Description} | `{argType}` | {canBeNil} | {optional} | {defaultValue} | "); } + } - if (evilDocThrowsAttributes.Any()) + if (evilDocThrowsAttributes.Any()) + { + sb.AppendLine(); + sb.AppendLine("**Thrown objects** "); + foreach (var attr in evilDocThrowsAttributes) { sb.AppendLine(); - sb.AppendLine("**Thrown objects** "); - foreach (var attr in evilDocThrowsAttributes) - { - sb.AppendLine(); - sb.AppendLine($"> **{attr.ThrownType.ToString()}** "); - sb.AppendLine($"> {attr.Description}"); - } + sb.AppendLine($"> **{attr.ThrownType.ToString()}** "); + sb.AppendLine($"> {attr.Description}"); } } - else - { - sb.AppendLine("This function has no available documentation."); - } + } + else + { + sb.AppendLine("This function has no available documentation."); + } + + if (!blockQuote) + { + return sb.ToString(); + } + else + { + var lines = sb.ToString() + .Split('\n') + .Select(x => x.Trim('\r')) + .ToList(); - if (!blockQuote) + for (var i = 0; i < lines.Count; i++) { - return sb.ToString(); + lines[i] = $"> {lines[i]}"; } - else - { - var lines = sb.ToString() - .Split('\n') - .Select(x => x.Trim('\r')) - .ToList(); - - for (var i = 0; i < lines.Count; i++) - { - lines[i] = $"> {lines[i]}"; - } - lines.Add(""); - return string.Join('\n', lines); - } + lines.Add(""); + return string.Join('\n', lines); } + } - public static string DescribeProperties(this RuntimeModule module) - { - var functions = module.GetType().GetMethods( - BindingFlags.Static - | BindingFlags.NonPublic - | BindingFlags.Public - ); + public static string DescribeProperties(this RuntimeModule module) + { + var functions = module.GetType().GetMethods( + BindingFlags.Static + | BindingFlags.NonPublic + | BindingFlags.Public + ); - var sb = new StringBuilder(); + var sb = new StringBuilder(); - foreach (var function in functions) + foreach (var function in functions) + { + var docString = module.DescribeProperty(function); + if (docString != null) { - var docString = module.DescribeProperty(function); - if (docString != null) - { - sb.AppendLine(docString); - } + sb.AppendLine(docString); } - - return sb.ToString(); } + + return sb.ToString(); + } - public static string DescribeFunctions(this RuntimeModule module) - { - var functions = module.GetType().GetMethods( - BindingFlags.Static - | BindingFlags.NonPublic - | BindingFlags.Public - ); + public static string DescribeFunctions(this RuntimeModule module) + { + var functions = module.GetType().GetMethods( + BindingFlags.Static + | BindingFlags.NonPublic + | BindingFlags.Public + ); - var sb = new StringBuilder(); + var sb = new StringBuilder(); - foreach (var function in functions) + foreach (var function in functions) + { + var docString = module.DescribeFunction(function); + if (docString != null) { - var docString = module.DescribeFunction(function); - if (docString != null) - { - sb.AppendLine(docString); - } + sb.AppendLine(docString); } - - return sb.ToString(); } - public static string Describe(this RuntimeModule module) - { - var sb = new StringBuilder(); + return sb.ToString(); + } - var propertyDescriptionString = module.DescribeProperties(); - var functionDescriptionString = module.DescribeFunctions(); - - sb.AppendLine($"# EVIL Runtime Module `{module.FullyQualifiedName}`"); + public static string Describe(this RuntimeModule module) + { + var sb = new StringBuilder(); - if (!string.IsNullOrEmpty(propertyDescriptionString)) - { - sb.AppendLine($"## Properties"); - sb.AppendLine(propertyDescriptionString); - sb.AppendLine(); - } + var propertyDescriptionString = module.DescribeProperties(); + var functionDescriptionString = module.DescribeFunctions(); + + sb.AppendLine($"# EVIL Runtime Module `{module.FullyQualifiedName}`"); - if (!string.IsNullOrEmpty(functionDescriptionString)) - { - sb.AppendLine($"## Functions"); - sb.AppendLine(functionDescriptionString); - sb.AppendLine(); - } + if (!string.IsNullOrEmpty(propertyDescriptionString)) + { + sb.AppendLine($"## Properties"); + sb.AppendLine(propertyDescriptionString); + sb.AppendLine(); + } - return sb.ToString(); + if (!string.IsNullOrEmpty(functionDescriptionString)) + { + sb.AppendLine($"## Functions"); + sb.AppendLine(functionDescriptionString); + sb.AppendLine(); } - - private static string GetTypeString(DynamicValueType type) - => new DynamicValue(type).ConvertToString().String!; + return sb.ToString(); } + + private static string GetTypeString(DynamicValueType type) + => new DynamicValue(type).ConvertToString().String!; + } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/RuntimeModule.cs b/VirtualMachine/EVIL.Ceres.Runtime/RuntimeModule.cs index 83ced37b..3248b6fe 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/RuntimeModule.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/RuntimeModule.cs @@ -1,4 +1,6 @@ -using System; +namespace EVIL.Ceres.Runtime; + +using System; using System.Linq; using System.Reflection; using EVIL.Ceres.ExecutionEngine.Collections; @@ -7,236 +9,233 @@ using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.Ceres.Runtime.Extensions; -namespace EVIL.Ceres.Runtime +public abstract class RuntimeModule : PropertyTable { - public abstract class RuntimeModule : PropertyTable - { - public const string GlobalMergeKey = ""; + public const string GlobalMergeKey = ""; - public abstract string FullyQualifiedName { get; } - - public RuntimeModule() - { - RegisterNativeFunctions(); - RegisterNativeSetters(); - RegisterNativeGetters(); - } + public abstract string FullyQualifiedName { get; } - public DynamicValue AttachTo(Table table) - { - var ret = this; + public RuntimeModule() + { + RegisterNativeFunctions(); + RegisterNativeSetters(); + RegisterNativeGetters(); + } - if (FullyQualifiedName == GlobalMergeKey) - { - foreach (var (k, v) in this) table[k] = v; - } - else - { - table.SetUsingPath( - FullyQualifiedName, - ret - ); - } + public DynamicValue AttachTo(Table table) + { + var ret = this; - return ret; + if (FullyQualifiedName == GlobalMergeKey) + { + foreach (var (k, v) in this) table[k] = v; } - - internal void Registered(EvilRuntime runtime) - => OnRegistered(runtime); - - protected virtual void OnRegistered(EvilRuntime runtime) + else { + table.SetUsingPath
( + FullyQualifiedName, + ret + ); } - private void RegisterNativeFunctions() - { - var validFunctions = GetType().GetMethods( - BindingFlags.Public - | BindingFlags.NonPublic - | BindingFlags.Static - ).Where(HasSupportedFunctionSignature) - .Where(HasRequiredFunctionAttribute) - .Select(x => - { - var nativeFunction = x.CreateDelegate(null); - var attribute = x.GetCustomAttribute()!; + return ret; + } - return (Function: nativeFunction, Attribute: attribute); - }); + internal void Registered(EvilRuntime runtime) + => OnRegistered(runtime); + + protected virtual void OnRegistered(EvilRuntime runtime) + { + } - foreach (var tuple in validFunctions) + private void RegisterNativeFunctions() + { + var validFunctions = GetType().GetMethods( + BindingFlags.Public + | BindingFlags.NonPublic + | BindingFlags.Static + ).Where(HasSupportedFunctionSignature) + .Where(HasRequiredFunctionAttribute) + .Select(x => { - if (this.ContainsPath(tuple.Attribute.SubNameSpace)) - { - throw new InvalidOperationException( - $"Attempt to register a duplicate member (native function) with name '{tuple.Attribute.SubNameSpace}' " + - $"in '{FullyQualifiedName}'." - ); - } + var nativeFunction = x.CreateDelegate(null); + var attribute = x.GetCustomAttribute()!; + + return (Function: nativeFunction, Attribute: attribute); + }); - this.SetUsingPath( - tuple.Attribute.SubNameSpace, - new(tuple.Function) + foreach (var tuple in validFunctions) + { + if (this.ContainsPath(tuple.Attribute.SubNameSpace)) + { + throw new InvalidOperationException( + $"Attempt to register a duplicate member (native function) with name '{tuple.Attribute.SubNameSpace}' " + + $"in '{FullyQualifiedName}'." ); } + + this.SetUsingPath( + tuple.Attribute.SubNameSpace, + new(tuple.Function) + ); } + } - private bool HasRequiredFunctionAttribute(MethodInfo method) - => method.GetCustomAttribute() != null; + private bool HasRequiredFunctionAttribute(MethodInfo method) + => method.GetCustomAttribute() != null; - private bool HasSupportedFunctionSignature(MethodInfo method) - { - var parameters = method.GetParameters(); + private bool HasSupportedFunctionSignature(MethodInfo method) + { + var parameters = method.GetParameters(); - return parameters.Length == 2 - && parameters[0].ParameterType.IsAssignableTo(typeof(Fiber)) - && parameters[1].ParameterType.IsAssignableTo(typeof(DynamicValue[])) - && method.ReturnType.IsAssignableTo(typeof(DynamicValue)); - } + return parameters.Length == 2 + && parameters[0].ParameterType.IsAssignableTo(typeof(Fiber)) + && parameters[1].ParameterType.IsAssignableTo(typeof(DynamicValue[])) + && method.ReturnType.IsAssignableTo(typeof(DynamicValue)); + } - private void RegisterNativeGetters() - { - var validGetters = GetType().GetMethods( - BindingFlags.Public - | BindingFlags.NonPublic - | BindingFlags.Static - ).Where(HasSupportedGetterSignature) - .Where(HasRequiredGetterAttribute) - .Select(x => - { - var getter = x.CreateDelegate(null); - var attribute = x.GetCustomAttribute()!; + private void RegisterNativeGetters() + { + var validGetters = GetType().GetMethods( + BindingFlags.Public + | BindingFlags.NonPublic + | BindingFlags.Static + ).Where(HasSupportedGetterSignature) + .Where(HasRequiredGetterAttribute) + .Select(x => + { + var getter = x.CreateDelegate(null); + var attribute = x.GetCustomAttribute()!; - return (Getter: getter, Attribute: attribute); - }); + return (Getter: getter, Attribute: attribute); + }); - foreach (var tuple in validGetters) + foreach (var tuple in validGetters) + { + if (this.ContainsValuePath(tuple.Attribute.SubNameSpace) || + this.ContainsGetterPath(tuple.Attribute.SubNameSpace)) { - if (this.ContainsValuePath(tuple.Attribute.SubNameSpace) || - this.ContainsGetterPath(tuple.Attribute.SubNameSpace)) - { - throw new InvalidOperationException( - $"Attempt to register a duplicate member (getter) with name '{tuple.Attribute.SubNameSpace}' " + - $"in '{FullyQualifiedName}'." - ); - } + throw new InvalidOperationException( + $"Attempt to register a duplicate member (getter) with name '{tuple.Attribute.SubNameSpace}' " + + $"in '{FullyQualifiedName}'." + ); + } - if (string.IsNullOrEmpty(tuple.Attribute.SubNameSpace)) - continue; + if (string.IsNullOrEmpty(tuple.Attribute.SubNameSpace)) + continue; - var subNameSpaceParts = tuple.Attribute.SubNameSpace.Split('.'); - var targetName = subNameSpaceParts[subNameSpaceParts.Length - 1]; + var subNameSpaceParts = tuple.Attribute.SubNameSpace.Split('.'); + var targetName = subNameSpaceParts[subNameSpaceParts.Length - 1]; - if (subNameSpaceParts.Length >= 2) - { - var subNameSpace = string.Join('.', subNameSpaceParts[0..^1]); - - var dynval = IndexUsingFullyQualifiedName(subNameSpace); + if (subNameSpaceParts.Length >= 2) + { + var subNameSpace = string.Join('.', subNameSpaceParts[0..^1]); - PropertyTable propTable; + var dynval = IndexUsingFullyQualifiedName(subNameSpace); - if (dynval == DynamicValue.Nil) - { - propTable = new PropertyTable(); - } - else - { - propTable = (PropertyTable)dynval.Table!; - } + PropertyTable propTable; - propTable.AddGetter(targetName, tuple.Getter); - this.SetUsingPath(subNameSpace, propTable); + if (dynval == DynamicValue.Nil) + { + propTable = new PropertyTable(); } else { - AddGetter(targetName, tuple.Getter); + propTable = (PropertyTable)dynval.Table!; } + + propTable.AddGetter(targetName, tuple.Getter); + this.SetUsingPath(subNameSpace, propTable); + } + else + { + AddGetter(targetName, tuple.Getter); } } + } - private bool HasRequiredGetterAttribute(MethodInfo method) - => method.GetCustomAttribute() != null; + private bool HasRequiredGetterAttribute(MethodInfo method) + => method.GetCustomAttribute() != null; - private bool HasSupportedGetterSignature(MethodInfo method) - { - var parameters = method.GetParameters(); + private bool HasSupportedGetterSignature(MethodInfo method) + { + var parameters = method.GetParameters(); - return parameters.Length == 1 - && parameters[0].ParameterType.IsAssignableTo(typeof(DynamicValue)) - && method.ReturnType.IsAssignableTo(typeof(DynamicValue)); - } + return parameters.Length == 1 + && parameters[0].ParameterType.IsAssignableTo(typeof(DynamicValue)) + && method.ReturnType.IsAssignableTo(typeof(DynamicValue)); + } - private void RegisterNativeSetters() - { - var validSetters = GetType().GetMethods( - BindingFlags.Public - | BindingFlags.NonPublic - | BindingFlags.Static - ).Where(HasSupportedSetterSignature) - .Where(HasRequiredSetterAttribute) - .Select(x => - { - var setter = x.CreateDelegate(null); - var attribute = x.GetCustomAttribute()!; + private void RegisterNativeSetters() + { + var validSetters = GetType().GetMethods( + BindingFlags.Public + | BindingFlags.NonPublic + | BindingFlags.Static + ).Where(HasSupportedSetterSignature) + .Where(HasRequiredSetterAttribute) + .Select(x => + { + var setter = x.CreateDelegate(null); + var attribute = x.GetCustomAttribute()!; - return (Setter: setter, Attribute: attribute); - }); + return (Setter: setter, Attribute: attribute); + }); - foreach (var tuple in validSetters) + foreach (var tuple in validSetters) + { + if (this.ContainsValuePath(tuple.Attribute.SubNameSpace) || + this.ContainsSetterPath(tuple.Attribute.SubNameSpace)) { - if (this.ContainsValuePath(tuple.Attribute.SubNameSpace) || - this.ContainsSetterPath(tuple.Attribute.SubNameSpace)) - { - throw new InvalidOperationException( - $"Attempt to register a duplicate member (setter) with name '{tuple.Attribute.SubNameSpace}' " + - $"in '{FullyQualifiedName}'." - ); - } + throw new InvalidOperationException( + $"Attempt to register a duplicate member (setter) with name '{tuple.Attribute.SubNameSpace}' " + + $"in '{FullyQualifiedName}'." + ); + } - if (string.IsNullOrEmpty(tuple.Attribute.SubNameSpace)) - continue; + if (string.IsNullOrEmpty(tuple.Attribute.SubNameSpace)) + continue; - var subNameSpaceParts = tuple.Attribute.SubNameSpace.Split('.'); - var targetName = subNameSpaceParts[subNameSpaceParts.Length - 1]; + var subNameSpaceParts = tuple.Attribute.SubNameSpace.Split('.'); + var targetName = subNameSpaceParts[subNameSpaceParts.Length - 1]; - if (subNameSpaceParts.Length >= 2) - { - var subNameSpace = string.Join('.', subNameSpaceParts[0..^1]); - - var dynval = IndexUsingFullyQualifiedName(subNameSpace); + if (subNameSpaceParts.Length >= 2) + { + var subNameSpace = string.Join('.', subNameSpaceParts[0..^1]); - PropertyTable propTable; + var dynval = IndexUsingFullyQualifiedName(subNameSpace); - if (dynval == DynamicValue.Nil) - { - propTable = new PropertyTable(); - } - else - { - propTable = (PropertyTable)dynval.Table!; - } + PropertyTable propTable; - propTable.AddSetter(targetName, tuple.Setter); - this.SetUsingPath(subNameSpace, propTable); + if (dynval == DynamicValue.Nil) + { + propTable = new PropertyTable(); } else { - AddSetter(targetName, tuple.Setter); + propTable = (PropertyTable)dynval.Table!; } + + propTable.AddSetter(targetName, tuple.Setter); + this.SetUsingPath(subNameSpace, propTable); + } + else + { + AddSetter(targetName, tuple.Setter); } } + } - private bool HasRequiredSetterAttribute(MethodInfo method) - => method.GetCustomAttribute() != null; + private bool HasRequiredSetterAttribute(MethodInfo method) + => method.GetCustomAttribute() != null; - private bool HasSupportedSetterSignature(MethodInfo method) - { - var parameters = method.GetParameters(); + private bool HasSupportedSetterSignature(MethodInfo method) + { + var parameters = method.GetParameters(); - return parameters.Length == 2 - && parameters[0].ParameterType.IsAssignableTo(typeof(DynamicValue)) - && parameters[1].ParameterType.IsAssignableTo(typeof(DynamicValue)) - && method.ReturnType.IsAssignableTo(typeof((DynamicValue, DynamicValue))); - } + return parameters.Length == 2 + && parameters[0].ParameterType.IsAssignableTo(typeof(DynamicValue)) + && parameters[1].ParameterType.IsAssignableTo(typeof(DynamicValue)) + && method.ReturnType.IsAssignableTo(typeof((DynamicValue, DynamicValue))); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/RuntimeModuleFunctionAttribute.cs b/VirtualMachine/EVIL.Ceres.Runtime/RuntimeModuleFunctionAttribute.cs index c212711c..1052df9f 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/RuntimeModuleFunctionAttribute.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/RuntimeModuleFunctionAttribute.cs @@ -1,15 +1,14 @@ -using System; +namespace EVIL.Ceres.Runtime; -namespace EVIL.Ceres.Runtime +using System; + +[AttributeUsage(AttributeTargets.Method)] +public class RuntimeModuleFunctionAttribute : Attribute { - [AttributeUsage(AttributeTargets.Method)] - public class RuntimeModuleFunctionAttribute : Attribute - { - public string SubNameSpace { get; } + public string SubNameSpace { get; } - public RuntimeModuleFunctionAttribute(string subNameSpace) - { - SubNameSpace = subNameSpace; - } + public RuntimeModuleFunctionAttribute(string subNameSpace) + { + SubNameSpace = subNameSpace; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/RuntimeModuleGetterAttribute.cs b/VirtualMachine/EVIL.Ceres.Runtime/RuntimeModuleGetterAttribute.cs index c50be26f..73967c98 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/RuntimeModuleGetterAttribute.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/RuntimeModuleGetterAttribute.cs @@ -1,15 +1,14 @@ -using System; +namespace EVIL.Ceres.Runtime; -namespace EVIL.Ceres.Runtime +using System; + +[AttributeUsage(AttributeTargets.Method)] +public class RuntimeModuleGetterAttribute : Attribute { - [AttributeUsage(AttributeTargets.Method)] - public class RuntimeModuleGetterAttribute : Attribute - { - public string SubNameSpace { get; } + public string SubNameSpace { get; } - public RuntimeModuleGetterAttribute(string subNameSpace) - { - SubNameSpace = subNameSpace; - } + public RuntimeModuleGetterAttribute(string subNameSpace) + { + SubNameSpace = subNameSpace; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/RuntimeModuleSetterAttribute.cs b/VirtualMachine/EVIL.Ceres.Runtime/RuntimeModuleSetterAttribute.cs index d6fa1f38..ac637dcd 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/RuntimeModuleSetterAttribute.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/RuntimeModuleSetterAttribute.cs @@ -1,15 +1,14 @@ -using System; +namespace EVIL.Ceres.Runtime; -namespace EVIL.Ceres.Runtime +using System; + +[AttributeUsage(AttributeTargets.Method)] +public class RuntimeModuleSetterAttribute : Attribute { - [AttributeUsage(AttributeTargets.Method)] - public class RuntimeModuleSetterAttribute : Attribute - { - public string SubNameSpace { get; } + public string SubNameSpace { get; } - public RuntimeModuleSetterAttribute(string subNameSpace) - { - SubNameSpace = subNameSpace; - } + public RuntimeModuleSetterAttribute(string subNameSpace) + { + SubNameSpace = subNameSpace; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres.Runtime/UserFailException.cs b/VirtualMachine/EVIL.Ceres.Runtime/UserFailException.cs index dc5822a7..96a7ff62 100644 --- a/VirtualMachine/EVIL.Ceres.Runtime/UserFailException.cs +++ b/VirtualMachine/EVIL.Ceres.Runtime/UserFailException.cs @@ -1,18 +1,17 @@ +namespace EVIL.Ceres.Runtime; + using EVIL.Ceres.ExecutionEngine.Concurrency; using EVIL.Ceres.ExecutionEngine.TypeSystem; -namespace EVIL.Ceres.Runtime +public class UserFailException : EvilRuntimeException { - public class UserFailException : EvilRuntimeException - { - public Fiber Fiber { get; } - public DynamicValue[] Arguments { get; } + public Fiber Fiber { get; } + public DynamicValue[] Arguments { get; } - public UserFailException(string message, Fiber fiber, DynamicValue[] arguments) - : base(message) - { - Fiber = fiber; - Arguments = arguments; - } + public UserFailException(string message, Fiber fiber, DynamicValue[] arguments) + : base(message) + { + Fiber = fiber; + Arguments = arguments; } -} \ No newline at end of file +}b \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/ArrayException.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/ArrayException.cs index c45791d6..e52fa379 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/ArrayException.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/ArrayException.cs @@ -1,16 +1,15 @@ +namespace EVIL.Ceres.ExecutionEngine; + using System; -namespace EVIL.Ceres.ExecutionEngine +public class ArrayException : RecoverableVirtualMachineException { - public class ArrayException : RecoverableVirtualMachineException + internal ArrayException(string message, Exception innerException) + : base(message, innerException) { - internal ArrayException(string message, Exception innerException) - : base(message, innerException) - { - } + } - internal ArrayException(string message) : base(message) - { - } + internal ArrayException(string message) : base(message) + { } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/CeresVM.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/CeresVM.cs index 4a8b3beb..f84bf85d 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/CeresVM.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/CeresVM.cs @@ -1,76 +1,75 @@ +namespace EVIL.Ceres.ExecutionEngine; + using System; using System.Threading.Tasks; using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.Concurrency; using EVIL.Ceres.ExecutionEngine.Diagnostics.Debugging; -namespace EVIL.Ceres.ExecutionEngine +public class CeresVM : IDisposable { - public class CeresVM : IDisposable - { - private Task? _schedulerTask; + private Task? _schedulerTask; - public Table Global { get; } - public FiberScheduler Scheduler { get; } - public Fiber MainFiber { get; } + public Table Global { get; } + public FiberScheduler Scheduler { get; } + public Fiber MainFiber { get; } - public CeresVM(FiberCrashHandler? crashHandler = null) - : this(new Table(), crashHandler) - { - } + public CeresVM(FiberCrashHandler? crashHandler = null) + : this(new Table(), crashHandler) + { + } - public CeresVM(Table global, FiberCrashHandler? crashHandler = null) - { - Global = global; - Scheduler = new FiberScheduler(this, crashHandler ?? DefaultCrashHandler); - MainFiber = Scheduler.CreateFiber(true); - } + public CeresVM(Table global, FiberCrashHandler? crashHandler = null) + { + Global = global; + Scheduler = new FiberScheduler(this, crashHandler ?? DefaultCrashHandler); + MainFiber = Scheduler.CreateFiber(true); + } - public void Start() + public void Start() + { + if (_schedulerTask != null) { - if (_schedulerTask != null) + if (_schedulerTask.Status == TaskStatus.Running) { - if (_schedulerTask.Status == TaskStatus.Running) - { - return; - } + return; } + } - _schedulerTask?.Dispose(); - _schedulerTask = new Task(Scheduler.Run); + _schedulerTask?.Dispose(); + _schedulerTask = new Task(Scheduler.Run); - _schedulerTask.Start(); - } + _schedulerTask.Start(); + } - public void Stop() + public void Stop() + { + if (_schedulerTask == null) { - if (_schedulerTask == null) - { - return; - } - - if (_schedulerTask.Status != TaskStatus.Running) - { - return; - } - - Scheduler.Stop(); + return; } - - public void Dispose() - { - if (_schedulerTask != null && _schedulerTask.Status == TaskStatus.Running) - { - Stop(); - } - _schedulerTask?.Wait(); - _schedulerTask?.Dispose(); + if (_schedulerTask.Status != TaskStatus.Running) + { + return; } - private void DefaultCrashHandler(Fiber fiber, Exception exception) + Scheduler.Stop(); + } + + public void Dispose() + { + if (_schedulerTask != null && _schedulerTask.Status == TaskStatus.Running) { - throw new VirtualMachineException("A fiber has crashed.", exception); + Stop(); } + + _schedulerTask?.Wait(); + _schedulerTask?.Dispose(); + } + + private void DefaultCrashHandler(Fiber fiber, Exception exception) + { + throw new VirtualMachineException("A fiber has crashed.", exception); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/ChunkDeserializationException.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/ChunkDeserializationException.cs index 913bdf75..1599f912 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/ChunkDeserializationException.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/ChunkDeserializationException.cs @@ -1,10 +1,9 @@ -namespace EVIL.Ceres.ExecutionEngine +namespace EVIL.Ceres.ExecutionEngine; + +public class ChunkDeserializationException : VirtualMachineException { - public class ChunkDeserializationException : VirtualMachineException + internal ChunkDeserializationException(string message) + : base(message) { - internal ChunkDeserializationException(string message) - : base(message) - { - } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Array.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Array.cs index 3ffebdf4..0d7472ea 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Array.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Array.cs @@ -1,235 +1,234 @@ +namespace EVIL.Ceres.ExecutionEngine.Collections; + +using static EVIL.Ceres.ExecutionEngine.TypeSystem.DynamicValue; + using System.Collections; using System.Collections.Generic; +using EVIL.Ceres.ExecutionEngine.Marshaling; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.CommonTypes.TypeSystem; -using static EVIL.Ceres.ExecutionEngine.TypeSystem.DynamicValue; -namespace EVIL.Ceres.ExecutionEngine.Collections +public class Array : IDynamicValueCollection, IIndexableObject, IWriteableObject { - using EVIL.Ceres.ExecutionEngine.Marshaling; - - public class Array : IDynamicValueCollection, IIndexableObject, IWriteableObject - { - private DynamicValue[] _values; + private DynamicValue[] _values; - public int Length => _values.Length; + public int Length => _values.Length; - public DynamicValue this[int index] + public DynamicValue this[int index] + { + get { - get + if (index < 0 || index >= _values.Length) { - if (index < 0 || index >= _values.Length) - { - throw new ArrayException($"Index {index} was out of bounds for this array."); - } - - return _values[index]; + throw new ArrayException($"Index {index} was out of bounds for this array."); } - set - { - if (index < 0 || index >= _values.Length) - { - throw new ArrayException($"Index {index} was out of bounds for this array."); - } - - _values[index] = value; - } + return _values[index]; } - public DynamicValue this[DynamicValue index] + set { - get + if (index < 0 || index >= _values.Length) { - if (index.Type != DynamicValueType.Number) - { - throw new ArrayException($"Attempt to index an Array using a {index.Type}."); - } - - return this[(int)index.Number]; + throw new ArrayException($"Index {index} was out of bounds for this array."); } - set - { - if (index.Type != DynamicValueType.Number) - { - throw new ArrayException($"Attempt to index an Array using a {index.Type}."); - } - this[(int)index.Number] = value; - } + _values[index] = value; } - - public Array(Array array) + } + + public DynamicValue this[DynamicValue index] + { + get { - _values = new DynamicValue[array.Length]; - - for (var i = 0; i < array.Length; i++) + if (index.Type != DynamicValueType.Number) { - _values[i] = array[i]; + throw new ArrayException($"Attempt to index an Array using a {index.Type}."); } + + return this[(int)index.Number]; } - - public Array(int size) + set { - if (size < 0) + if (index.Type != DynamicValueType.Number) { - throw new ArrayException($"Attempt to initialize an Array using a negative size ({size})."); + throw new ArrayException($"Attempt to index an Array using a {index.Type}."); } + + this[(int)index.Number] = value; + } + } + + public Array(Array array) + { + _values = new DynamicValue[array.Length]; - _values = new DynamicValue[size]; - System.Array.Fill(_values, Nil); + for (var i = 0; i < array.Length; i++) + { + _values[i] = array[i]; } + } - public int IndexOf(DynamicValue value) - => System.Array.IndexOf(_values, value); - - public void Fill(DynamicValue value) + public Array(int size) + { + if (size < 0) { - for (var i = 0; i < _values.Length; i++) - { - _values[i] = value; - } + throw new ArrayException($"Attempt to initialize an Array using a negative size ({size})."); } + + _values = new DynamicValue[size]; + System.Array.Fill(_values, Nil); + } - public int Resize(int size) + public int IndexOf(DynamicValue value) + => System.Array.IndexOf(_values, value); + + public void Fill(DynamicValue value) + { + for (var i = 0; i < _values.Length; i++) { - if (size < 0) - { - return -1; - } + _values[i] = value; + } + } - System.Array.Resize(ref _values, size); - return _values.Length; + public int Resize(int size) + { + if (size < 0) + { + return -1; } + + System.Array.Resize(ref _values, size); + return _values.Length; + } - public int Push(params DynamicValue[] values) - { - if (values.Length == 0) - return _values.Length; + public int Push(params DynamicValue[] values) + { + if (values.Length == 0) + return _values.Length; - System.Array.Resize( - ref _values, - _values.Length + values.Length - ); + System.Array.Resize( + ref _values, + _values.Length + values.Length + ); - for (var i = 0; i < values.Length; i++) - { - _values[_values.Length - values.Length + i] = values[i]; - } - - return _values.Length; + for (var i = 0; i < values.Length; i++) + { + _values[_values.Length - values.Length + i] = values[i]; } - public int Insert(int index, params DynamicValue[] values) - { - if (index < 0) - return -1; + return _values.Length; + } - if (index > _values.Length) - return -1; + public int Insert(int index, params DynamicValue[] values) + { + if (index < 0) + return -1; - if (values.Length == 0) - return _values.Length; - - System.Array.Resize( - ref _values, - _values.Length + values.Length - ); + if (index > _values.Length) + return -1; - var start = _values.Length - values.Length - 1; + if (values.Length == 0) + return _values.Length; - for (var i = start; i >= index; i--) - { - _values[_values.Length - values.Length + i] = _values[i]; - } - - for (var i = 0; i < values.Length; i++) - { - _values[index + i] = values[i]; - } + System.Array.Resize( + ref _values, + _values.Length + values.Length + ); - return _values.Length; + var start = _values.Length - values.Length - 1; + + for (var i = start; i >= index; i--) + { + _values[_values.Length - values.Length + i] = _values[i]; } - public DynamicValue RightShift() + for (var i = 0; i < values.Length; i++) { - if (_values.Length <= 0) - return Nil; + _values[index + i] = values[i]; + } - var ret = _values[_values.Length - 1]; - System.Array.Resize(ref _values, _values.Length - 1); + return _values.Length; + } - return ret; - } + public DynamicValue RightShift() + { + if (_values.Length <= 0) + return Nil; + + var ret = _values[_values.Length - 1]; + System.Array.Resize(ref _values, _values.Length - 1); + + return ret; + } - public DynamicValue LeftShift() - { - if (_values.Length <= 0) - return Nil; + public DynamicValue LeftShift() + { + if (_values.Length <= 0) + return Nil; - var ret = _values[0]; + var ret = _values[0]; - for (var i = 1; i < _values.Length; i++) - { - _values[i - 1] = _values[i]; - } + for (var i = 1; i < _values.Length; i++) + { + _values[i - 1] = _values[i]; + } - System.Array.Resize(ref _values, _values.Length - 1); + System.Array.Resize(ref _values, _values.Length - 1); - return ret; - } + return ret; + } - public bool IsDeeplyEqualTo(Array other) - { - if (Length != other.Length) - return false; + public bool IsDeeplyEqualTo(Array other) + { + if (Length != other.Length) + return false; - lock (_values) + lock (_values) + { + for (var i = 0; i < Length; i++) { - for (var i = 0; i < Length; i++) + if (this[i].Type == DynamicValueType.Table || this[i].Type == DynamicValueType.Array) { - if (this[i].Type == DynamicValueType.Table || this[i].Type == DynamicValueType.Array) + if (!IsTruth(this[i].IsDeeplyEqualTo(other[i]))) { - if (!IsTruth(this[i].IsDeeplyEqualTo(other[i]))) - { - return false; - } + return false; } - else + } + else + { + if (!IsTruth(this[i].IsEqualTo(other[i]))) { - if (!IsTruth(this[i].IsEqualTo(other[i]))) - { - return false; - } + return false; } } } - - return true; } + + return true; + } - public static Array FromString(string s) - { - var a = new Array(s.Length); + public static Array FromString(string s) + { + var a = new Array(s.Length); - for (var i = 0; i < s.Length; i++) - { - a[i] = s[i].ToString(); - } - - return a; + for (var i = 0; i < s.Length; i++) + { + a[i] = s[i].ToString(); } - public IEnumerator> GetEnumerator() - => new ArrayEnumerator(this); + return a; + } - IEnumerator IEnumerable.GetEnumerator() - => GetEnumerator(); + public IEnumerator> GetEnumerator() + => new ArrayEnumerator(this); - public DynamicValue Index(DynamicValue key) - => this[key]; + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); - public void Set(DynamicValue key, DynamicValue value) - => this[key] = value; - } + public DynamicValue Index(DynamicValue key) + => this[key]; + + public void Set(DynamicValue key, DynamicValue value) + => this[key] = value; } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/ArrayEnumerator.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/ArrayEnumerator.cs index 1d4b74c9..57fa0c65 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/ArrayEnumerator.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/ArrayEnumerator.cs @@ -1,72 +1,71 @@ +namespace EVIL.Ceres.ExecutionEngine.Collections; + using System; using System.Collections; using System.Collections.Generic; using EVIL.Ceres.ExecutionEngine.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine.Collections +internal sealed class ArrayEnumerator : IEnumerator>, ICloneable { - internal sealed class ArrayEnumerator : IEnumerator>, ICloneable - { - private readonly Array _array; - private int _index; + private readonly Array _array; + private int _index; - object IEnumerator.Current => Current; + object IEnumerator.Current => Current; - public KeyValuePair Current + public KeyValuePair Current + { + get { - get - { - var index = _index; - var array = _array; + var index = _index; + var array = _array; - if (index >= array.Length) + if (index >= array.Length) + { + if (index < 0) { - if (index < 0) - { - throw new InvalidOperationException("Enumeration has not started yet."); - } - else - { - throw new InvalidOperationException("Enumeration has already finished."); - } + throw new InvalidOperationException("Enumeration has not started yet."); + } + else + { + throw new InvalidOperationException("Enumeration has already finished."); } - - return new(index, array[index]); } - } - internal ArrayEnumerator(Array array) - { - _array = array; - _index = -1; + return new(index, array[index]); } + } - public object Clone() - { - return MemberwiseClone(); - } + internal ArrayEnumerator(Array array) + { + _array = array; + _index = -1; + } - public bool MoveNext() - { - var index = _index + 1; - - if (index >= _array.Length) - { - _index = _array.Length; - return false; - } - - _index = index; - return true; - } + public object Clone() + { + return MemberwiseClone(); + } - public void Reset() + public bool MoveNext() + { + var index = _index + 1; + + if (index >= _array.Length) { - _index = -1; + _index = _array.Length; + return false; } + + _index = index; + return true; + } - public void Dispose() - { - } + public void Reset() + { + _index = -1; + } + + public void Dispose() + { } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/IDynamicValueCollection.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/IDynamicValueCollection.cs index 254247b2..2c5def00 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/IDynamicValueCollection.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/IDynamicValueCollection.cs @@ -1,10 +1,9 @@ +namespace EVIL.Ceres.ExecutionEngine.Collections; + using System.Collections.Generic; using EVIL.Ceres.ExecutionEngine.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine.Collections +public interface IDynamicValueCollection : IEnumerable> { - public interface IDynamicValueCollection : IEnumerable> - { - DynamicValue this[DynamicValue index] { get; set; } - } + DynamicValue this[DynamicValue index] { get; set; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Marshaling/IIndexableObject.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/IIndexableObject.cs similarity index 76% rename from VirtualMachine/EVIL.Ceres/ExecutionEngine/Marshaling/IIndexableObject.cs rename to VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/IIndexableObject.cs index df344088..9abb4556 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Marshaling/IIndexableObject.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/IIndexableObject.cs @@ -1,4 +1,4 @@ -namespace EVIL.Ceres.ExecutionEngine.Marshaling; +namespace EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.TypeSystem; diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Marshaling/IWriteableObject.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/IWriteableObject.cs similarity index 77% rename from VirtualMachine/EVIL.Ceres/ExecutionEngine/Marshaling/IWriteableObject.cs rename to VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/IWriteableObject.cs index 1bb6012c..7e229481 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Marshaling/IWriteableObject.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/IWriteableObject.cs @@ -1,4 +1,4 @@ -namespace EVIL.Ceres.ExecutionEngine.Marshaling; +namespace EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.TypeSystem; diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/PropertyTable.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/PropertyTable.cs index 98f71ae5..5f22c9ba 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/PropertyTable.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/PropertyTable.cs @@ -1,102 +1,101 @@ -using System; +namespace EVIL.Ceres.ExecutionEngine.Collections; + +using System; using System.Collections.Generic; using EVIL.Ceres.ExecutionEngine.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine.Collections +public class PropertyTable : Table { - public class PropertyTable : Table - { - public delegate DynamicValue TableGetter(DynamicValue key); + public delegate DynamicValue TableGetter(DynamicValue key); + + public delegate (DynamicValue Key, DynamicValue Value) TableSetter(DynamicValue key, DynamicValue value); - public delegate (DynamicValue Key, DynamicValue Value) TableSetter(DynamicValue key, DynamicValue value); + private readonly Dictionary _getters = new(); + private readonly Dictionary _setters = new(); - private readonly Dictionary _getters = new(); - private readonly Dictionary _setters = new(); + public PropertyTable() + { + } - public PropertyTable() + public PropertyTable(PropertyTable collection) + : base(collection) + { + foreach (var (key, value) in collection._getters) { + _getters[key] = value; } - public PropertyTable(PropertyTable collection) - : base(collection) + foreach (var (key, value) in collection._setters) { - foreach (var (key, value) in collection._getters) - { - _getters[key] = value; - } - - foreach (var (key, value) in collection._setters) - { - _setters[key] = value; - } + _setters[key] = value; } + } - public void Add(DynamicValue key, TableSetter setter) - => AddSetter(key, setter); + public void Add(DynamicValue key, TableSetter setter) + => AddSetter(key, setter); - public void Add(DynamicValue key, TableGetter getter) - => AddGetter(key, getter); + public void Add(DynamicValue key, TableGetter getter) + => AddGetter(key, getter); - public virtual void AddGetter(DynamicValue key, TableGetter getter) + public virtual void AddGetter(DynamicValue key, TableGetter getter) + { + if (!_getters.TryAdd(key, getter)) { - if (!_getters.TryAdd(key, getter)) - { - throw new InvalidOperationException( - $"Attempt to register a duplicate getter for '{key.ToString()}'" - ); - } + throw new InvalidOperationException( + $"Attempt to register a duplicate getter for '{key.ToString()}'" + ); } + } - public virtual bool RemoveGetter(DynamicValue key) - => _getters.Remove(key); + public virtual bool RemoveGetter(DynamicValue key) + => _getters.Remove(key); - public virtual void AddSetter(DynamicValue key, TableSetter setter) + public virtual void AddSetter(DynamicValue key, TableSetter setter) + { + if (!_setters.TryAdd(key, setter)) { - if (!_setters.TryAdd(key, setter)) - { - throw new InvalidOperationException( - $"Attempt to register a duplicate setter for '{key.ToString()}'" - ); - } + throw new InvalidOperationException( + $"Attempt to register a duplicate setter for '{key.ToString()}'" + ); } + } - public virtual bool RemoveSetter(DynamicValue key) - => _setters.Remove(key); + public virtual bool RemoveSetter(DynamicValue key) + => _setters.Remove(key); - protected override DynamicValue OnIndex(DynamicValue key) + protected override DynamicValue OnIndex(DynamicValue key) + { + if (_getters.TryGetValue(key, out var getter)) { - if (_getters.TryGetValue(key, out var getter)) - { - return getter(key); - } - - return base.OnIndex(key); + return getter(key); } - protected override (DynamicValue Key, DynamicValue Value) OnBeforeSet(DynamicValue key, DynamicValue value) - { - if (_setters.TryGetValue(key, out var setter)) - { - return setter(key, value); - } + return base.OnIndex(key); + } - return base.OnBeforeSet(key, value); + protected override (DynamicValue Key, DynamicValue Value) OnBeforeSet(DynamicValue key, DynamicValue value) + { + if (_setters.TryGetValue(key, out var setter)) + { + return setter(key, value); } - public virtual bool ContainsGetter(DynamicValue key) - => _getters.ContainsKey(key); + return base.OnBeforeSet(key, value); + } + + public virtual bool ContainsGetter(DynamicValue key) + => _getters.ContainsKey(key); - public virtual bool ContainsSetter(DynamicValue key) - => _setters.ContainsKey(key); + public virtual bool ContainsSetter(DynamicValue key) + => _setters.ContainsKey(key); - public virtual bool ContainsValue(DynamicValue key) - => base.OnContains(key); + public virtual bool ContainsValue(DynamicValue key) + => base.OnContains(key); - protected override bool OnContains(DynamicValue key) - { - return ContainsGetter(key) - || ContainsSetter(key) - || ContainsValue(key); - } + protected override bool OnContains(DynamicValue key) + { + return ContainsGetter(key) + || ContainsSetter(key) + || ContainsValue(key); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Serialization/ArraySerializer.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Serialization/ArraySerializer.cs index f488890f..1e48eef2 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Serialization/ArraySerializer.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Serialization/ArraySerializer.cs @@ -1,68 +1,69 @@ +namespace EVIL.Ceres.ExecutionEngine.Collections.Serialization; + +using Array = EVIL.Ceres.ExecutionEngine.Collections.Array; + using System; using System.IO; using System.Text; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine.Collections.Serialization +internal static class ArraySerializer { - internal static class ArraySerializer + public static void Serialize(Array array, Stream stream) { - public static void Serialize(Array array, Stream stream) + using (var bw = new BinaryWriter(stream, Encoding.UTF8, true)) { - using (var bw = new BinaryWriter(stream, Encoding.UTF8, true)) + bw.Write(new[] { (byte)'E', (byte)'V', (byte)'A' }); + bw.Write(array.Length); + + for (var i = 0; i < array.Length; i++) { - bw.Write(new[] { (byte)'E', (byte)'V', (byte)'A' }); - bw.Write(array.Length); + var value = array[i]; - for (var i = 0; i < array.Length; i++) + if (value.Type == DynamicValueType.Array && ReferenceEquals(value.Array!, array)) { - var value = array[i]; - - if (value.Type == DynamicValueType.Array && ReferenceEquals(value.Array!, array)) - { - throw new SerializationException("Circular reference in serialized array."); - } - - array[i].Serialize(stream); + throw new SerializationException("Circular reference in serialized array."); } + + array[i].Serialize(stream); } } + } - public static Array Deserialize(Stream stream) + public static Array Deserialize(Stream stream) + { + var offset = stream.Position; + + using (var br = new BinaryReader(stream, Encoding.UTF8, true)) { - var offset = stream.Position; + var header = br.ReadBytes(3); - using (var br = new BinaryReader(stream, Encoding.UTF8, true)) + if (header[0] != 'E' + || header[1] != 'V' + || header[2] != 'A') { - var header = br.ReadBytes(3); - - if (header[0] != 'E' - || header[1] != 'V' - || header[2] != 'A') - { - throw new SerializationException("Invalid array header."); - } - - try - { - var length = br.ReadInt32(); - var array = new Array(length); + throw new SerializationException("Invalid array header."); + } - for (var i = 0; i < length; i++) - { - array[i] = DynamicValue.Deserialize(stream); - } + try + { + var length = br.ReadInt32(); + var array = new Array(length); - return array; - } - catch (Exception e) + for (var i = 0; i < length; i++) { - throw new SerializationException( - $"Failed to deserialize the array at stream offset '{offset}'. Data may be corrupt.", - e - ); + array[i] = DynamicValue.Deserialize(stream); } + + return array; + } + catch (Exception e) + { + throw new SerializationException( + $"Failed to deserialize the array at stream offset '{offset}'. Data may be corrupt.", + e + ); } } } diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Serialization/DynamicValueSerializer.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Serialization/DynamicValueSerializer.cs index 7d07e23b..e75e36a4 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Serialization/DynamicValueSerializer.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Serialization/DynamicValueSerializer.cs @@ -1,3 +1,5 @@ +namespace EVIL.Ceres.ExecutionEngine.Collections.Serialization; + using System; using System.IO; using System.Reflection; @@ -7,262 +9,259 @@ using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine.Collections.Serialization +internal static class DynamicValueSerializer { - internal static class DynamicValueSerializer + public static void Serialize(DynamicValue dynamicValue, Stream stream, bool throwOnUnsupported = false) { - public static void Serialize(DynamicValue dynamicValue, Stream stream, bool throwOnUnsupported = false) + if (dynamicValue.Type == DynamicValueType.Fiber) { - if (dynamicValue.Type == DynamicValueType.Fiber) + if (throwOnUnsupported) { - if (throwOnUnsupported) - { - throw new SerializationException( - $"Serialization of values of type '{dynamicValue.Type}' is not supported." - ); - } - - return; + throw new SerializationException( + $"Serialization of values of type '{dynamicValue.Type}' is not supported." + ); } - using (var bw = new BinaryWriter(stream, Encoding.UTF8, true)) - { - bw.Write((byte)dynamicValue.Type); + return; + } - switch (dynamicValue.Type) - { - case DynamicValueType.Nil: - break; + using (var bw = new BinaryWriter(stream, Encoding.UTF8, true)) + { + bw.Write((byte)dynamicValue.Type); - case DynamicValueType.Number: - bw.Write(dynamicValue.Number); - break; + switch (dynamicValue.Type) + { + case DynamicValueType.Nil: + break; - case DynamicValueType.String: - bw.Write(dynamicValue.String!); - break; + case DynamicValueType.Number: + bw.Write(dynamicValue.Number); + break; - case DynamicValueType.Boolean: - bw.Write(dynamicValue.Boolean); - break; + case DynamicValueType.String: + bw.Write(dynamicValue.String!); + break; - case DynamicValueType.Table: - TableSerializer.Serialize(dynamicValue.Table!, stream); - break; + case DynamicValueType.Boolean: + bw.Write(dynamicValue.Boolean); + break; - case DynamicValueType.Array: - ArraySerializer.Serialize(dynamicValue.Array!, stream); - break; + case DynamicValueType.Table: + TableSerializer.Serialize(dynamicValue.Table!, stream); + break; - case DynamicValueType.TypeCode: - bw.Write((byte)dynamicValue.TypeCode); - break; + case DynamicValueType.Array: + ArraySerializer.Serialize(dynamicValue.Array!, stream); + break; - case DynamicValueType.Chunk: - { - using (var ms = new MemoryStream()) - { - dynamicValue.Chunk!.Serialize(ms); - bw.Write((int)ms.Length); - bw.Write(ms.ToArray()); - } + case DynamicValueType.TypeCode: + bw.Write((byte)dynamicValue.TypeCode); + break; - break; + case DynamicValueType.Chunk: + { + using (var ms = new MemoryStream()) + { + dynamicValue.Chunk!.Serialize(ms); + bw.Write((int)ms.Length); + bw.Write(ms.ToArray()); } - case DynamicValueType.NativeFunction: - { - var nativeFunc = dynamicValue.NativeFunction!; + break; + } - if (!nativeFunc.Method.IsStatic) - { - throw new SerializationException( - "Serialization of non-static native functions is not supported." - ); - } + case DynamicValueType.NativeFunction: + { + var nativeFunc = dynamicValue.NativeFunction!; - if (nativeFunc.Method.DeclaringType == null) - { - throw new SerializationException( - "A serialized native function must have a declaring type." - ); - } + if (!nativeFunc.Method.IsStatic) + { + throw new SerializationException( + "Serialization of non-static native functions is not supported." + ); + } - var fullTypeName = nativeFunc.Method.DeclaringType!.AssemblyQualifiedName; - var methodName = nativeFunc.Method.Name; + if (nativeFunc.Method.DeclaringType == null) + { + throw new SerializationException( + "A serialized native function must have a declaring type." + ); + } - bw.Write(fullTypeName!); - bw.Write(methodName); + var fullTypeName = nativeFunc.Method.DeclaringType!.AssemblyQualifiedName; + var methodName = nativeFunc.Method.Name; - break; - } + bw.Write(fullTypeName!); + bw.Write(methodName); - case DynamicValueType.NativeObject: - { - try - { - var bf = new BinaryFormatter(); + break; + } - using (var ms = new MemoryStream()) - { - bf.Serialize(ms, dynamicValue.NativeObject!); - bw.Write((int)ms.Length); - bw.Write(ms.ToArray()); - } + case DynamicValueType.NativeObject: + { + try + { + var bf = new BinaryFormatter(); - break; - } - catch (Exception e) + using (var ms = new MemoryStream()) { - throw new SerializationException( - $"Failed to serialize the native object '{dynamicValue.NativeObject!.GetType().FullName}", - e - ); + bf.Serialize(ms, dynamicValue.NativeObject!); + bw.Write((int)ms.Length); + bw.Write(ms.ToArray()); } + + break; + } + catch (Exception e) + { + throw new SerializationException( + $"Failed to serialize the native object '{dynamicValue.NativeObject!.GetType().FullName}", + e + ); } } } } + } - public static DynamicValue Deserialize(Stream stream, bool throwOnErrors = false) + public static DynamicValue Deserialize(Stream stream, bool throwOnErrors = false) + { + using (var br = new BinaryReader(stream, Encoding.UTF8, true)) { - using (var br = new BinaryReader(stream, Encoding.UTF8, true)) - { - var type = (DynamicValueType)br.ReadByte(); + var type = (DynamicValueType)br.ReadByte(); - switch (type) - { - case DynamicValueType.Nil: - return DynamicValue.Nil; - - case DynamicValueType.Number: - return new DynamicValue(br.ReadDouble()); + switch (type) + { + case DynamicValueType.Nil: + return DynamicValue.Nil; - case DynamicValueType.String: - return new DynamicValue(br.ReadString()); + case DynamicValueType.Number: + return new DynamicValue(br.ReadDouble()); - case DynamicValueType.Boolean: - return new DynamicValue(br.ReadBoolean()); + case DynamicValueType.String: + return new DynamicValue(br.ReadString()); - case DynamicValueType.Table: - return TableSerializer.Deserialize(stream); + case DynamicValueType.Boolean: + return new DynamicValue(br.ReadBoolean()); - case DynamicValueType.Array: - return ArraySerializer.Deserialize(stream); + case DynamicValueType.Table: + return TableSerializer.Deserialize(stream); - case DynamicValueType.TypeCode: - return new DynamicValue((DynamicValueType)br.ReadByte()); + case DynamicValueType.Array: + return ArraySerializer.Deserialize(stream); - case DynamicValueType.Chunk: - return DeserializeChunk(br); + case DynamicValueType.TypeCode: + return new DynamicValue((DynamicValueType)br.ReadByte()); - case DynamicValueType.NativeFunction: - return DeserializeNativeFunction(br); + case DynamicValueType.Chunk: + return DeserializeChunk(br); - case DynamicValueType.NativeObject: - return DeserializeNativeObject(br); - } + case DynamicValueType.NativeFunction: + return DeserializeNativeFunction(br); - if (throwOnErrors) - { - throw new SerializationException( - $"Deserialization of dynamic values of type '{type}' is not supported." - ); - } - else return DynamicValue.Nil; + case DynamicValueType.NativeObject: + return DeserializeNativeObject(br); } - } - private static DynamicValue DeserializeChunk(BinaryReader br) - { - try - { - var length = br.ReadInt32(); - var data = br.ReadBytes(length); - - using (var ms = new MemoryStream(data)) - { - ms.Seek(0, SeekOrigin.Begin); - - return new DynamicValue( - Chunk.Deserialize(ms, out _, out _) - ); - } - } - catch (Exception e) + if (throwOnErrors) { throw new SerializationException( - $"Failed to deserialize a function.", - e + $"Deserialization of dynamic values of type '{type}' is not supported." ); } + else return DynamicValue.Nil; } + } - private static DynamicValue DeserializeNativeFunction(BinaryReader br) + private static DynamicValue DeserializeChunk(BinaryReader br) + { + try { - var typeName = br.ReadString(); - var methodName = br.ReadString(); + var length = br.ReadInt32(); + var data = br.ReadBytes(length); - var nativeType = Type.GetType(typeName); - - if (nativeType == null) + using (var ms = new MemoryStream(data)) { - throw new SerializationException( - $"Failed to resolve native type '{typeName}'." + ms.Seek(0, SeekOrigin.Begin); + + return new DynamicValue( + Chunk.Deserialize(ms, out _, out _) ); } + } + catch (Exception e) + { + throw new SerializationException( + $"Failed to deserialize a function.", + e + ); + } + } - var method = nativeType.GetMethod( - methodName, - BindingFlags.Static - | BindingFlags.Public - | BindingFlags.NonPublic + private static DynamicValue DeserializeNativeFunction(BinaryReader br) + { + var typeName = br.ReadString(); + var methodName = br.ReadString(); + + var nativeType = Type.GetType(typeName); + + if (nativeType == null) + { + throw new SerializationException( + $"Failed to resolve native type '{typeName}'." ); + } - if (method == null) - { - throw new SerializationException( - $"Failed to resolve method '{methodName}' in native type '{typeName}." - ); - } + var method = nativeType.GetMethod( + methodName, + BindingFlags.Static + | BindingFlags.Public + | BindingFlags.NonPublic + ); - try - { - return new DynamicValue( - (NativeFunction)Delegate.CreateDelegate(typeof(NativeFunction), method) - ); - } - catch - { - throw new SerializationException( - $"Failed to bind the method '{methodName}' in native type '{typeName}'." - ); - } + if (method == null) + { + throw new SerializationException( + $"Failed to resolve method '{methodName}' in native type '{typeName}." + ); } - private static DynamicValue DeserializeNativeObject(BinaryReader br) + try { - try - { - var length = br.ReadInt32(); - var data = br.ReadBytes(length); + return new DynamicValue( + (NativeFunction)Delegate.CreateDelegate(typeof(NativeFunction), method) + ); + } + catch + { + throw new SerializationException( + $"Failed to bind the method '{methodName}' in native type '{typeName}'." + ); + } + } - using (var ms = new MemoryStream(data)) - { - ms.Seek(0, SeekOrigin.Begin); - var bf = new BinaryFormatter(); - var nativeObject = bf.Deserialize(ms); + private static DynamicValue DeserializeNativeObject(BinaryReader br) + { + try + { + var length = br.ReadInt32(); + var data = br.ReadBytes(length); - return new DynamicValue(nativeObject); - } - } - catch (Exception e) + using (var ms = new MemoryStream(data)) { - throw new SerializationException( - "Failed to deserialize the native object.", - e - ); + ms.Seek(0, SeekOrigin.Begin); + var bf = new BinaryFormatter(); + var nativeObject = bf.Deserialize(ms); + + return new DynamicValue(nativeObject); } } + catch (Exception e) + { + throw new SerializationException( + "Failed to deserialize the native object.", + e + ); + } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Serialization/SerializationException.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Serialization/SerializationException.cs index c6077dd6..90c301ec 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Serialization/SerializationException.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Serialization/SerializationException.cs @@ -1,17 +1,16 @@ +namespace EVIL.Ceres.ExecutionEngine.Collections.Serialization; + using System; -namespace EVIL.Ceres.ExecutionEngine.Collections.Serialization +public class SerializationException : VirtualMachineException { - public class SerializationException : VirtualMachineException + internal SerializationException(string message, Exception innerException) + : base(message, innerException) { - internal SerializationException(string message, Exception innerException) - : base(message, innerException) - { - } + } - internal SerializationException(string message) - : base(message) - { - } + internal SerializationException(string message) + : base(message) + { } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Serialization/TableSerializer.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Serialization/TableSerializer.cs index 30f32362..7e1bcd38 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Serialization/TableSerializer.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Serialization/TableSerializer.cs @@ -1,89 +1,87 @@ +namespace EVIL.Ceres.ExecutionEngine.Collections.Serialization; + using System; using System.IO; using System.Text; -using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine.Collections.Serialization +internal static class TableSerializer { - internal static class TableSerializer + public static void Serialize(Table table, Stream stream) { - public static void Serialize(Table table, Stream stream) + using (var bw = new BinaryWriter(stream, Encoding.UTF8, true)) { - using (var bw = new BinaryWriter(stream, Encoding.UTF8, true)) - { - bw.Write(new[] { (byte)'E', (byte)'V', (byte)'T' }); - bw.Write(table.Length); + bw.Write(new[] { (byte)'E', (byte)'V', (byte)'T' }); + bw.Write(table.Length); - foreach (var (key, value) in table) + foreach (var (key, value) in table) + { + if (key.Type == DynamicValueType.Table && ReferenceEquals(key.Table, table)) { - if (key.Type == DynamicValueType.Table && ReferenceEquals(key.Table, table)) - { - throw new SerializationException("Circular reference in table key."); - } - - if (value.Type == DynamicValueType.Table && ReferenceEquals(value.Table, table)) - { - throw new SerializationException("Circular reference in table value."); - } - - key.Serialize(stream); - value.Serialize(stream); + throw new SerializationException("Circular reference in table key."); } - bw.Write(table.HasMetaTable); - if (table.HasMetaTable) + if (value.Type == DynamicValueType.Table && ReferenceEquals(value.Table, table)) { - table.MetaTable!.Serialize(stream); + throw new SerializationException("Circular reference in table value."); } + + key.Serialize(stream); + value.Serialize(stream); + } + + bw.Write(table.HasMetaTable); + if (table.HasMetaTable) + { + table.MetaTable!.Serialize(stream); } } + } - public static Table Deserialize(Stream stream) - { - var offset = stream.Position; + public static Table Deserialize(Stream stream) + { + var offset = stream.Position; - using (var br = new BinaryReader(stream, Encoding.UTF8, true)) + using (var br = new BinaryReader(stream, Encoding.UTF8, true)) + { + var header = br.ReadBytes(3); + + if (header[0] != 'E' + || header[1] != 'V' + || header[2] != 'T') { - var header = br.ReadBytes(3); + throw new SerializationException("Invalid table header."); + } - if (header[0] != 'E' - || header[1] != 'V' - || header[2] != 'T') - { - throw new SerializationException("Invalid table header."); - } + try + { + var valueCount = br.ReadInt32(); + var table = new Table(); - try + for (var i = 0; i < valueCount; i++) { - var valueCount = br.ReadInt32(); - var table = new Table(); - - for (var i = 0; i < valueCount; i++) - { - var key = DynamicValue.Deserialize(stream); - var value = DynamicValue.Deserialize(stream); + var key = DynamicValue.Deserialize(stream); + var value = DynamicValue.Deserialize(stream); - table[key] = value; - } - - var hasMetaTable = br.ReadBoolean(); - if (hasMetaTable) - { - var metaTable = Table.Deserialize(stream); - table.MetaTable = metaTable; - } - - return table; + table[key] = value; } - catch (Exception e) + + var hasMetaTable = br.ReadBoolean(); + if (hasMetaTable) { - throw new SerializationException( - $"Failed to deserialize the table at stream offset '{offset}'. Data may be corrupt.", - e - ); + var metaTable = Table.Deserialize(stream); + table.MetaTable = metaTable; } + + return table; + } + catch (Exception e) + { + throw new SerializationException( + $"Failed to deserialize the table at stream offset '{offset}'. Data may be corrupt.", + e + ); } } } diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Table.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Table.cs index 9eb9a5ad..d637d06e 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Table.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Collections/Table.cs @@ -6,10 +6,9 @@ namespace EVIL.Ceres.ExecutionEngine.Collections; using System.IO; using System.Linq; using EVIL.Ceres.ExecutionEngine.Collections.Serialization; -using EVIL.Ceres.ExecutionEngine.Marshaling; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.CommonTypes.TypeSystem; -using static EVIL.Ceres.ExecutionEngine.TypeSystem.DynamicValue; +using static TypeSystem.DynamicValue; public class Table : IDynamicValueCollection, IIndexableObject, IWriteableObject { diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Concurrency/Fiber.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Concurrency/Fiber.cs index f2ad96e3..df93e018 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Concurrency/Fiber.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Concurrency/Fiber.cs @@ -1,3 +1,5 @@ +namespace EVIL.Ceres.ExecutionEngine.Concurrency; + using System; using System.Collections.Generic; using System.Linq; @@ -9,206 +11,194 @@ using EVIL.Ceres.ExecutionEngine.Diagnostics.Debugging; using EVIL.Ceres.ExecutionEngine.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine.Concurrency +public sealed class Fiber { - public sealed class Fiber - { - private Queue<(Chunk Chunk, DynamicValue[] Arguments)> _scheduledChunks; - private HashSet _waitingFor; + private Queue<(Chunk Chunk, DynamicValue[] Arguments)> _scheduledChunks; + private HashSet _waitingFor; - private Stack _evaluationStack; - private CallStack _callStack; - private Dictionary _closureContexts; + private Stack _evaluationStack; + private CallStack _callStack; + private Dictionary _closureContexts; - private ExecutionUnit _executionUnit; - private FiberCrashHandler? _crashHandler; - internal FiberState _state; + private ExecutionUnit _executionUnit; + private FiberCrashHandler? _crashHandler; + internal FiberState _state; - internal ChunkInvokeHandler? OnChunkInvoke { get; private set; } - internal NativeFunctionInvokeHandler? OnNativeFunctionInvoke { get; private set; } + internal ChunkInvokeHandler? OnChunkInvoke { get; private set; } + internal NativeFunctionInvokeHandler? OnNativeFunctionInvoke { get; private set; } - public FiberCrashHandler? CrashHandler => _crashHandler; - public IReadOnlySet WaitingFor => _waitingFor; + public FiberCrashHandler? CrashHandler => _crashHandler; + public IReadOnlySet WaitingFor => _waitingFor; - public IReadOnlyDictionary ClosureContexts => _closureContexts; + public IReadOnlyDictionary ClosureContexts => _closureContexts; - public CeresVM VirtualMachine { get; } + public CeresVM VirtualMachine { get; } - public FiberState State => _state; + public FiberState State => _state; - public bool ImmuneToCollection { get; private set; } + public bool ImmuneToCollection { get; private set; } - public IReadOnlyCollection EvaluationStack + public IReadOnlyCollection EvaluationStack + { + get { - get + lock (_evaluationStack) { - lock (_evaluationStack) - { - return _evaluationStack; - } + return _evaluationStack; } } + } - public CallStack CallStack + public CallStack CallStack + { + get { - get + lock (_callStack) { - lock (_callStack) - { - return _callStack; - } + return _callStack; } } + } - internal Fiber(CeresVM virtualMachine, Dictionary? closureContexts = null) - { - VirtualMachine = virtualMachine; + internal Fiber(CeresVM virtualMachine, Dictionary? closureContexts = null) + { + VirtualMachine = virtualMachine; - _scheduledChunks = new Queue<(Chunk, DynamicValue[])>(); - _waitingFor = new HashSet(); + _scheduledChunks = new Queue<(Chunk, DynamicValue[])>(); + _waitingFor = new HashSet(); - _evaluationStack = new Stack(); - _callStack = new CallStack(); - _closureContexts = closureContexts ?? new Dictionary(); + _evaluationStack = new Stack(); + _callStack = new CallStack(); + _closureContexts = closureContexts ?? new Dictionary(); - _executionUnit = new ExecutionUnit( - virtualMachine.Global, - this, - _evaluationStack, - _callStack - ); - - _state = FiberState.Fresh; - } + _executionUnit = new ExecutionUnit( + virtualMachine.Global, + this, + _evaluationStack, + _callStack + ); + + _state = FiberState.Fresh; + } - internal Fiber( - CeresVM virtualMachine, - FiberCrashHandler fiberCrashHandler, - Dictionary? closureContexts = null) : this(virtualMachine, closureContexts) - { - SetCrashHandler(fiberCrashHandler); - } + internal Fiber( + CeresVM virtualMachine, + FiberCrashHandler fiberCrashHandler, + Dictionary? closureContexts = null) : this(virtualMachine, closureContexts) + { + SetCrashHandler(fiberCrashHandler); + } - public void Schedule(Chunk chunk, params DynamicValue[] args) - => Schedule(chunk, true, args); + public void Schedule(Chunk chunk, params DynamicValue[] args) + => Schedule(chunk, true, args); - public void Schedule(Chunk chunk, bool resumeImmediately, params DynamicValue[] args) + public void Schedule(Chunk chunk, bool resumeImmediately, params DynamicValue[] args) + { + lock (_scheduledChunks) { - lock (_scheduledChunks) - { - _scheduledChunks.Enqueue((chunk, args)); - } + _scheduledChunks.Enqueue((chunk, args)); + } - if (resumeImmediately) - { - Resume(); - } + if (resumeImmediately) + { + Resume(); } + } - public void BlockUntilFinished() + public void BlockUntilFinished() + { + while (_state != FiberState.Finished && + _state != FiberState.Crashed) { - while (_state != FiberState.Finished && - _state != FiberState.Crashed) - { - Thread.Sleep(1); - } + Thread.Sleep(1); } + } - public async Task BlockUntilFinishedAsync() + public async Task BlockUntilFinishedAsync() + { + while (_state != FiberState.Finished && + _state != FiberState.Crashed) { - while (_state != FiberState.Finished && - _state != FiberState.Crashed) - { - await Task.Delay(1); - } + await Task.Delay(1); } + } - public string StackTrace(bool skipNativeFrames) - { - return StackTrace( - CallStack.ToArray(skipNativeFrames) - ); - } + public string StackTrace(bool skipNativeFrames) + { + return StackTrace( + CallStack.ToArray(skipNativeFrames) + ); + } - public static string StackTrace(StackFrame[] callStack) - { - var sb = new StringBuilder(); + public static string StackTrace(StackFrame[] callStack) + { + var sb = new StringBuilder(); - for (var i = 0; i < callStack.Length; i++) + for (var i = 0; i < callStack.Length; i++) + { + if (callStack[i] is ScriptStackFrame ssf) { - if (callStack[i] is ScriptStackFrame ssf) - { - sb.Append($"at {ssf.Chunk.Name ?? ""}"); + sb.Append($"at {ssf.Chunk.Name ?? ""}"); - if (!string.IsNullOrEmpty(ssf.Chunk.DebugDatabase.DefinedInFile)) - { - sb.Append($" in {ssf.Chunk.DebugDatabase.DefinedInFile}"); - } - - sb.Append($": line {ssf.Chunk.DebugDatabase.GetLineForIP((int)ssf.PreviousOpCodeIP)} (IP: {ssf.PreviousOpCodeIP:X8})"); - sb.AppendLine(); - } - else if (callStack[i] is NativeStackFrame nsf) + if (!string.IsNullOrEmpty(ssf.Chunk.DebugDatabase.DefinedInFile)) { - sb.AppendLine($"at clr!{nsf.NativeFunction.Method.DeclaringType!.FullName}::{nsf.NativeFunction.Method.Name}"); + sb.Append($" in {ssf.Chunk.DebugDatabase.DefinedInFile}"); } + + sb.Append($": line {ssf.Chunk.DebugDatabase.GetLineForIP((int)ssf.PreviousOpCodeIP)} (IP: {ssf.PreviousOpCodeIP:X8})"); + sb.AppendLine(); + } + else if (callStack[i] is NativeStackFrame nsf) + { + sb.AppendLine($"at clr!{nsf.NativeFunction.Method.DeclaringType!.FullName}::{nsf.NativeFunction.Method.Name}"); } - - return sb.ToString(); } - public void Step() + return sb.ToString(); + } + + public void Step() + { + try { - try - { - if (_state != FiberState.Running) - return; + if (_state != FiberState.Running) + return; - lock (_callStack) + lock (_callStack) + { + if (_callStack.Count == 0) { - if (_callStack.Count == 0) + lock (_scheduledChunks) { - lock (_scheduledChunks) + if (_scheduledChunks.TryDequeue(out var info)) { - if (_scheduledChunks.TryDequeue(out var info)) - { - Invoke(info.Chunk, info.Arguments); - } - else - { - _state = FiberState.Finished; - return; - } + Invoke(info.Chunk, info.Arguments); + } + else + { + _state = FiberState.Finished; + return; } } } - - _executionUnit.Step(); } - catch (Exception e) + + _executionUnit.Step(); + } + catch (Exception e) + { + if (e is RecoverableVirtualMachineException rvme) { - if (e is RecoverableVirtualMachineException rvme) + try { - try - { - ThrowFromNative( - new Error( - new Table { { "native_exception", DynamicValue.FromObject(rvme) } }, - rvme.Message - ) - ); - } - catch - { - EnterCrashState(); - - if (_crashHandler != null) - { - _crashHandler(this, e); - } - } + ThrowFromNative( + new Error( + new Table { { "native_exception", DynamicValue.FromObject(rvme) } }, + rvme.Message + ) + ); } - else + catch { EnterCrashState(); @@ -218,41 +208,84 @@ public void Step() } } } + else + { + EnterCrashState(); + + if (_crashHandler != null) + { + _crashHandler(this, e); + } + } } + } - public void Yield() + public void Yield() + { + if (_state != FiberState.Running) { - if (_state != FiberState.Running) - { - return; - } + return; + } - _state = FiberState.Paused; + _state = FiberState.Paused; + } + + public void Yield(Fiber to) + { + if (_state != FiberState.Running) + { + return; } - public void Yield(Fiber to) + _state = FiberState.Paused; + to.Resume(); + } + + public void Await() + { + if (!_waitingFor.Any()) { - if (_state != FiberState.Running) - { - return; - } + return; + } + + _state = FiberState.Awaiting; + } + + public void WaitFor(Fiber fiber) + { + if (fiber == this) + { + throw new FiberException("A fiber cannot wait for self."); + } - _state = FiberState.Paused; - to.Resume(); + if (fiber._state == FiberState.Finished) + { + return; } - public void Await() + _waitingFor.Add(fiber); + Await(); + } + + public void StopWaitingFor(Fiber fiber) + { + _waitingFor.Remove(fiber); + + if (_state == FiberState.Awaiting) { if (!_waitingFor.Any()) { - return; + _state = FiberState.Running; } - - _state = FiberState.Awaiting; } + } - public void WaitFor(Fiber fiber) + public void WaitForAll(params Fiber[] fibers) + { + for (var i = 0; i < fibers.Length; i++) { + var fiber = fibers[i]; + if (fiber == this) { throw new FiberException("A fiber cannot wait for self."); @@ -260,232 +293,198 @@ public void WaitFor(Fiber fiber) if (fiber._state == FiberState.Finished) { - return; + continue; } - _waitingFor.Add(fiber); - Await(); + _waitingFor.Add(fibers[i]); } - public void StopWaitingFor(Fiber fiber) + Await(); + } + + public void Resume() + { + if (_state == FiberState.Awaiting) { - _waitingFor.Remove(fiber); - - if (_state == FiberState.Awaiting) + if (_waitingFor.Any()) { - if (!_waitingFor.Any()) - { - _state = FiberState.Running; - } + return; } } - public void WaitForAll(params Fiber[] fibers) - { - for (var i = 0; i < fibers.Length; i++) - { - var fiber = fibers[i]; - - if (fiber == this) - { - throw new FiberException("A fiber cannot wait for self."); - } - - if (fiber._state == FiberState.Finished) - { - continue; - } - - _waitingFor.Add(fibers[i]); - } + _state = FiberState.Running; + } - Await(); - } - - public void Resume() + public void Stop() + { + lock (_scheduledChunks) { - if (_state == FiberState.Awaiting) - { - if (_waitingFor.Any()) - { - return; - } - } - - _state = FiberState.Running; + _scheduledChunks.Clear(); } - public void Stop() + lock (_callStack) { - lock (_scheduledChunks) - { - _scheduledChunks.Clear(); - } - - lock (_callStack) - { - _callStack.DisposeAllAndClear(); - } + _callStack.DisposeAllAndClear(); } + } - public void Reset() - { - Stop(); - - lock (_evaluationStack) - { - _evaluationStack.Clear(); - } - - lock (_waitingFor) - { - _waitingFor.Clear(); - } + public void Reset() + { + Stop(); - _state = FiberState.Fresh; - } - - public void Immunize() + lock (_evaluationStack) { - ImmuneToCollection = true; + _evaluationStack.Clear(); } - public void DeImmunize() + lock (_waitingFor) { - ImmuneToCollection = false; + _waitingFor.Clear(); } + + _state = FiberState.Fresh; + } + + public void Immunize() + { + ImmuneToCollection = true; + } + + public void DeImmunize() + { + ImmuneToCollection = false; + } - public void PushValue(DynamicValue value) + public void PushValue(DynamicValue value) + { + lock (_evaluationStack) { - lock (_evaluationStack) - { - _evaluationStack.Push(value); - } + _evaluationStack.Push(value); } + } - public DynamicValue PeekValue() + public DynamicValue PeekValue() + { + lock (_evaluationStack) { - lock (_evaluationStack) - { - return _evaluationStack.Peek(); - } + return _evaluationStack.Peek(); } + } - public bool TryPeekValue(out DynamicValue value) + public bool TryPeekValue(out DynamicValue value) + { + lock (_evaluationStack) { - lock (_evaluationStack) - { - return _evaluationStack.TryPeek(out value!); - } + return _evaluationStack.TryPeek(out value!); } + } - public DynamicValue PopValue() + public DynamicValue PopValue() + { + lock (_evaluationStack) { - lock (_evaluationStack) - { - return _evaluationStack.Pop(); - } + return _evaluationStack.Pop(); } + } - public bool TryPopValue(out DynamicValue value) + public bool TryPopValue(out DynamicValue value) + { + lock (_evaluationStack) { - lock (_evaluationStack) - { - return _evaluationStack.TryPop(out value!); - } + return _evaluationStack.TryPop(out value!); } + } - public ClosureContext SetClosureContext(string chunkName) + public ClosureContext SetClosureContext(string chunkName) + { + if (!_closureContexts.TryGetValue(chunkName, out var value)) { - if (!_closureContexts.TryGetValue(chunkName, out var value)) - { - value = _closureContexts[chunkName] = new ClosureContext(chunkName); - } - - return value; + value = _closureContexts[chunkName] = new ClosureContext(chunkName); } - public void SetCrashHandler(FiberCrashHandler? crashHandler) - { - _crashHandler = crashHandler; - } + return value; + } - public void SetOnChunkInvoke(ChunkInvokeHandler? handler) - { - OnChunkInvoke = handler; - } + public void SetCrashHandler(FiberCrashHandler? crashHandler) + { + _crashHandler = crashHandler; + } - public void SetOnNativeFunctionInvoke(NativeFunctionInvokeHandler? handler) - { - OnNativeFunctionInvoke = handler; - } + public void SetOnChunkInvoke(ChunkInvokeHandler? handler) + { + OnChunkInvoke = handler; + } - public DynamicValue ThrowFromNative(DynamicValue value) - { - lock (_callStack) - lock (_evaluationStack) - { - var frame = _callStack.Peek(); - if (frame is NativeStackFrame nsf) - { - nsf.HasThrown = true; - _callStack.Pop(); - } + public void SetOnNativeFunctionInvoke(NativeFunctionInvokeHandler? handler) + { + OnNativeFunctionInvoke = handler; + } + + public DynamicValue ThrowFromNative(DynamicValue value) + { + lock (_callStack) + lock (_evaluationStack) + { + var frame = _callStack.Peek(); + if (frame is NativeStackFrame nsf) + { + nsf.HasThrown = true; + _callStack.Pop(); + } - _evaluationStack.Push(value); + _evaluationStack.Push(value); - UnwindTryHandle(_callStack.ToArray()); - } - - return DynamicValue.Nil; + UnwindTryHandle(_callStack.ToArray()); } + + return DynamicValue.Nil; + } - internal void UnwindTryHandle(StackFrame[] callStackCopy) + internal void UnwindTryHandle(StackFrame[] callStackCopy) + { + lock (_callStack) { - lock (_callStack) - { - var scriptFrame = _callStack.Peek().As(); + var scriptFrame = _callStack.Peek().As(); - while (_callStack.Count > 1 && !scriptFrame.IsProtectedState) - { - _callStack.Pop(); - scriptFrame = _callStack.Peek().As(); - } + while (_callStack.Count > 1 && !scriptFrame.IsProtectedState) + { + _callStack.Pop(); + scriptFrame = _callStack.Peek().As(); + } - if (scriptFrame.IsProtectedState) - { - var info = scriptFrame.BlockProtectorStack.Peek(); - scriptFrame.JumpAbsolute(info.HandlerAddress); - } - else - { - var exceptionObject = PopValue(); + 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 - ); - } + throw new UserUnhandledExceptionException( + "A user-unhandled exception has been thrown.", + exceptionObject, + callStackCopy + ); } } + } - internal void RemoveFinishedAwaitees() - { - _waitingFor.RemoveWhere(x => x._state == FiberState.Finished); - } + internal void RemoveFinishedAwaitees() + { + _waitingFor.RemoveWhere(x => x._state == FiberState.Finished); + } - private void EnterCrashState() - { - _state = FiberState.Crashed; - } + private void EnterCrashState() + { + _state = FiberState.Crashed; + } - private void Invoke(Chunk chunk, DynamicValue[] args) + private void Invoke(Chunk chunk, DynamicValue[] args) + { + lock (_callStack) { - lock (_callStack) - { - _callStack.Push(new ScriptStackFrame(this, chunk, args)); - } + _callStack.Push(new ScriptStackFrame(this, chunk, args)); } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Concurrency/FiberException.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Concurrency/FiberException.cs index 744ccda5..bf1ce25e 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Concurrency/FiberException.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Concurrency/FiberException.cs @@ -1,10 +1,9 @@ -namespace EVIL.Ceres.ExecutionEngine.Concurrency +namespace EVIL.Ceres.ExecutionEngine.Concurrency; + +public sealed class FiberException : VirtualMachineException { - public sealed class FiberException : VirtualMachineException + public FiberException(string message) + : base(message) { - public FiberException(string message) - : base(message) - { - } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Concurrency/FiberScheduler.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Concurrency/FiberScheduler.cs index 26b82b5b..1e0468f2 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Concurrency/FiberScheduler.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Concurrency/FiberScheduler.cs @@ -1,148 +1,146 @@ +namespace EVIL.Ceres.ExecutionEngine.Concurrency; + using System.Collections.Generic; using System.Linq; using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.ExecutionEngine.Diagnostics.Debugging; -namespace EVIL.Ceres.ExecutionEngine.Concurrency +public class FiberScheduler { + private CeresVM _vm; + private FiberCrashHandler _defaultCrashHandler; - public class FiberScheduler - { - private CeresVM _vm; - private FiberCrashHandler _defaultCrashHandler; - - private List _fibers; - private List _dueForRemoval; + private List _fibers; + private List _dueForRemoval; - private bool _running; + private bool _running; - public IReadOnlyList Fibers => _fibers; - public bool IsRunning => _running; + public IReadOnlyList Fibers => _fibers; + public bool IsRunning => _running; - public FiberScheduler(CeresVM vm, FiberCrashHandler defaultCrashHandler) - { - _vm = vm; - _defaultCrashHandler = defaultCrashHandler; + public FiberScheduler(CeresVM vm, FiberCrashHandler defaultCrashHandler) + { + _vm = vm; + _defaultCrashHandler = defaultCrashHandler; - _fibers = new(); - _dueForRemoval = new(); - } + _fibers = new(); + _dueForRemoval = new(); + } - public void Run() - { - _running = true; + public void Run() + { + _running = true; - while (_running) + while (_running) + { + lock (_fibers) { - lock (_fibers) + for (var i = 0; i < _fibers.Count; i++) { - for (var i = 0; i < _fibers.Count; i++) - { - var fiber = _fibers[i]; + var fiber = _fibers[i]; - if (fiber._state == FiberState.Awaiting) + if (fiber._state == FiberState.Awaiting) + { + fiber.RemoveFinishedAwaitees(); + fiber.Resume(); + } + else if (fiber._state == FiberState.Fresh) + { + fiber.Resume(); + } + else if (fiber._state == FiberState.Paused) + { + continue; + } + else + { + if (fiber._state == FiberState.Finished || fiber._state == FiberState.Crashed) { - fiber.RemoveFinishedAwaitees(); - fiber.Resume(); + if (!fiber.ImmuneToCollection) + { + _dueForRemoval.Add(i); + } } - else if (fiber._state == FiberState.Fresh) + else { fiber.Resume(); } - else if (fiber._state == FiberState.Paused) + + if (fiber._state != FiberState.Running) { continue; } - else - { - if (fiber._state == FiberState.Finished || fiber._state == FiberState.Crashed) - { - if (!fiber.ImmuneToCollection) - { - _dueForRemoval.Add(i); - } - } - else - { - fiber.Resume(); - } - - if (fiber._state != FiberState.Running) - { - continue; - } - } - - fiber.Step(); } - - RemoveFinishedFibers(); + + fiber.Step(); } + + RemoveFinishedFibers(); } } + } - public void SetDefaultCrashHandler(FiberCrashHandler crashHandler) + public void SetDefaultCrashHandler(FiberCrashHandler crashHandler) + { + _defaultCrashHandler = crashHandler; + } + + public void Stop() + { + lock (_fibers) { - _defaultCrashHandler = crashHandler; + _running = false; } + } - public void Stop() + public Fiber CreateFiber( + bool immunized, + FiberCrashHandler? crashHandler = null, + Dictionary? closureContexts = null) + { + var fiber = new Fiber( + _vm, + crashHandler ?? _defaultCrashHandler, + closureContexts + ); + + if (immunized) { - lock (_fibers) - { - _running = false; - } + fiber.Immunize(); } - public Fiber CreateFiber( - bool immunized, - FiberCrashHandler? crashHandler = null, - Dictionary? closureContexts = null) + lock (_fibers) { - var fiber = new Fiber( - _vm, - crashHandler ?? _defaultCrashHandler, - closureContexts - ); - - if (immunized) - { - fiber.Immunize(); - } - - lock (_fibers) - { - _fibers.Add(fiber); - } - - return fiber; + _fibers.Add(fiber); } - public void RemoveCrashedFibers() + return fiber; + } + + public void RemoveCrashedFibers() + { + for (var i = 0; i < _fibers.Count; i++) { - for (var i = 0; i < _fibers.Count; i++) + if (_fibers[i]._state == FiberState.Crashed) { - if (_fibers[i]._state == FiberState.Crashed) - { - _dueForRemoval.Add(i); - } + _dueForRemoval.Add(i); } } + } - private void RemoveFinishedFibers() - { - if (!_dueForRemoval.Any()) - return; - - _dueForRemoval.Sort(); - _dueForRemoval.Reverse(); + private void RemoveFinishedFibers() + { + if (!_dueForRemoval.Any()) + return; - for (var i = 0; i < _dueForRemoval.Count; i++) - { - _fibers.RemoveAt(_dueForRemoval[i]); - } + _dueForRemoval.Sort(); + _dueForRemoval.Reverse(); - _dueForRemoval.Clear(); + for (var i = 0; i < _dueForRemoval.Count; i++) + { + _fibers.RemoveAt(_dueForRemoval[i]); } + + _dueForRemoval.Clear(); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Concurrency/FiberState.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Concurrency/FiberState.cs index fb55df39..45b49629 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Concurrency/FiberState.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Concurrency/FiberState.cs @@ -1,12 +1,11 @@ -namespace EVIL.Ceres.ExecutionEngine.Concurrency +namespace EVIL.Ceres.ExecutionEngine.Concurrency; + +public enum FiberState { - public enum FiberState - { - Fresh, - Running, - Awaiting, - Paused, - Crashed, - Finished - } + Fresh, + Running, + Awaiting, + Paused, + Crashed, + Finished } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/BlockProtectionInfo.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/BlockProtectionInfo.cs index a07e1fed..f09c9027 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/BlockProtectionInfo.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/BlockProtectionInfo.cs @@ -1,10 +1,9 @@ -namespace EVIL.Ceres.ExecutionEngine.Diagnostics +namespace EVIL.Ceres.ExecutionEngine.Diagnostics; + +public class BlockProtectionInfo { - public class BlockProtectionInfo - { - public int EnterLabelId { get; internal set; } - public int StartAddress { get; internal set; } - public int Length { get; internal set; } - public int HandlerAddress { get; internal set; } - } + public int EnterLabelId { get; internal set; } + public int StartAddress { get; internal set; } + public int Length { get; internal set; } + public int HandlerAddress { get; internal set; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/CallStack.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/CallStack.cs index a05247e9..1ec08bb6 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/CallStack.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/CallStack.cs @@ -1,85 +1,84 @@ +namespace EVIL.Ceres.ExecutionEngine.Diagnostics; + using System; using System.Linq; using System.Runtime.CompilerServices; -namespace EVIL.Ceres.ExecutionEngine.Diagnostics +public class CallStack { - public class CallStack - { - public const int MaxFrames = 16384; + public const int MaxFrames = 16384; - private int _currentPointer = -1; - private StackFrame?[] _frames = new StackFrame[MaxFrames]; + private int _currentPointer = -1; + private StackFrame?[] _frames = new StackFrame[MaxFrames]; - public StackFrame this[int index] => _frames[_currentPointer - index]!; - public int Count => _currentPointer + 1; + public StackFrame this[int index] => _frames[_currentPointer - index]!; + public int Count => _currentPointer + 1; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public StackFrame Peek() + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public StackFrame Peek() + { + if (_currentPointer < 0) { - if (_currentPointer < 0) - { - throw new InvalidOperationException("Stack empty"); - } - - return _frames[_currentPointer]!; + throw new InvalidOperationException("Stack empty"); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Push(StackFrame stackFrame) - { - if (_currentPointer + 1 >= MaxFrames) - { - throw new VirtualMachineException("Call stack overflow."); - } + return _frames[_currentPointer]!; + } - _frames[++_currentPointer] = stackFrame; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Push(StackFrame stackFrame) + { + if (_currentPointer + 1 >= MaxFrames) + { + throw new VirtualMachineException("Call stack overflow."); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public StackFrame Pop() + _frames[++_currentPointer] = stackFrame; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public StackFrame Pop() + { + if (_currentPointer < 0) { - if (_currentPointer < 0) - { - throw new InvalidOperationException("Stack empty."); - } + throw new InvalidOperationException("Stack empty."); + } - var ret = _frames[_currentPointer]!; - _frames[_currentPointer--] = null; + var ret = _frames[_currentPointer]!; + _frames[_currentPointer--] = null; - return ret; - } + return ret; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void DisposeAllAndClear() + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void DisposeAllAndClear() + { + for (var i = 0; i < _frames.Length; i++) { - for (var i = 0; i < _frames.Length; i++) - { - if (_frames[i] == null) - break; - - _frames[i]!.Dispose(); - } + if (_frames[i] == null) + break; - Array.Clear(_frames); - _currentPointer = -1; + _frames[i]!.Dispose(); } - public StackFrame[] ToArray(bool skipNativeFrames = false) + Array.Clear(_frames); + _currentPointer = -1; + } + + public StackFrame[] ToArray(bool skipNativeFrames = false) + { + if (skipNativeFrames) + { + return _frames.Take(_currentPointer + 1) + .Where(x => x is ScriptStackFrame) + .Reverse() + .ToArray()!; + } + else { - if (skipNativeFrames) - { - return _frames.Take(_currentPointer + 1) - .Where(x => x is ScriptStackFrame) - .Reverse() - .ToArray()!; - } - else - { - return _frames.Take(_currentPointer + 1) - .Reverse() - .ToArray()!; - } + return _frames.Take(_currentPointer + 1) + .Reverse() + .ToArray()!; } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Chunk.Deserializer.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Chunk.Deserializer.cs index 0a8f29bb..512e221b 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Chunk.Deserializer.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Chunk.Deserializer.cs @@ -1,246 +1,246 @@ -using System.IO; +namespace EVIL.Ceres.ExecutionEngine.Diagnostics; + +using static EVIL.Ceres.ExecutionEngine.TypeSystem.DynamicValue; + +using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.CommonTypes.TypeSystem; -using static EVIL.Ceres.ExecutionEngine.TypeSystem.DynamicValue; -namespace EVIL.Ceres.ExecutionEngine.Diagnostics +public sealed partial class Chunk { - public sealed partial class Chunk + private static class Deserializer { - private static class Deserializer + private static void ValidateSignature(byte[] signature, out byte version) { - private static void ValidateSignature(byte[] signature, out byte version) + if (signature[0] != 'E' + || signature[1] != 'V' + || signature[2] != 'C' + || signature[3] != 0x06) { - if (signature[0] != 'E' - || signature[1] != 'V' - || signature[2] != 'C' - || signature[3] != 0x06) - { - throw new ChunkDeserializationException( - "Expected signature 'E' 'V' 'C' '\\x06', found " + - $"'{(char)signature[0]}' '{(char)signature[1]}' '{(char)signature[2]}' '\\x{signature[3]:X2}' instead." - ); - } - - version = signature[4]; + throw new ChunkDeserializationException( + "Expected signature 'E' 'V' 'C' '\\x06', found " + + $"'{(char)signature[0]}' '{(char)signature[1]}' '{(char)signature[2]}' '\\x{signature[3]:X2}' instead." + ); } - private static void ReadHeader( - BinaryReader br, - out byte version, - out long timestamp, - out ChunkFlags flags) + version = signature[4]; + } + + private static void ReadHeader( + BinaryReader br, + out byte version, + out long timestamp, + out ChunkFlags flags) + { + ValidateSignature( + br.ReadBytes(5), + out version + ); + + timestamp = br.ReadInt64(); + flags = (ChunkFlags)br.ReadInt32(); + } + + private static DynamicValue ReadConstValue(BinaryReader br) + { + var type = (DynamicValueType)br.ReadByte(); + + return type switch { - ValidateSignature( - br.ReadBytes(5), - out version - ); + DynamicValueType.Nil => Nil, + DynamicValueType.Number => br.ReadDouble(), + DynamicValueType.String => br.ReadString(), + DynamicValueType.Boolean => br.ReadBoolean(), + DynamicValueType.TypeCode => br.ReadByte(), + _ => throw new ChunkDeserializationException($"Unexpected constant value type '{type}'.") + }; + } - timestamp = br.ReadInt64(); - flags = (ChunkFlags)br.ReadInt32(); + private static ChunkAttribute ReadAttribute(BinaryReader br) + { + var name = br.ReadString(); + var attribute = new ChunkAttribute(name); + + var valueCount = br.ReadInt32(); + for (var i = 0; i < valueCount; i++) + { + attribute.Values.Add(ReadConstValue(br)); } - private static DynamicValue ReadConstValue(BinaryReader br) + var propertyCount = br.ReadInt32(); + for (var i = 0; i < propertyCount; i++) { - var type = (DynamicValueType)br.ReadByte(); - - return type switch - { - DynamicValueType.Nil => Nil, - DynamicValueType.Number => br.ReadDouble(), - DynamicValueType.String => br.ReadString(), - DynamicValueType.Boolean => br.ReadBoolean(), - DynamicValueType.TypeCode => br.ReadByte(), - _ => throw new ChunkDeserializationException($"Unexpected constant value type '{type}'.") - }; + attribute.Properties.Add( + br.ReadString(), + ReadConstValue(br) + ); } - private static ChunkAttribute ReadAttribute(BinaryReader br) + return attribute; + } + + private static BlockProtectionInfo ReadProtectedBlock(BinaryReader br) + { + return new BlockProtectionInfo { - var name = br.ReadString(); - var attribute = new ChunkAttribute(name); + StartAddress = br.ReadInt32(), + Length = br.ReadInt32(), + HandlerAddress = br.ReadInt32() + }; + } + + private static string ReadName(BinaryReader br) + { + return br.ReadString(); + } + + public static Chunk Deserialize(Stream stream, out byte version, out long timestamp) + { + Chunk chunk; - var valueCount = br.ReadInt32(); - for (var i = 0; i < valueCount; i++) + using (var br = new BinaryReader(stream, Encoding.UTF8, true)) + { + ReadHeader(br, out version, out timestamp, out var flags); + + chunk = new Chunk(ReadName(br)); + + if (flags.HasFlag(ChunkFlags.IsSelfAware)) { - attribute.Values.Add(ReadConstValue(br)); + chunk.MarkSelfAware(); } - var propertyCount = br.ReadInt32(); - for (var i = 0; i < propertyCount; i++) + if (flags.HasFlag(ChunkFlags.MayThrow)) { - attribute.Properties.Add( - br.ReadString(), - ReadConstValue(br) - ); + chunk.MarkThrowing(); } - return attribute; - } + chunk.IsSpecialName = flags.HasFlag(ChunkFlags.IsSpecialName); - private static BlockProtectionInfo ReadProtectedBlock(BinaryReader br) - { - return new BlockProtectionInfo + if (flags.HasFlag(ChunkFlags.HasParameters)) { - StartAddress = br.ReadInt32(), - Length = br.ReadInt32(), - HandlerAddress = br.ReadInt32() - }; - } + chunk.ParameterCount = br.ReadInt32(); + } - private static string ReadName(BinaryReader br) - { - return br.ReadString(); - } - - public static Chunk Deserialize(Stream stream, out byte version, out long timestamp) - { - Chunk chunk; - - using (var br = new BinaryReader(stream, Encoding.UTF8, true)) + if (flags.HasFlag(ChunkFlags.HasParameterInitializers)) { - ReadHeader(br, out version, out timestamp, out var flags); + var initializerCount = br.ReadInt32(); - chunk = new Chunk(ReadName(br)); - - if (flags.HasFlag(ChunkFlags.IsSelfAware)) + for (var i = 0; i < initializerCount; i++) { - chunk.MarkSelfAware(); + chunk._parameterInitializers.Add( + br.ReadInt32(), + ReadConstValue(br) + ); } + } - if (flags.HasFlag(ChunkFlags.MayThrow)) - { - chunk.MarkThrowing(); - } - - chunk.IsSpecialName = flags.HasFlag(ChunkFlags.IsSpecialName); - - if (flags.HasFlag(ChunkFlags.HasParameters)) - { - chunk.ParameterCount = br.ReadInt32(); - } + if (flags.HasFlag(ChunkFlags.HasClosures)) + { + var closureCount = br.ReadInt32(); - if (flags.HasFlag(ChunkFlags.HasParameterInitializers)) + for (var i = 0; i < closureCount; i++) { - var initializerCount = br.ReadInt32(); - - for (var i = 0; i < initializerCount; i++) - { - chunk._parameterInitializers.Add( + chunk._closures.Add( + new ClosureInfo( + br.ReadInt32(), br.ReadInt32(), - ReadConstValue(br) - ); - } + br.ReadString(), + br.ReadBoolean(), + br.ReadBoolean(), + br.ReadBoolean() + ) + ); } + } - if (flags.HasFlag(ChunkFlags.HasClosures)) + if (flags.HasFlag(ChunkFlags.HasSubChunks)) + { + var subChunkCount = br.ReadInt32(); + for (var i = 0; i < subChunkCount; i++) { - var closureCount = br.ReadInt32(); - - for (var i = 0; i < closureCount; i++) - { - chunk._closures.Add( - new ClosureInfo( - br.ReadInt32(), - br.ReadInt32(), - br.ReadString(), - br.ReadBoolean(), - br.ReadBoolean(), - br.ReadBoolean() - ) - ); - } - } - - if (flags.HasFlag(ChunkFlags.HasSubChunks)) - { - var subChunkCount = br.ReadInt32(); - for (var i = 0; i < subChunkCount; i++) - { - var subChunk = Deserialize(stream, out _, out _); + var subChunk = Deserialize(stream, out _, out _); - chunk._subChunks.Add(subChunk); - subChunk.Parent = chunk; - } - - var lookupCount = br.ReadInt32(); - for (var i = 0; i < lookupCount; i++) - { - chunk._namedSubChunkLookup.Add( - br.ReadString(), - br.ReadInt32() - ); - } + chunk._subChunks.Add(subChunk); + subChunk.Parent = chunk; } - - if (flags.HasFlag(ChunkFlags.HasLocals)) + + var lookupCount = br.ReadInt32(); + for (var i = 0; i < lookupCount; i++) { - chunk.LocalCount = br.ReadInt32(); + chunk._namedSubChunkLookup.Add( + br.ReadString(), + br.ReadInt32() + ); } + } - if (flags.HasFlag(ChunkFlags.HasLabels)) - { - var labelCount = br.ReadInt32(); - for (var i = 0; i < labelCount; i++) - { - chunk._labels.Add(br.ReadInt32()); - } - } + if (flags.HasFlag(ChunkFlags.HasLocals)) + { + chunk.LocalCount = br.ReadInt32(); + } - if (flags.HasFlag(ChunkFlags.HasAttributes)) + if (flags.HasFlag(ChunkFlags.HasLabels)) + { + var labelCount = br.ReadInt32(); + for (var i = 0; i < labelCount; i++) { - var attrCount = br.ReadInt32(); - - for (var i = 0; i < attrCount; i++) - { - chunk._attributes.Add(ReadAttribute(br)); - } + chunk._labels.Add(br.ReadInt32()); } + } - 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.HasAttributes)) + { + var attrCount = br.ReadInt32(); - if (flags.HasFlag(ChunkFlags.HasDebugInfo)) + for (var i = 0; i < attrCount; i++) { - chunk.DebugDatabase.Deserialize(br); + chunk._attributes.Add(ReadAttribute(br)); } + } + + if (flags.HasFlag(ChunkFlags.HasProtectedBlocks)) + { + var blockCount = br.ReadInt32(); - var stringPoolLength = br.ReadInt32(); - for (var i = 0; i < stringPoolLength; i++) + for (var i = 0; i < blockCount; i++) { - chunk.StringPool.FetchOrAdd(br.ReadString()); + chunk._protectedBlocks.Add(ReadProtectedBlock(br)); } + } - var codeAreaLength = br.ReadInt32(); - var code = br.ReadBytes(codeAreaLength); + if (flags.HasFlag(ChunkFlags.HasDebugInfo)) + { + chunk.DebugDatabase.Deserialize(br); + } - var md5sum = br.ReadBytes(16); - using (var md5 = MD5.Create()) - { - var sum = md5.ComputeHash(code); + var stringPoolLength = br.ReadInt32(); + for (var i = 0; i < stringPoolLength; i++) + { + chunk.StringPool.FetchOrAdd(br.ReadString()); + } + + var codeAreaLength = br.ReadInt32(); + var code = br.ReadBytes(codeAreaLength); + + var md5sum = br.ReadBytes(16); + using (var md5 = MD5.Create()) + { + var sum = md5.ComputeHash(code); - if (!md5sum.SequenceEqual(sum)) - { - throw new ChunkDeserializationException("Code area checksum mismatch."); - } + if (!md5sum.SequenceEqual(sum)) + { + throw new ChunkDeserializationException("Code area checksum mismatch."); } - - chunk._code.Write(code); - chunk._code.Seek(0, SeekOrigin.Begin); } - - return chunk; + + chunk._code.Write(code); + chunk._code.Seek(0, SeekOrigin.Begin); } + + return chunk; } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Chunk.Serializer.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Chunk.Serializer.cs index 9f2fcdd0..5e0d788e 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Chunk.Serializer.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Chunk.Serializer.cs @@ -1,240 +1,239 @@ -using System; +namespace EVIL.Ceres.ExecutionEngine.Diagnostics; + +using System; using System.IO; using System.Security.Cryptography; using System.Text; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine.Diagnostics +public sealed partial class Chunk { - public sealed partial class Chunk + private class Serializer { - private class Serializer - { - private readonly Chunk _chunk; + private readonly Chunk _chunk; - public Serializer(Chunk chunk) - { - _chunk = chunk; - } + public Serializer(Chunk chunk) + { + _chunk = chunk; + } - private void WriteHeader(BinaryWriter bw) + private void WriteHeader(BinaryWriter bw) + { + bw.Write(new[] { - bw.Write(new[] - { - (byte)'E', - (byte)'V', - (byte)'C', - (byte)0x06, - FormatVersion - }); - - bw.Write(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()); - bw.Write((int)_chunk.Flags); - } + (byte)'E', + (byte)'V', + (byte)'C', + (byte)0x06, + FormatVersion + }); + + bw.Write(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()); + bw.Write((int)_chunk.Flags); + } - private void WriteConstValue(BinaryWriter bw, DynamicValue value) + private void WriteConstValue(BinaryWriter bw, DynamicValue value) + { + bw.Write((byte)value.Type); + switch (value.Type) { - bw.Write((byte)value.Type); - switch (value.Type) - { - case DynamicValueType.Nil: - break; + case DynamicValueType.Nil: + break; - case DynamicValueType.Number: - bw.Write(value.Number); - break; + case DynamicValueType.Number: + bw.Write(value.Number); + break; - case DynamicValueType.String: - bw.Write(value.String!); - break; + case DynamicValueType.String: + bw.Write(value.String!); + break; - case DynamicValueType.Boolean: - bw.Write(value.Boolean); - break; + case DynamicValueType.Boolean: + bw.Write(value.Boolean); + break; - case DynamicValueType.TypeCode: - bw.Write((byte)value.TypeCode); - break; + case DynamicValueType.TypeCode: + bw.Write((byte)value.TypeCode); + break; - default: throw new InvalidOperationException("Invalid constant value type."); - } + default: throw new InvalidOperationException("Invalid constant value type."); } + } - private void WriteAttribute(BinaryWriter bw, ChunkAttribute attribute) - { - bw.Write(attribute.Name); - - bw.Write(attribute.Values.Count); - foreach (var value in attribute.Values) - { - WriteConstValue(bw, value); - } + private void WriteAttribute(BinaryWriter bw, ChunkAttribute attribute) + { + bw.Write(attribute.Name); - bw.Write(attribute.Properties.Count); - foreach (var property in attribute.Properties) - { - bw.Write(property.Key); - WriteConstValue(bw, property.Value); - } + bw.Write(attribute.Values.Count); + foreach (var value in attribute.Values) + { + WriteConstValue(bw, value); } - private void WriteName(BinaryWriter bw) - => bw.Write(_chunk.Name); - - private void WriteParameterInfo(BinaryWriter bw) + bw.Write(attribute.Properties.Count); + foreach (var property in attribute.Properties) { - if (_chunk.Flags.HasFlag(ChunkFlags.HasParameters)) - { - bw.Write(_chunk.ParameterCount); - } + bw.Write(property.Key); + WriteConstValue(bw, property.Value); + } + } - if (_chunk.Flags.HasFlag(ChunkFlags.HasParameterInitializers)) - { - bw.Write(_chunk.ParameterInitializers.Count); + private void WriteName(BinaryWriter bw) + => bw.Write(_chunk.Name); - foreach (var kvp in _chunk.ParameterInitializers) - { - bw.Write(kvp.Key); - WriteConstValue(bw, kvp.Value); - } - } + private void WriteParameterInfo(BinaryWriter bw) + { + if (_chunk.Flags.HasFlag(ChunkFlags.HasParameters)) + { + bw.Write(_chunk.ParameterCount); } - private void WriteClosureInfo(BinaryWriter bw) + if (_chunk.Flags.HasFlag(ChunkFlags.HasParameterInitializers)) { - if (_chunk.Flags.HasFlag(ChunkFlags.HasClosures)) + bw.Write(_chunk.ParameterInitializers.Count); + + foreach (var kvp in _chunk.ParameterInitializers) { - bw.Write(_chunk.ClosureCount); - - for (var i = 0; i < _chunk.ClosureCount; i++) - { - var closure = _chunk.Closures[i]; - - bw.Write(closure.NestingLevel); - bw.Write(closure.EnclosedId); - bw.Write(closure.EnclosedFunctionName); - bw.Write(closure.IsParameter); - bw.Write(closure.IsClosure); - bw.Write(closure.IsSharedScope); - } + bw.Write(kvp.Key); + WriteConstValue(bw, kvp.Value); } } + } - private void WriteSubChunks(BinaryWriter bw) + private void WriteClosureInfo(BinaryWriter bw) + { + if (_chunk.Flags.HasFlag(ChunkFlags.HasClosures)) { - if (_chunk.Flags.HasFlag(ChunkFlags.HasSubChunks)) - { - bw.Write(_chunk.SubChunkCount); - for (var i = 0; i < _chunk.SubChunkCount; i++) - { - var subChunk = _chunk.SubChunks[i]; - subChunk.Serialize(bw.BaseStream); - } - - bw.Write(_chunk.NamedSubChunkLookup.Count); - foreach (var (name, id) in _chunk.NamedSubChunkLookup) - { - bw.Write(name); - bw.Write(id); - } - } - } + bw.Write(_chunk.ClosureCount); - private void WriteLocalInfo(BinaryWriter bw) - { - if (_chunk.Flags.HasFlag(ChunkFlags.HasLocals)) + for (var i = 0; i < _chunk.ClosureCount; i++) { - bw.Write(_chunk.LocalCount); + var closure = _chunk.Closures[i]; + + bw.Write(closure.NestingLevel); + bw.Write(closure.EnclosedId); + bw.Write(closure.EnclosedFunctionName); + bw.Write(closure.IsParameter); + bw.Write(closure.IsClosure); + bw.Write(closure.IsSharedScope); } } + } - private void WriteLabelInfo(BinaryWriter bw) - { - if (_chunk.Flags.HasFlag(ChunkFlags.HasLabels)) + private void WriteSubChunks(BinaryWriter bw) + { + if (_chunk.Flags.HasFlag(ChunkFlags.HasSubChunks)) + { + bw.Write(_chunk.SubChunkCount); + for (var i = 0; i < _chunk.SubChunkCount; i++) { - bw.Write(_chunk.Labels.Count); - foreach (var label in _chunk.Labels) - { - bw.Write(label); - } + var subChunk = _chunk.SubChunks[i]; + subChunk.Serialize(bw.BaseStream); } + + bw.Write(_chunk.NamedSubChunkLookup.Count); + foreach (var (name, id) in _chunk.NamedSubChunkLookup) + { + bw.Write(name); + bw.Write(id); + } } + } - private void WriteChunkAttributes(BinaryWriter bw) + private void WriteLocalInfo(BinaryWriter bw) + { + if (_chunk.Flags.HasFlag(ChunkFlags.HasLocals)) { - if (_chunk.Flags.HasFlag(ChunkFlags.HasAttributes)) - { - bw.Write(_chunk.Attributes.Count); - - foreach (var attr in _chunk.Attributes) - { - WriteAttribute(bw, attr); - } - } + bw.Write(_chunk.LocalCount); } + } - private void WriteProtectionInformation(BinaryWriter bw) + private void WriteLabelInfo(BinaryWriter bw) + { + if (_chunk.Flags.HasFlag(ChunkFlags.HasLabels)) { - if (_chunk.Flags.HasFlag(ChunkFlags.HasProtectedBlocks)) + bw.Write(_chunk.Labels.Count); + foreach (var label in _chunk.Labels) { - bw.Write(_chunk.ProtectedBlocks.Count); - - foreach (var block in _chunk.ProtectedBlocks) - { - bw.Write(block.StartAddress); - bw.Write(block.Length); - bw.Write(block.HandlerAddress); - } + bw.Write(label); } } + } - private void WriteDebugDatabase(BinaryWriter bw) + private void WriteChunkAttributes(BinaryWriter bw) + { + if (_chunk.Flags.HasFlag(ChunkFlags.HasAttributes)) { - if (_chunk.Flags.HasFlag(ChunkFlags.HasDebugInfo)) + bw.Write(_chunk.Attributes.Count); + + foreach (var attr in _chunk.Attributes) { - _chunk.DebugDatabase.Serialize(bw); + WriteAttribute(bw, attr); } } + } - private void WriteStringPool(BinaryWriter bw) + private void WriteProtectionInformation(BinaryWriter bw) + { + if (_chunk.Flags.HasFlag(ChunkFlags.HasProtectedBlocks)) { - bw.Write(_chunk.StringPool.Count); + bw.Write(_chunk.ProtectedBlocks.Count); - foreach (var str in _chunk.StringPool.ToArray()) + foreach (var block in _chunk.ProtectedBlocks) { - bw.Write(str); + bw.Write(block.StartAddress); + bw.Write(block.Length); + bw.Write(block.HandlerAddress); } } + } - private void WriteCodeArea(BinaryWriter bw) + private void WriteDebugDatabase(BinaryWriter bw) + { + if (_chunk.Flags.HasFlag(ChunkFlags.HasDebugInfo)) { - bw.Write(_chunk.Code.Length); - bw.Write(_chunk.Code); + _chunk.DebugDatabase.Serialize(bw); + } + } - using (var md5 = MD5.Create()) - { - bw.Write(md5.ComputeHash(_chunk.Code)); - } + private void WriteStringPool(BinaryWriter bw) + { + bw.Write(_chunk.StringPool.Count); + + foreach (var str in _chunk.StringPool.ToArray()) + { + bw.Write(str); + } + } + + private void WriteCodeArea(BinaryWriter bw) + { + bw.Write(_chunk.Code.Length); + bw.Write(_chunk.Code); + + using (var md5 = MD5.Create()) + { + bw.Write(md5.ComputeHash(_chunk.Code)); } + } - public void Write(Stream stream) + public void Write(Stream stream) + { + using (var bw = new BinaryWriter(stream, Encoding.UTF8, true)) { - using (var bw = new BinaryWriter(stream, Encoding.UTF8, true)) - { - WriteHeader(bw); - WriteName(bw); - WriteParameterInfo(bw); - WriteClosureInfo(bw); - WriteSubChunks(bw); - WriteLocalInfo(bw); - WriteLabelInfo(bw); - WriteChunkAttributes(bw); - WriteProtectionInformation(bw); - WriteDebugDatabase(bw); - WriteStringPool(bw); - WriteCodeArea(bw); - } + WriteHeader(bw); + WriteName(bw); + WriteParameterInfo(bw); + WriteClosureInfo(bw); + WriteSubChunks(bw); + WriteLocalInfo(bw); + WriteLabelInfo(bw); + WriteChunkAttributes(bw); + WriteProtectionInformation(bw); + WriteDebugDatabase(bw); + WriteStringPool(bw); + WriteCodeArea(bw); } } } diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Chunk.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Chunk.cs index fa09a479..9a5b1ef8 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Chunk.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Chunk.cs @@ -1,3 +1,5 @@ +namespace EVIL.Ceres.ExecutionEngine.Diagnostics; + using System; using System.Collections.Generic; using System.IO; @@ -7,449 +9,446 @@ using EVIL.Ceres.ExecutionEngine.Diagnostics.Debugging; using EVIL.Ceres.ExecutionEngine.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine.Diagnostics +public sealed partial class Chunk : IDisposable, IEquatable { - public sealed partial class Chunk : IDisposable, IEquatable + private readonly MemoryStream _code; + private List _labels; + private List _attributes; + private Dictionary _parameterInitializers; + private List _closures; + private Dictionary _closureContexts; + private List _subChunks; + private Dictionary _namedSubChunkLookup; + private List _protectedBlocks; + + private readonly Serializer _serializer; + + public const byte FormatVersion = 3; + + public string Name { get; set; } + public Chunk? Parent { get; private set; } + + public StringPool StringPool { get; } + public CodeGenerator CodeGenerator { get; } + public DebugDatabase DebugDatabase { get; private set; } + + public int ParameterCount { get; private set; } + public int LocalCount { get; private set; } + public int ClosureCount => Closures.Count; + public int SubChunkCount => SubChunks.Count; + public bool IsSelfAware { get; private set; } + public bool IsSpecialName { get; private set; } + public bool MayThrow { get; private set; } + + public IReadOnlyList Labels => _labels; + public IReadOnlyList Attributes => _attributes; + public IReadOnlyDictionary ParameterInitializers => _parameterInitializers; + public IReadOnlyList Closures => _closures; + public IReadOnlyDictionary ClosureContexts => _closureContexts; + public IReadOnlyList SubChunks => _subChunks; + public IReadOnlyDictionary NamedSubChunkLookup => _namedSubChunkLookup; + public IReadOnlyList ProtectedBlocks => _protectedBlocks; + + public byte[] Code => _code.GetBuffer(); + + public bool HasParameters => Flags.HasFlag(ChunkFlags.HasParameters); + public bool HasLocals => Flags.HasFlag(ChunkFlags.HasLocals); + public bool HasAttributes => Flags.HasFlag(ChunkFlags.HasAttributes); + public bool HasDebugInfo => Flags.HasFlag(ChunkFlags.HasDebugInfo); + public bool HasClosures => Flags.HasFlag(ChunkFlags.HasClosures); + public bool HasSubChunks => Flags.HasFlag(ChunkFlags.HasSubChunks); + public bool IsSubChunk => Flags.HasFlag(ChunkFlags.IsSubChunk); + + public Chunk? this[string name] { - private readonly MemoryStream _code; - private List _labels; - private List _attributes; - private Dictionary _parameterInitializers; - private List _closures; - private Dictionary _closureContexts; - private List _subChunks; - private Dictionary _namedSubChunkLookup; - private List _protectedBlocks; - - private readonly Serializer _serializer; - - public const byte FormatVersion = 3; - - public string Name { get; set; } - public Chunk? Parent { get; private set; } - - public StringPool StringPool { get; } - public CodeGenerator CodeGenerator { get; } - public DebugDatabase DebugDatabase { get; private set; } - - public int ParameterCount { get; private set; } - public int LocalCount { get; private set; } - public int ClosureCount => Closures.Count; - public int SubChunkCount => SubChunks.Count; - public bool IsSelfAware { get; private set; } - public bool IsSpecialName { get; private set; } - public bool MayThrow { get; private set; } - - public IReadOnlyList Labels => _labels; - public IReadOnlyList Attributes => _attributes; - public IReadOnlyDictionary ParameterInitializers => _parameterInitializers; - public IReadOnlyList Closures => _closures; - public IReadOnlyDictionary ClosureContexts => _closureContexts; - public IReadOnlyList SubChunks => _subChunks; - public IReadOnlyDictionary NamedSubChunkLookup => _namedSubChunkLookup; - public IReadOnlyList ProtectedBlocks => _protectedBlocks; - - public byte[] Code => _code.GetBuffer(); - - public bool HasParameters => Flags.HasFlag(ChunkFlags.HasParameters); - public bool HasLocals => Flags.HasFlag(ChunkFlags.HasLocals); - public bool HasAttributes => Flags.HasFlag(ChunkFlags.HasAttributes); - public bool HasDebugInfo => Flags.HasFlag(ChunkFlags.HasDebugInfo); - public bool HasClosures => Flags.HasFlag(ChunkFlags.HasClosures); - public bool HasSubChunks => Flags.HasFlag(ChunkFlags.HasSubChunks); - public bool IsSubChunk => Flags.HasFlag(ChunkFlags.IsSubChunk); - - public Chunk? this[string name] + get { - get + if (_namedSubChunkLookup.TryGetValue(name, out var id)) { - if (_namedSubChunkLookup.TryGetValue(name, out var id)) - { - return _subChunks[id]; - } - - return null; + return _subChunks[id]; } + + return null; } + } - public ChunkFlags Flags + public ChunkFlags Flags + { + get { - get - { - var ret = ChunkFlags.Empty; + var ret = ChunkFlags.Empty; - if (ParameterCount > 0) - ret |= ChunkFlags.HasParameters; + if (ParameterCount > 0) + ret |= ChunkFlags.HasParameters; - if (ParameterInitializers.Count > 0) - ret |= ChunkFlags.HasParameterInitializers; + if (ParameterInitializers.Count > 0) + ret |= ChunkFlags.HasParameterInitializers; - if (LocalCount > 0) - ret |= ChunkFlags.HasLocals; + if (LocalCount > 0) + ret |= ChunkFlags.HasLocals; - if (Attributes.Count > 0) - ret |= ChunkFlags.HasAttributes; + if (Attributes.Count > 0) + ret |= ChunkFlags.HasAttributes; - if (Labels.Count > 0) - ret |= ChunkFlags.HasLabels; + if (Labels.Count > 0) + ret |= ChunkFlags.HasLabels; - if (!DebugDatabase.IsEmpty) - ret |= ChunkFlags.HasDebugInfo; + if (!DebugDatabase.IsEmpty) + ret |= ChunkFlags.HasDebugInfo; - if (ClosureCount > 0) - ret |= ChunkFlags.HasClosures; + if (ClosureCount > 0) + ret |= ChunkFlags.HasClosures; - if (SubChunkCount > 0) - ret |= ChunkFlags.HasSubChunks; + if (SubChunkCount > 0) + ret |= ChunkFlags.HasSubChunks; - if (Parent != null) - ret |= ChunkFlags.IsSubChunk; + if (Parent != null) + ret |= ChunkFlags.IsSubChunk; - if (IsSelfAware) - ret |= ChunkFlags.IsSelfAware; + if (IsSelfAware) + ret |= ChunkFlags.IsSelfAware; - if (IsSpecialName) - ret |= ChunkFlags.IsSpecialName; + if (IsSpecialName) + ret |= ChunkFlags.IsSpecialName; - if (ProtectedBlocks.Count > 0) - ret |= ChunkFlags.HasProtectedBlocks; + if (ProtectedBlocks.Count > 0) + ret |= ChunkFlags.HasProtectedBlocks; - if (MayThrow) - ret |= ChunkFlags.MayThrow; + if (MayThrow) + ret |= ChunkFlags.MayThrow; - return ret; - } + return ret; } + } - public Chunk(string name) - { - _code = new MemoryStream(0); - _labels = new List(); - _attributes = new List(); - _parameterInitializers = new Dictionary(); - _closures = new List(); - _closureContexts = new Dictionary(); - _subChunks = new List(); - _namedSubChunkLookup = new Dictionary(); - _protectedBlocks = new List(); - _serializer = new Serializer(this); - - Name = name; - StringPool = new StringPool(); - CodeGenerator = new CodeGenerator(_code, _labels); - DebugDatabase = new DebugDatabase(); - } + public Chunk(string name) + { + _code = new MemoryStream(0); + _labels = new List(); + _attributes = new List(); + _parameterInitializers = new Dictionary(); + _closures = new List(); + _closureContexts = new Dictionary(); + _subChunks = new List(); + _namedSubChunkLookup = new Dictionary(); + _protectedBlocks = new List(); + _serializer = new Serializer(this); + + Name = name; + StringPool = new StringPool(); + CodeGenerator = new CodeGenerator(_code, _labels); + DebugDatabase = new DebugDatabase(); + } - public Chunk(string name, byte[] code) - { - _code = new MemoryStream(code, 0, code.Length, true, true); - _labels = new List(); - _attributes = new List(); - _parameterInitializers = new Dictionary(); - _closures = new List(); - _closureContexts = new Dictionary(); - _subChunks = new List(); - _namedSubChunkLookup = new Dictionary(); - _protectedBlocks = new List(); - _serializer = new Serializer(this); - - Name = name; - StringPool = new StringPool(); - CodeGenerator = new CodeGenerator(_code, _labels); - DebugDatabase = new DebugDatabase(); - } + public Chunk(string name, byte[] code) + { + _code = new MemoryStream(code, 0, code.Length, true, true); + _labels = new List(); + _attributes = new List(); + _parameterInitializers = new Dictionary(); + _closures = new List(); + _closureContexts = new Dictionary(); + _subChunks = new List(); + _namedSubChunkLookup = new Dictionary(); + _protectedBlocks = new List(); + _serializer = new Serializer(this); + + Name = name; + StringPool = new StringPool(); + CodeGenerator = new CodeGenerator(_code, _labels); + DebugDatabase = new DebugDatabase(); + } - public Chunk(string name, byte[] code, string[] stringConstants) - { - _code = new MemoryStream(code, 0, code.Length, true, true); - _labels = new List(); - _attributes = new List(); - _parameterInitializers = new Dictionary(); - _closures = new List(); - _closureContexts = new Dictionary(); - _subChunks = new List(); - _namedSubChunkLookup = new Dictionary(); - _protectedBlocks = new List(); - _serializer = new Serializer(this); - - Name = name; - StringPool = new StringPool(stringConstants); - CodeGenerator = new CodeGenerator(_code, _labels); - DebugDatabase = new DebugDatabase(); - } + public Chunk(string name, byte[] code, string[] stringConstants) + { + _code = new MemoryStream(code, 0, code.Length, true, true); + _labels = new List(); + _attributes = new List(); + _parameterInitializers = new Dictionary(); + _closures = new List(); + _closureContexts = new Dictionary(); + _subChunks = new List(); + _namedSubChunkLookup = new Dictionary(); + _protectedBlocks = new List(); + _serializer = new Serializer(this); + + Name = name; + StringPool = new StringPool(stringConstants); + CodeGenerator = new CodeGenerator(_code, _labels); + DebugDatabase = new DebugDatabase(); + } - public BinaryReader SpawnCodeReader() - { - return new BinaryReader( - new MemoryStream(_code.ToArray()), - Encoding.UTF8, - false - ); - } + public BinaryReader SpawnCodeReader() + { + return new BinaryReader( + new MemoryStream(_code.ToArray()), + Encoding.UTF8, + false + ); + } - public void MarkThrowing() - => MayThrow = true; + public void MarkThrowing() + => MayThrow = true; - public void MarkSelfAware() - => IsSelfAware = true; + public void MarkSelfAware() + => IsSelfAware = true; - public int AllocateParameter() - => ParameterCount++; + public int AllocateParameter() + => ParameterCount++; - public int AllocateLocal() - => LocalCount++; + public int AllocateLocal() + => LocalCount++; - public ClosureContext SetClosureContext(string chunkName) + public ClosureContext SetClosureContext(string chunkName) + { + if (!_closureContexts.TryGetValue(chunkName, out var value)) { - if (!_closureContexts.TryGetValue(chunkName, out var value)) - { - value = _closureContexts[chunkName] = new ClosureContext(chunkName); - } - - return value; + value = _closureContexts[chunkName] = new ClosureContext(chunkName); } - - public (int Id, ClosureInfo Closure) AllocateClosure(int nestingLevel, int enclosedId, string enclosedFunctionName, bool isParameter, bool isClosure, bool isSharedScope) - { - var id = ClosureCount; - var ret = new ClosureInfo( - nestingLevel, - enclosedId, - enclosedFunctionName, - isParameter, - isClosure, - isSharedScope - ); - _closures.Add(ret); + return value; + } + + public (int Id, ClosureInfo Closure) AllocateClosure(int nestingLevel, int enclosedId, string enclosedFunctionName, bool isParameter, bool isClosure, bool isSharedScope) + { + var id = ClosureCount; + var ret = new ClosureInfo( + nestingLevel, + enclosedId, + enclosedFunctionName, + isParameter, + isClosure, + isSharedScope + ); + + _closures.Add(ret); + + return (id, ret); + } - return (id, ret); - } + public (int Id, Chunk SubChunk) AllocateAnonymousSubChunk() + { + var id = SubChunkCount; - public (int Id, Chunk SubChunk) AllocateAnonymousSubChunk() + string BuildName() { - var id = SubChunkCount; + var list = new List(); - string BuildName() + if (Parent == null) { - var list = new List(); - - if (Parent == null) - { - return $"{Name}$?{id}"; - } - else - { - list.AddRange( - Name.Split('$') - .Where(x => !string.IsNullOrEmpty(x)) - ); - } - - list.Add($"?{id}"); - return string.Join("$", list); + return $"{Name}$?{id}"; } - - var chunk = new Chunk(BuildName()) + else { - IsSpecialName = true, - Parent = this - }; + list.AddRange( + Name.Split('$') + .Where(x => !string.IsNullOrEmpty(x)) + ); + } - _subChunks.Add(chunk); - return (id, chunk); + list.Add($"?{id}"); + return string.Join("$", list); } - - public (int Id, Chunk SubChunk) AllocateNamedSubChunk(string name, out bool wasReplaced, out Chunk replacedChunk) + + var chunk = new Chunk(BuildName()) { - var id = SubChunkCount; - wasReplaced = false; - replacedChunk = null!; + IsSpecialName = true, + Parent = this + }; + + _subChunks.Add(chunk); + return (id, chunk); + } + + public (int Id, Chunk SubChunk) AllocateNamedSubChunk(string name, out bool wasReplaced, out Chunk replacedChunk) + { + var id = SubChunkCount; + wasReplaced = false; + replacedChunk = null!; - var chunk = new Chunk(name) { Parent = this }; + var chunk = new Chunk(name) { Parent = this }; - if (_namedSubChunkLookup.TryGetValue(name, out var existingId)) - { - replacedChunk = _subChunks[existingId]; + if (_namedSubChunkLookup.TryGetValue(name, out var existingId)) + { + replacedChunk = _subChunks[existingId]; - _subChunks[existingId] = chunk; - wasReplaced = true; - } - else - { - _namedSubChunkLookup.Add(name, id); - _subChunks.Add(chunk); - } - - return (id, chunk); + _subChunks[existingId] = chunk; + wasReplaced = true; } - - public void InitializeParameter(int parameterId, DynamicValue constant) + else { - if (!_parameterInitializers.TryAdd(parameterId, constant)) - { - throw new InvalidOperationException( - $"Internal compiler error: Attempt to initialize the same parameter symbol twice." - ); - } + _namedSubChunkLookup.Add(name, id); + _subChunks.Add(chunk); } - public int CreateLabel() - => CreateLabel(CodeGenerator.IP); + return (id, chunk); + } - public int CreateLabel(int ip) + public void InitializeParameter(int parameterId, DynamicValue constant) + { + if (!_parameterInitializers.TryAdd(parameterId, constant)) { - _labels.Add(ip); - return _labels.Count - 1; + throw new InvalidOperationException( + $"Internal compiler error: Attempt to initialize the same parameter symbol twice." + ); } + } - public BlockProtectionInfo AllocateBlockProtector() - { - var info = new BlockProtectionInfo(); - _protectedBlocks.Add(info); - return info; - } + public int CreateLabel() + => CreateLabel(CodeGenerator.IP); - public void AddAttribute(ChunkAttribute attribute) - => _attributes.Add(attribute); + public int CreateLabel(int ip) + { + _labels.Add(ip); + return _labels.Count - 1; + } - public void UpdateLabel(int id, int ip) - => _labels[id] = ip; + public BlockProtectionInfo AllocateBlockProtector() + { + var info = new BlockProtectionInfo(); + _protectedBlocks.Add(info); + return info; + } - public ChunkAttribute[] GetAttributes(string name) - => _attributes.Where(x => x.Name == name).ToArray(); + public void AddAttribute(ChunkAttribute attribute) + => _attributes.Add(attribute); - public ChunkAttribute GetAttribute(string name) - => _attributes.First(x => x.Name == name); + public void UpdateLabel(int id, int ip) + => _labels[id] = ip; - public bool TryGetAttribute(string name, out ChunkAttribute value) - { - var ret = _attributes.FirstOrDefault(x => x.Name == name); - value = ret!; + public ChunkAttribute[] GetAttributes(string name) + => _attributes.Where(x => x.Name == name).ToArray(); - return ret != null; - } + public ChunkAttribute GetAttribute(string name) + => _attributes.First(x => x.Name == name); - public bool HasAttribute(string name) - => TryGetAttribute(name, out _); + public bool TryGetAttribute(string name, out ChunkAttribute value) + { + var ret = _attributes.FirstOrDefault(x => x.Name == name); + value = ret!; - public byte[] ComputeChecksum() - { - var bytes = new List(); - bytes.AddRange(_code.ToArray()); - foreach (var subChunk in _subChunks) - { - bytes.AddRange(subChunk.ComputeChecksum()); - } + return ret != null; + } - return SHA256.HashData(bytes.ToArray()); - } + public bool HasAttribute(string name) + => TryGetAttribute(name, out _); - public string ComputeChecksumString() + public byte[] ComputeChecksum() + { + var bytes = new List(); + bytes.AddRange(_code.ToArray()); + foreach (var subChunk in _subChunks) { - var bytes = ComputeChecksum(); - var sb = new StringBuilder(); - - foreach (var b in bytes) - { - sb.Append($"{b:X2}"); - } - - return sb.ToString(); + bytes.AddRange(subChunk.ComputeChecksum()); } - public void Serialize(Stream stream) - => _serializer.Write(stream); + return SHA256.HashData(bytes.ToArray()); + } - public static Chunk Deserialize(Stream stream, out byte version, out long timestamp) - => Deserializer.Deserialize(stream, out version, out timestamp); + public string ComputeChecksumString() + { + var bytes = ComputeChecksum(); + var sb = new StringBuilder(); - public Chunk Clone() + foreach (var b in bytes) { - var clone = new Chunk( - Name, - _code.ToArray(), - StringPool.ToArray() - ) - { - Parent = Parent, - Name = Name, - LocalCount = LocalCount, - ParameterCount = ParameterCount, - DebugDatabase = DebugDatabase, - IsSelfAware = IsSelfAware, - _subChunks = new(_subChunks), - _closures = new(_closures), - _closureContexts = new(_closureContexts), - _labels = new(_labels), - _attributes = new(_attributes), - _parameterInitializers = new(_parameterInitializers), - _protectedBlocks = new(_protectedBlocks) - }; - - return clone; + sb.Append($"{b:X2}"); } - public void Dispose() - { - _code.Dispose(); - CodeGenerator.Dispose(); - } + return sb.ToString(); + } - public bool Equals(Chunk? other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - - return Name == other.Name - && IsSelfAware == other.IsSelfAware - && ParameterCount == other.ParameterCount - && _parameterInitializers.SequenceEqual(other._parameterInitializers) - && LocalCount == other.LocalCount - && _closures.SequenceEqual(other._closures) - && _labels.SequenceEqual(other._labels) - && _attributes.SequenceEqual(other._attributes) - && _subChunks.SequenceEqual(other._subChunks) - && _namedSubChunkLookup.SequenceEqual(other._namedSubChunkLookup) - && _protectedBlocks.SequenceEqual(other._protectedBlocks) - && StringPool.Equals(other.StringPool) - && Code.SequenceEqual(other.Code) - && DebugDatabase.Equals(other.DebugDatabase); - } + public void Serialize(Stream stream) + => _serializer.Write(stream); - public override bool Equals(object? obj) - { - return ReferenceEquals(this, obj) - || obj is Chunk other && Equals(other); - } + public static Chunk Deserialize(Stream stream, out byte version, out long timestamp) + => Deserializer.Deserialize(stream, out version, out timestamp); - public override int GetHashCode() + public Chunk Clone() + { + var clone = new Chunk( + Name, + _code.ToArray(), + StringPool.ToArray() + ) { - var hashCode = new HashCode(); - - hashCode.Add(Name); - hashCode.Add(IsSelfAware); - hashCode.Add(ParameterCount); - hashCode.Add(_parameterInitializers); - hashCode.Add(LocalCount); - hashCode.Add(_closures); - hashCode.Add(_closureContexts); - hashCode.Add(_labels); - hashCode.Add(_attributes); - hashCode.Add(_subChunks); - hashCode.Add(_namedSubChunkLookup); - hashCode.Add(_protectedBlocks); - hashCode.Add(StringPool); - hashCode.Add(Code); - hashCode.Add(DebugDatabase); - - return hashCode.ToHashCode(); - } + Parent = Parent, + Name = Name, + LocalCount = LocalCount, + ParameterCount = ParameterCount, + DebugDatabase = DebugDatabase, + IsSelfAware = IsSelfAware, + _subChunks = new(_subChunks), + _closures = new(_closures), + _closureContexts = new(_closureContexts), + _labels = new(_labels), + _attributes = new(_attributes), + _parameterInitializers = new(_parameterInitializers), + _protectedBlocks = new(_protectedBlocks) + }; + + return clone; + } - public static bool operator ==(Chunk? left, Chunk? right) - => Equals(left, right); + public void Dispose() + { + _code.Dispose(); + CodeGenerator.Dispose(); + } - public static bool operator !=(Chunk? left, Chunk? right) - => !Equals(left, right); + public bool Equals(Chunk? other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + + return Name == other.Name + && IsSelfAware == other.IsSelfAware + && ParameterCount == other.ParameterCount + && _parameterInitializers.SequenceEqual(other._parameterInitializers) + && LocalCount == other.LocalCount + && _closures.SequenceEqual(other._closures) + && _labels.SequenceEqual(other._labels) + && _attributes.SequenceEqual(other._attributes) + && _subChunks.SequenceEqual(other._subChunks) + && _namedSubChunkLookup.SequenceEqual(other._namedSubChunkLookup) + && _protectedBlocks.SequenceEqual(other._protectedBlocks) + && StringPool.Equals(other.StringPool) + && Code.SequenceEqual(other.Code) + && DebugDatabase.Equals(other.DebugDatabase); } + + public override bool Equals(object? obj) + { + return ReferenceEquals(this, obj) + || obj is Chunk other && Equals(other); + } + + public override int GetHashCode() + { + var hashCode = new HashCode(); + + hashCode.Add(Name); + hashCode.Add(IsSelfAware); + hashCode.Add(ParameterCount); + hashCode.Add(_parameterInitializers); + hashCode.Add(LocalCount); + hashCode.Add(_closures); + hashCode.Add(_closureContexts); + hashCode.Add(_labels); + hashCode.Add(_attributes); + hashCode.Add(_subChunks); + hashCode.Add(_namedSubChunkLookup); + hashCode.Add(_protectedBlocks); + hashCode.Add(StringPool); + hashCode.Add(Code); + hashCode.Add(DebugDatabase); + + return hashCode.ToHashCode(); + } + + public static bool operator ==(Chunk? left, Chunk? right) + => Equals(left, right); + + public static bool operator !=(Chunk? left, Chunk? right) + => !Equals(left, right); } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ChunkAttribute.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ChunkAttribute.cs index 80683c37..26f8c5ff 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ChunkAttribute.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ChunkAttribute.cs @@ -1,83 +1,82 @@ -using System; +namespace EVIL.Ceres.ExecutionEngine.Diagnostics; + +using System; using System.Collections.Generic; using System.Linq; using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.Marshaling; using EVIL.Ceres.ExecutionEngine.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine.Diagnostics +public sealed record ChunkAttribute : IDynamicValueProvider { - public sealed record ChunkAttribute : IDynamicValueProvider - { - public string Name { get; } + public string Name { get; } - public List Values { get; } = new(); - public Dictionary Properties { get; } = new(); + public List Values { get; } = new(); + public Dictionary Properties { get; } = new(); - public DynamicValue this[int valueIndex] + public DynamicValue this[int valueIndex] + { + get { - get + if (valueIndex < 0 || valueIndex >= Values.Count) { - if (valueIndex < 0 || valueIndex >= Values.Count) - { - return DynamicValue.Nil; - } - - return Values[valueIndex]; + return DynamicValue.Nil; } + + return Values[valueIndex]; } + } - public DynamicValue this[string propertyKey] + public DynamicValue this[string propertyKey] + { + get { - get + if (Properties.TryGetValue(propertyKey, out var value)) { - if (Properties.TryGetValue(propertyKey, out var value)) - { - return value; - } - - return DynamicValue.Nil; + return value; } - } - public ChunkAttribute(string name) - { - Name = name; + return DynamicValue.Nil; } + } - public bool Equals(ChunkAttribute? other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; + public ChunkAttribute(string name) + { + Name = name; + } - return Name == other.Name - && Values.SequenceEqual(other.Values) - && Properties.SequenceEqual(other.Properties); - } + public bool Equals(ChunkAttribute? other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; - public override int GetHashCode() - => HashCode.Combine(Name, Values, Properties); + return Name == other.Name + && Values.SequenceEqual(other.Values) + && Properties.SequenceEqual(other.Properties); + } - public DynamicValue ToDynamicValue() - { - var values = new Table(); - for (var i = 0; i < Values.Count; i++) - { - values[i] = Values[i]; - } + public override int GetHashCode() + => HashCode.Combine(Name, Values, Properties); - var properties = new Table(); - foreach (var kvp in Properties) - { - properties[kvp.Key] = kvp.Value; - } + public DynamicValue ToDynamicValue() + { + var values = new Table(); + for (var i = 0; i < Values.Count; i++) + { + values[i] = Values[i]; + } - return new Table - { - { "name", Name }, - { "values", values }, - { "properties", properties } - }; + var properties = new Table(); + foreach (var kvp in Properties) + { + properties[kvp.Key] = kvp.Value; } + + return new Table + { + { "name", Name }, + { "values", values }, + { "properties", properties } + }; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ChunkFlags.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ChunkFlags.cs index d5ee6919..4fe1c803 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ChunkFlags.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ChunkFlags.cs @@ -1,23 +1,22 @@ -using System; +namespace EVIL.Ceres.ExecutionEngine.Diagnostics; -namespace EVIL.Ceres.ExecutionEngine.Diagnostics +using System; + +[Flags] +public enum ChunkFlags { - [Flags] - public enum ChunkFlags - { - Empty = 0, - HasParameters = 1 << 0, - HasParameterInitializers = 1 << 1, - HasLocals = 1 << 2, - HasLabels = 1 << 3, - HasAttributes = 1 << 4, - HasDebugInfo = 1 << 5, - HasClosures = 1 << 6, - HasSubChunks = 1 << 7, - IsSubChunk = 1 << 8, - IsSelfAware = 1 << 9, - IsSpecialName = 1 << 10, - HasProtectedBlocks = 1 << 11, - MayThrow = 1 << 12 - } + Empty = 0, + HasParameters = 1 << 0, + HasParameterInitializers = 1 << 1, + HasLocals = 1 << 2, + HasLabels = 1 << 3, + HasAttributes = 1 << 4, + HasDebugInfo = 1 << 5, + HasClosures = 1 << 6, + HasSubChunks = 1 << 7, + IsSubChunk = 1 << 8, + IsSelfAware = 1 << 9, + IsSpecialName = 1 << 10, + HasProtectedBlocks = 1 << 11, + MayThrow = 1 << 12 } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ClosureContext.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ClosureContext.cs index 10ecd098..dfb9258b 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ClosureContext.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ClosureContext.cs @@ -1,16 +1,15 @@ +namespace EVIL.Ceres.ExecutionEngine.Diagnostics; + using System.Collections.Generic; using EVIL.Ceres.ExecutionEngine.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine.Diagnostics +public class ClosureContext { - public class ClosureContext - { - public string EnclosedFunctionName { get; } - public Dictionary Values { get; } = new(); + public string EnclosedFunctionName { get; } + public Dictionary Values { get; } = new(); - public ClosureContext(string enclosedFunctionName) - { - EnclosedFunctionName = enclosedFunctionName; - } + public ClosureContext(string enclosedFunctionName) + { + EnclosedFunctionName = enclosedFunctionName; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ClosureInfo.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ClosureInfo.cs index 27d068e3..b1a4604e 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ClosureInfo.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ClosureInfo.cs @@ -1,52 +1,51 @@ +namespace EVIL.Ceres.ExecutionEngine.Diagnostics; + using System; -namespace EVIL.Ceres.ExecutionEngine.Diagnostics +public record ClosureInfo { - public record ClosureInfo - { - public int NestingLevel { get; } - public int EnclosedId { get; } - public string EnclosedFunctionName { get; } + public int NestingLevel { get; } + public int EnclosedId { get; } + public string EnclosedFunctionName { get; } - public bool IsParameter { get; } - public bool IsClosure { get; } + public bool IsParameter { get; } + public bool IsClosure { get; } - public bool IsSharedScope { get; } + public bool IsSharedScope { get; } - internal ClosureInfo( - int nestingLevel, - int enclosedId, - string enclosedFunctionName, - bool isParameter, - bool isClosure, - bool isSharedScope) - { - NestingLevel = nestingLevel; - EnclosedId = enclosedId; - EnclosedFunctionName = enclosedFunctionName; - IsParameter = isParameter; - IsClosure = isClosure; - IsSharedScope = isSharedScope; - } - - public virtual bool Equals(ClosureInfo? other) - { - return NestingLevel == other?.NestingLevel - && EnclosedId == other.EnclosedId - && EnclosedFunctionName == other.EnclosedFunctionName - && IsParameter == other.IsParameter - && IsClosure == other.IsClosure - && IsSharedScope == other.IsSharedScope; - } + internal ClosureInfo( + int nestingLevel, + int enclosedId, + string enclosedFunctionName, + bool isParameter, + bool isClosure, + bool isSharedScope) + { + NestingLevel = nestingLevel; + EnclosedId = enclosedId; + EnclosedFunctionName = enclosedFunctionName; + IsParameter = isParameter; + IsClosure = isClosure; + IsSharedScope = isSharedScope; + } - public override int GetHashCode() - => HashCode.Combine( - NestingLevel, - EnclosedId, - EnclosedFunctionName, - IsParameter, - IsClosure, - IsSharedScope - ); + public virtual bool Equals(ClosureInfo? other) + { + return NestingLevel == other?.NestingLevel + && EnclosedId == other.EnclosedId + && EnclosedFunctionName == other.EnclosedFunctionName + && IsParameter == other.IsParameter + && IsClosure == other.IsClosure + && IsSharedScope == other.IsSharedScope; } + + public override int GetHashCode() + => HashCode.Combine( + NestingLevel, + EnclosedId, + EnclosedFunctionName, + IsParameter, + IsClosure, + IsSharedScope + ); } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/CodeGenerator.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/CodeGenerator.cs index 7fdf9813..726dc605 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/CodeGenerator.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/CodeGenerator.cs @@ -1,132 +1,131 @@ +namespace EVIL.Ceres.ExecutionEngine; + using System; using System.Collections.Generic; using System.IO; using System.Text; using EVIL.Ceres.ExecutionEngine.Diagnostics; -namespace EVIL.Ceres.ExecutionEngine +public sealed class CodeGenerator : IDisposable { - public sealed class CodeGenerator : IDisposable - { - private readonly MemoryStream _code; - private readonly BinaryWriter _writer; - private readonly List _labels; - private readonly Stack _opCodeAddresses; + private readonly MemoryStream _code; + private readonly BinaryWriter _writer; + private readonly List _labels; + private readonly Stack _opCodeAddresses; - public Action? OpCodeEmitted { get; set; } + public Action? OpCodeEmitted { get; set; } - public int IP - { - get => (int)_code.Position; - set => _code.Seek(value, SeekOrigin.Begin); - } + public int IP + { + get => (int)_code.Position; + set => _code.Seek(value, SeekOrigin.Begin); + } - public IReadOnlyList Labels => _labels; - public IReadOnlyCollection OpCodeAddresses => _opCodeAddresses; + public IReadOnlyList Labels => _labels; + public IReadOnlyCollection OpCodeAddresses => _opCodeAddresses; - internal CodeGenerator(MemoryStream code, List labels) - { - _code = code; - _labels = labels; - _opCodeAddresses = new(); + internal CodeGenerator(MemoryStream code, List labels) + { + _code = code; + _labels = labels; + _opCodeAddresses = new(); - _writer = new BinaryWriter(_code, Encoding.UTF8, true); - } - - public OpCode PeekOpCode() - { - if (_code.Length == 0 || _opCodeAddresses.Count == 0) - { - throw new InvalidOperationException("Chunk contains no instructions."); - } - - var position = _code.Position; - _code.Seek(_opCodeAddresses.Peek(), SeekOrigin.Begin); - var opCode = (OpCode)_code.ReadByte(); - _code.Seek(position, SeekOrigin.Begin); - return opCode; - } + _writer = new BinaryWriter(_code, Encoding.UTF8, true); + } - public bool TryPeekOpCode(out OpCode? opCode) + public OpCode PeekOpCode() + { + if (_code.Length == 0 || _opCodeAddresses.Count == 0) { - opCode = null; - - try - { - opCode = PeekOpCode(); - return true; - } - catch - { - return false; - } + throw new InvalidOperationException("Chunk contains no instructions."); } - public void Emit(OpCode value) - { - _opCodeAddresses.Push(IP); - _writer.Write((byte)value); + var position = _code.Position; + _code.Seek(_opCodeAddresses.Peek(), SeekOrigin.Begin); + var opCode = (OpCode)_code.ReadByte(); + _code.Seek(position, SeekOrigin.Begin); + return opCode; + } - OpCodeEmitted?.Invoke(_opCodeAddresses.Peek(), value); - } + public bool TryPeekOpCode(out OpCode? opCode) + { + opCode = null; - public void Emit(OpCode value, double operand) + try { - Emit(value); - Emit(operand); + opCode = PeekOpCode(); + return true; } - - public void Emit(OpCode value, long operand) + catch { - Emit(value); - Emit(operand); + return false; } + } + + public void Emit(OpCode value) + { + _opCodeAddresses.Push(IP); + _writer.Write((byte)value); + + OpCodeEmitted?.Invoke(_opCodeAddresses.Peek(), value); + } + + public void Emit(OpCode value, double operand) + { + Emit(value); + Emit(operand); + } + + public void Emit(OpCode value, long operand) + { + Emit(value); + Emit(operand); + } - public void Emit(OpCode value, int operand) - { - Emit(value); - Emit(operand); - } + public void Emit(OpCode value, int operand) + { + Emit(value); + Emit(operand); + } - public void Emit(OpCode value, byte operand) - { - Emit(value); - Emit(operand); - } + public void Emit(OpCode value, byte operand) + { + Emit(value); + Emit(operand); + } - public void Emit(OpCode value, bool operand) - { - Emit(value); - Emit(operand); - } + public void Emit(OpCode value, bool operand) + { + Emit(value); + Emit(operand); + } - public void Emit(double value) - => _writer.Write(value); + public void Emit(double value) + => _writer.Write(value); - public void Emit(long value) - => _writer.Write(value); + public void Emit(long value) + => _writer.Write(value); - public void Emit(int value) - => _writer.Write(value); + public void Emit(int value) + => _writer.Write(value); - public void Emit(bool value) - => _writer.Write(value); + public void Emit(bool value) + => _writer.Write(value); - public void Emit(byte value) - => _writer.Write(value); + public void Emit(byte value) + => _writer.Write(value); - public long Label(int offset = 0) - { - _labels.Add(IP + offset); - return _labels[_labels.Count - 1]; - } + public long Label(int offset = 0) + { + _labels.Add(IP + offset); + return _labels[_labels.Count - 1]; + } - public void Dispose() - { - OpCodeEmitted = null; - _opCodeAddresses.Clear(); + public void Dispose() + { + OpCodeEmitted = null; + _opCodeAddresses.Clear(); - _writer.Dispose(); - } + _writer.Dispose(); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Debugging/ChunkInvokeHandler.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Debugging/ChunkInvokeHandler.cs index b7d8d205..d43cc8d6 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Debugging/ChunkInvokeHandler.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Debugging/ChunkInvokeHandler.cs @@ -1,6 +1,5 @@ -using EVIL.Ceres.ExecutionEngine.Concurrency; +namespace EVIL.Ceres.ExecutionEngine.Diagnostics.Debugging; -namespace EVIL.Ceres.ExecutionEngine.Diagnostics.Debugging -{ - public delegate void ChunkInvokeHandler(Fiber fiber, Chunk chunk, bool isTailCall); -} \ No newline at end of file +using EVIL.Ceres.ExecutionEngine.Concurrency; + +public delegate void ChunkInvokeHandler(Fiber fiber, Chunk chunk, bool isTailCall); \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Debugging/DebugDatabase.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Debugging/DebugDatabase.cs index b18fa95b..078a7d3c 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Debugging/DebugDatabase.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Debugging/DebugDatabase.cs @@ -1,231 +1,230 @@ -using System; +namespace EVIL.Ceres.ExecutionEngine.Diagnostics.Debugging; + +using System; using System.Collections.Generic; using System.IO; using System.Linq; -namespace EVIL.Ceres.ExecutionEngine.Diagnostics.Debugging +public sealed class DebugDatabase : IEquatable { - public sealed class DebugDatabase : IEquatable - { - private readonly Dictionary> _records = new(); + private readonly Dictionary> _records = new(); - private readonly Dictionary _parameterNames = new(); - private readonly Dictionary _parameterRwStates = new(); + private readonly Dictionary _parameterNames = new(); + private readonly Dictionary _parameterRwStates = new(); - private readonly Dictionary _localNames = new(); - private readonly Dictionary _localRwStates = new(); + private readonly Dictionary _localNames = new(); + private readonly Dictionary _localRwStates = new(); - public int DefinedOnLine { get; internal set; } = -1; - public string DefinedInFile { get; internal set; } = string.Empty; + public int DefinedOnLine { get; internal set; } = -1; + public string DefinedInFile { get; internal set; } = string.Empty; - public void AddDebugRecord(int line, int ip) + public void AddDebugRecord(int line, int ip) + { + if (!_records.TryGetValue(line, out var addresses)) { - if (!_records.TryGetValue(line, out var addresses)) - { - addresses = new HashSet(); - _records.Add(line, addresses); - } - - addresses.Add(ip); + addresses = new HashSet(); + _records.Add(line, addresses); } - public int GetLineForIP(int ip) + addresses.Add(ip); + } + + public int GetLineForIP(int ip) + { + foreach (var kvp in _records) { - foreach (var kvp in _records) + if (kvp.Value.Contains(ip)) { - if (kvp.Value.Contains(ip)) - { - return kvp.Key; - } + return kvp.Key; } - - return -1; } - public void SetParameterName(int id, string name, bool rw) - { - if (!_parameterNames.TryAdd(id, name)) - { - _parameterNames[id] = name; - } + return -1; + } - if (!_parameterRwStates.TryAdd(id, rw)) - { - _parameterRwStates[id] = rw; - } + public void SetParameterName(int id, string name, bool rw) + { + if (!_parameterNames.TryAdd(id, name)) + { + _parameterNames[id] = name; } - public bool RemoveParameterName(int id) + if (!_parameterRwStates.TryAdd(id, rw)) { - _parameterRwStates.Remove(id); - return _parameterNames.Remove(id); + _parameterRwStates[id] = rw; } + } - public bool HasParameterNameFor(int id) - => _parameterNames.ContainsKey(id); + public bool RemoveParameterName(int id) + { + _parameterRwStates.Remove(id); + return _parameterNames.Remove(id); + } - public bool TryGetParameterName(int id, out string parameterName) - => _parameterNames.TryGetValue(id, out parameterName!); + public bool HasParameterNameFor(int id) + => _parameterNames.ContainsKey(id); - public bool TryGetParameterRwState(int id, out bool rw) - => _parameterRwStates.TryGetValue(id, out rw); + public bool TryGetParameterName(int id, out string parameterName) + => _parameterNames.TryGetValue(id, out parameterName!); - public void SetLocalName(int id, string name, bool rw) - { - if (!_localNames.TryAdd(id, name)) - { - _localNames[id] = name; - } + public bool TryGetParameterRwState(int id, out bool rw) + => _parameterRwStates.TryGetValue(id, out rw); - if (!_localRwStates.TryAdd(id, rw)) - { - _localRwStates[id] = rw; - } + public void SetLocalName(int id, string name, bool rw) + { + if (!_localNames.TryAdd(id, name)) + { + _localNames[id] = name; } - public bool RemoveLocalName(int id) + if (!_localRwStates.TryAdd(id, rw)) { - _localRwStates.Remove(id); - return _localNames.Remove(id); + _localRwStates[id] = rw; } + } - public bool HasLocalNameFor(int id) - => _localNames.ContainsKey(id); + public bool RemoveLocalName(int id) + { + _localRwStates.Remove(id); + return _localNames.Remove(id); + } - public bool TryGetLocalName(int id, out string localName) - => _localNames.TryGetValue(id, out localName!); + public bool HasLocalNameFor(int id) + => _localNames.ContainsKey(id); - public bool TryGetLocalRwState(int id, out bool rw) - => _localRwStates.TryGetValue(id, out rw); + public bool TryGetLocalName(int id, out string localName) + => _localNames.TryGetValue(id, out localName!); - public bool IsEmpty => !_records.Any() - && !_parameterNames.Any() - && !_localNames.Any() - && DefinedOnLine == -1; + public bool TryGetLocalRwState(int id, out bool rw) + => _localRwStates.TryGetValue(id, out rw); - public void Strip() - { - _records.Clear(); - _parameterNames.Clear(); - _localNames.Clear(); - DefinedOnLine = -1; - DefinedInFile = string.Empty; - } + public bool IsEmpty => !_records.Any() + && !_parameterNames.Any() + && !_localNames.Any() + && DefinedOnLine == -1; - internal void Serialize(BinaryWriter bw) - { - bw.Write(DefinedOnLine); - bw.Write(DefinedInFile); + public void Strip() + { + _records.Clear(); + _parameterNames.Clear(); + _localNames.Clear(); + DefinedOnLine = -1; + DefinedInFile = string.Empty; + } - bw.Write(_records.Count); - foreach (var record in _records) - { - bw.Write(record.Key); - bw.Write(record.Value.Count); + internal void Serialize(BinaryWriter bw) + { + bw.Write(DefinedOnLine); + bw.Write(DefinedInFile); - foreach (var addr in record.Value) - bw.Write(addr); - } + bw.Write(_records.Count); + foreach (var record in _records) + { + bw.Write(record.Key); + bw.Write(record.Value.Count); - bw.Write(_localNames.Count); - foreach (var localKvp in _localNames) - { - bw.Write(localKvp.Key); - bw.Write(localKvp.Value); - bw.Write(_localRwStates[localKvp.Key]); - } + foreach (var addr in record.Value) + bw.Write(addr); + } - bw.Write(_parameterNames.Count); - foreach (var paramKvp in _parameterNames) - { - bw.Write(paramKvp.Key); - bw.Write(paramKvp.Value); - bw.Write(_parameterRwStates[paramKvp.Key]); - } + bw.Write(_localNames.Count); + foreach (var localKvp in _localNames) + { + bw.Write(localKvp.Key); + bw.Write(localKvp.Value); + bw.Write(_localRwStates[localKvp.Key]); } - internal void Deserialize(BinaryReader br) + bw.Write(_parameterNames.Count); + foreach (var paramKvp in _parameterNames) { - Strip(); + bw.Write(paramKvp.Key); + bw.Write(paramKvp.Value); + bw.Write(_parameterRwStates[paramKvp.Key]); + } + } - DefinedOnLine = br.ReadInt32(); - DefinedInFile = br.ReadString(); + internal void Deserialize(BinaryReader br) + { + Strip(); - var recordCount = br.ReadInt32(); - for (var i = 0; i < recordCount; i++) - { - var line = br.ReadInt32(); - var addrCount = br.ReadInt32(); - - for (var j = 0; j < addrCount; j++) - { - AddDebugRecord( - line, - br.ReadInt32() - ); - } - } + DefinedOnLine = br.ReadInt32(); + DefinedInFile = br.ReadString(); - var localNameCount = br.ReadInt32(); - for (var i = 0; i < localNameCount; i++) - { - SetLocalName( - br.ReadInt32(), - br.ReadString(), - br.ReadBoolean() - ); - } + var recordCount = br.ReadInt32(); + for (var i = 0; i < recordCount; i++) + { + var line = br.ReadInt32(); + var addrCount = br.ReadInt32(); - var paramNameCount = br.ReadInt32(); - for (var i = 0; i < paramNameCount; i++) + for (var j = 0; j < addrCount; j++) { - SetParameterName( - br.ReadInt32(), - br.ReadString(), - br.ReadBoolean() + AddDebugRecord( + line, + br.ReadInt32() ); } } - public bool Equals(DebugDatabase? other) + var localNameCount = br.ReadInt32(); + for (var i = 0; i < localNameCount; i++) { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - - var recordsEqual = true; - recordsEqual &= _records.Keys.SequenceEqual(other._records.Keys); - foreach (var kvp in _records) - { - recordsEqual &= kvp.Value.SequenceEqual(other._records[kvp.Key]); - } - - return recordsEqual - && _parameterNames.SequenceEqual(other._parameterNames) - && _parameterRwStates.SequenceEqual(other._parameterRwStates) - && _localNames.SequenceEqual(other._localNames) - && _localRwStates.SequenceEqual(other._localRwStates) - && DefinedOnLine == other.DefinedOnLine - && DefinedInFile == other.DefinedInFile; + SetLocalName( + br.ReadInt32(), + br.ReadString(), + br.ReadBoolean() + ); } - public override bool Equals(object? obj) - => ReferenceEquals(this, obj) - || obj is DebugDatabase other - && Equals(other); - - public override int GetHashCode() - => HashCode.Combine( - _records, - _parameterNames, - _localNames, - DefinedOnLine, - DefinedInFile + var paramNameCount = br.ReadInt32(); + for (var i = 0; i < paramNameCount; i++) + { + SetParameterName( + br.ReadInt32(), + br.ReadString(), + br.ReadBoolean() ); + } + } + + public bool Equals(DebugDatabase? other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; - public static bool operator ==(DebugDatabase? left, DebugDatabase? right) - => Equals(left, right); + var recordsEqual = true; + recordsEqual &= _records.Keys.SequenceEqual(other._records.Keys); + foreach (var kvp in _records) + { + recordsEqual &= kvp.Value.SequenceEqual(other._records[kvp.Key]); + } - public static bool operator !=(DebugDatabase? left, DebugDatabase? right) - => !Equals(left, right); + return recordsEqual + && _parameterNames.SequenceEqual(other._parameterNames) + && _parameterRwStates.SequenceEqual(other._parameterRwStates) + && _localNames.SequenceEqual(other._localNames) + && _localRwStates.SequenceEqual(other._localRwStates) + && DefinedOnLine == other.DefinedOnLine + && DefinedInFile == other.DefinedInFile; } + + public override bool Equals(object? obj) + => ReferenceEquals(this, obj) + || obj is DebugDatabase other + && Equals(other); + + public override int GetHashCode() + => HashCode.Combine( + _records, + _parameterNames, + _localNames, + DefinedOnLine, + DefinedInFile + ); + + public static bool operator ==(DebugDatabase? left, DebugDatabase? right) + => Equals(left, right); + + public static bool operator !=(DebugDatabase? left, DebugDatabase? right) + => !Equals(left, right); } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Debugging/FiberCrashHandler.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Debugging/FiberCrashHandler.cs index 872cba06..04036572 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Debugging/FiberCrashHandler.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Debugging/FiberCrashHandler.cs @@ -1,7 +1,6 @@ +namespace EVIL.Ceres.ExecutionEngine.Diagnostics.Debugging; + using System; using EVIL.Ceres.ExecutionEngine.Concurrency; -namespace EVIL.Ceres.ExecutionEngine.Diagnostics.Debugging -{ - public delegate void FiberCrashHandler(Fiber fiber, Exception exception); -} \ No newline at end of file +public delegate void FiberCrashHandler(Fiber fiber, Exception exception); \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Debugging/NativeFunctionInvokeHandler.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Debugging/NativeFunctionInvokeHandler.cs index d72f11a4..ab69a199 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Debugging/NativeFunctionInvokeHandler.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Debugging/NativeFunctionInvokeHandler.cs @@ -1,6 +1,5 @@ +namespace EVIL.Ceres.ExecutionEngine.Diagnostics.Debugging; + using EVIL.Ceres.ExecutionEngine.Concurrency; -namespace EVIL.Ceres.ExecutionEngine.Diagnostics.Debugging -{ - public delegate void NativeFunctionInvokeHandler(Fiber fiber, NativeFunction nativeFunction); -} \ No newline at end of file +public delegate void NativeFunctionInvokeHandler(Fiber fiber, NativeFunction nativeFunction); \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Disassembler.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Disassembler.cs index 956b700a..b8a70906 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Disassembler.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Disassembler.cs @@ -1,3 +1,5 @@ +namespace EVIL.Ceres.ExecutionEngine.Diagnostics; + using System.Collections.Generic; using System.IO; using System.Linq; @@ -5,421 +7,418 @@ using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine.Diagnostics +public static class Disassembler { - public static class Disassembler + public class DisassemblyOptions { - public class DisassemblyOptions - { - public bool WriteLineNumbersWhenAvailable { get; set; } = true; - public bool WriteLocalNames { get; set; } = true; - public bool WriteParameterNames { get; set; } = true; - public bool WriteClosureInfo { get; set; } = true; - public bool WriteSubChunkNames { get; set; } = true; - public bool WriteLabelAddresses { get; set; } = true; - public bool WriteNumericConstants { get; set; } = true; - public bool WriteStringConstants { get; set; } = true; - } + public bool WriteLineNumbersWhenAvailable { get; set; } = true; + public bool WriteLocalNames { get; set; } = true; + public bool WriteParameterNames { get; set; } = true; + public bool WriteClosureInfo { get; set; } = true; + public bool WriteSubChunkNames { get; set; } = true; + public bool WriteLabelAddresses { get; set; } = true; + public bool WriteNumericConstants { get; set; } = true; + public bool WriteStringConstants { get; set; } = true; + } - public static void Disassemble(Chunk chunk, TextWriter output, DisassemblyOptions? options = null, - int indentLevel = 0) - { - options ??= new DisassemblyOptions(); - var indent = new string(' ', indentLevel); + public static void Disassemble(Chunk chunk, TextWriter output, DisassemblyOptions? options = null, + int indentLevel = 0) + { + options ??= new DisassemblyOptions(); + var indent = new string(' ', indentLevel); - output.Write($"{indent}.CHUNK "); + output.Write($"{indent}.CHUNK "); - output.Write(chunk.Name); - output.Write(" "); + output.Write(chunk.Name); + output.Write(" "); - if (chunk.HasDebugInfo) + if (chunk.HasDebugInfo) + { + if (chunk.DebugDatabase.DefinedOnLine > 0) { - if (chunk.DebugDatabase.DefinedOnLine > 0) - { - output.Write( - $"(def. on line {chunk.DebugDatabase.DefinedOnLine}) " - ); - } + output.Write( + $"(def. on line {chunk.DebugDatabase.DefinedOnLine}) " + ); } + } - output.WriteLine("{"); + output.WriteLine("{"); - if (chunk.MayThrow) - { - output.WriteLine($"{indent} .MAY_THROW"); - output.WriteLine(); - } + if (chunk.MayThrow) + { + output.WriteLine($"{indent} .MAY_THROW"); + output.WriteLine(); + } - output.WriteLine($"{indent} .LOCALS {chunk.LocalCount}"); - output.WriteLine($"{indent} .CLOSRS {chunk.ClosureCount}"); - output.WriteLine($"{indent} .PARAMS {chunk.ParameterCount}"); + output.WriteLine($"{indent} .LOCALS {chunk.LocalCount}"); + output.WriteLine($"{indent} .CLOSRS {chunk.ClosureCount}"); + output.WriteLine($"{indent} .PARAMS {chunk.ParameterCount}"); - for (var i = 0; i < chunk.ParameterCount; i++) + for (var i = 0; i < chunk.ParameterCount; i++) + { + if (chunk.IsSelfAware) { - if (chunk.IsSelfAware) - { - if (i == 0) - { - output.WriteLine($"{indent} .PARAM SELF({i})"); - continue; - } - } - - if (chunk.ParameterInitializers.TryGetValue(i, out var value)) - { - output.WriteLine($"{indent} .PARAM DO_INIT({i}): {value.ConvertToString().String}"); - } - else + if (i == 0) { - output.WriteLine($"{indent} .PARAM NO_INIT({i})"); + output.WriteLine($"{indent} .PARAM SELF({i})"); + continue; } } - if (chunk.Attributes.Any()) + if (chunk.ParameterInitializers.TryGetValue(i, out var value)) + { + output.WriteLine($"{indent} .PARAM DO_INIT({i}): {value.ConvertToString().String}"); + } + else { - output.WriteLine(); - DumpAttributes(chunk, output); + output.WriteLine($"{indent} .PARAM NO_INIT({i})"); } + } + if (chunk.Attributes.Any()) + { output.WriteLine(); - output.WriteLine($"{indent} .TEXT {{"); + DumpAttributes(chunk, output); + } - var prevLine = -1; - using (var reader = chunk.SpawnCodeReader()) + output.WriteLine(); + output.WriteLine($"{indent} .TEXT {{"); + + var prevLine = -1; + using (var reader = chunk.SpawnCodeReader()) + { + while (reader.BaseStream.Position < reader.BaseStream.Length) { - while (reader.BaseStream.Position < reader.BaseStream.Length) + var ip = reader.BaseStream.Position; + var opCode = (OpCode)reader.ReadByte(); + + if (chunk.HasDebugInfo && options.WriteLineNumbersWhenAvailable) { - var ip = reader.BaseStream.Position; - var opCode = (OpCode)reader.ReadByte(); + var line = chunk.DebugDatabase.GetLineForIP((int)ip); - if (chunk.HasDebugInfo && options.WriteLineNumbersWhenAvailable) + if (line > 0) { - var line = chunk.DebugDatabase.GetLineForIP((int)ip); - - if (line > 0) + if (prevLine != line) { - if (prevLine != line) - { - output.WriteLine($"{indent} line {line}:"); - prevLine = line; - } + output.WriteLine($"{indent} line {line}:"); + prevLine = line; } } + } - output.Write($"{indent} {ip:X8}: "); - switch (opCode) - { - case OpCode.YIELD: - case OpCode.NEXT: - output.Write(opCode); - output.Write(" "); - output.WriteLine(reader.ReadInt32()); - break; + output.Write($"{indent} {ip:X8}: "); + switch (opCode) + { + case OpCode.YIELD: + case OpCode.NEXT: + output.Write(opCode); + output.Write(" "); + output.WriteLine(reader.ReadInt32()); + break; - case OpCode.INVOKE: - output.Write(opCode); - output.Write(" "); - output.Write(reader.ReadInt32()); - output.Write(" "); - output.WriteLine(reader.ReadByte() == 1 ? "VARARGS" : ""); - break; - - case OpCode.GETCLOSURE: - case OpCode.SETCLOSURE: - { - output.Write(opCode); - output.Write(" "); - - var closureId = reader.ReadInt32(); - output.Write(closureId); + case OpCode.INVOKE: + output.Write(opCode); + output.Write(" "); + output.Write(reader.ReadInt32()); + output.Write(" "); + output.WriteLine(reader.ReadByte() == 1 ? "VARARGS" : ""); + break; - if (options.WriteClosureInfo) - { - var closure = chunk.Closures[closureId]; - var closureType = "local"; - if (closure.IsParameter) - { - closureType = "parameter"; - } - else if (closure.IsClosure) - { - closureType = "closure"; - } + case OpCode.GETCLOSURE: + case OpCode.SETCLOSURE: + { + output.Write(opCode); + output.Write(" "); - var names = new List(); - var closureFrom = chunk; - var nesting = closure.NestingLevel; + var closureId = reader.ReadInt32(); + output.Write(closureId); - while (closureFrom?.Parent != null) - { - closureFrom = closureFrom.Parent; - names.Add($"'{closureFrom?.Name ?? "???"}'"); - } + if (options.WriteClosureInfo) + { + var closure = chunk.Closures[closureId]; + var closureType = "local"; + if (closure.IsParameter) + { + closureType = "parameter"; + } + else if (closure.IsClosure) + { + closureType = "closure"; + } - for (var i = 0; i < nesting - 1; i++) - { - names.RemoveAt(0); - } + var names = new List(); + var closureFrom = chunk; + var nesting = closure.NestingLevel; - names.Reverse(); + while (closureFrom?.Parent != null) + { + closureFrom = closureFrom.Parent; + names.Add($"'{closureFrom?.Name ?? "???"}'"); + } - output.Write($" ({closureType} {closure.EnclosedId} in {string.Join(" -> ", names)})"); + for (var i = 0; i < nesting - 1; i++) + { + names.RemoveAt(0); } - output.WriteLine(); - break; + names.Reverse(); + + output.Write($" ({closureType} {closure.EnclosedId} in {string.Join(" -> ", names)})"); } - case OpCode.LDCNK: - { - output.Write(opCode); - output.Write(" "); + output.WriteLine(); + break; + } - var chunkId = reader.ReadInt32(); - output.Write(chunkId); + case OpCode.LDCNK: + { + output.Write(opCode); + output.Write(" "); - if (options.WriteSubChunkNames) - { - var subChunk = chunk.SubChunks[chunkId]; - output.Write($" (subchunk {chunkId} '{subChunk.Name}')"); - } + var chunkId = reader.ReadInt32(); + output.Write(chunkId); - output.WriteLine(); - break; + if (options.WriteSubChunkNames) + { + var subChunk = chunk.SubChunks[chunkId]; + output.Write($" (subchunk {chunkId} '{subChunk.Name}')"); } + + output.WriteLine(); + break; + } - case OpCode.TABCLN: - output.Write(opCode); - output.Write(" "); + case OpCode.TABCLN: + output.Write(opCode); + output.Write(" "); - var isDeepClone = reader.ReadByte(); - output.Write(isDeepClone); + var isDeepClone = reader.ReadByte(); + output.Write(isDeepClone); - output.WriteLine(); - break; + output.WriteLine(); + break; - case OpCode.SETLOCAL: - case OpCode.GETLOCAL: - case OpCode.SETARG: - case OpCode.GETARG: - output.Write(opCode); - output.Write(" "); + case OpCode.SETLOCAL: + case OpCode.GETLOCAL: + case OpCode.SETARG: + case OpCode.GETARG: + output.Write(opCode); + output.Write(" "); - var symId = reader.ReadInt32(); - output.Write(symId); + var symId = reader.ReadInt32(); + output.Write(symId); - if (chunk.HasDebugInfo) + if (chunk.HasDebugInfo) + { + if (opCode == OpCode.SETLOCAL || opCode == OpCode.GETLOCAL) { - if (opCode == OpCode.SETLOCAL || opCode == OpCode.GETLOCAL) + if (options.WriteLocalNames) { - if (options.WriteLocalNames) + if (chunk.DebugDatabase.TryGetLocalName(symId, out var name)) { - if (chunk.DebugDatabase.TryGetLocalName(symId, out var name)) - { - output.Write($" ({name})"); - } + output.Write($" ({name})"); } } - else + } + else + { + if (options.WriteParameterNames) { - if (options.WriteParameterNames) + if (chunk.DebugDatabase.TryGetParameterName(symId, out var name)) { - if (chunk.DebugDatabase.TryGetParameterName(symId, out var name)) - { - output.Write($" ({name})"); - } - else if (chunk.IsSelfAware) + output.Write($" ({name})"); + } + else if (chunk.IsSelfAware) + { + if (symId == 0) { - if (symId == 0) - { - output.Write($" (self)"); - } + output.Write($" (self)"); } } } } + } - output.WriteLine(); - break; + output.WriteLine(); + break; - case OpCode.FJMP: - case OpCode.TJMP: - case OpCode.JUMP: - output.Write(opCode); - output.Write(" "); + case OpCode.FJMP: + case OpCode.TJMP: + case OpCode.JUMP: + output.Write(opCode); + output.Write(" "); - var labelid = reader.ReadInt32(); - output.Write(labelid); + var labelid = reader.ReadInt32(); + output.Write(labelid); - if (options.WriteLabelAddresses) - { - output.Write($" ({chunk.Labels[labelid]:X8})"); - } + if (options.WriteLabelAddresses) + { + output.Write($" ({chunk.Labels[labelid]:X8})"); + } + + output.WriteLine(); + break; + + case OpCode.LDTYPE: + var typeCode = reader.ReadInt32(); + + output.Write(opCode); + output.Write(" "); + output.Write(typeCode); + output.Write($" ; {(DynamicValueType)typeCode}"); + output.WriteLine(); + break; - output.WriteLine(); - break; - - case OpCode.LDTYPE: - var typeCode = reader.ReadInt32(); - - output.Write(opCode); - output.Write(" "); - output.Write(typeCode); - output.Write($" ; {(DynamicValueType)typeCode}"); - output.WriteLine(); - break; - - case OpCode.LDNUM: - output.Write(opCode); - output.Write(" "); - output.Write(reader.ReadDouble()); - output.WriteLine(); - break; + case OpCode.LDNUM: + output.Write(opCode); + output.Write(" "); + output.Write(reader.ReadDouble()); + output.WriteLine(); + break; - case OpCode.ENTER: - output.Write(opCode); - output.Write(" "); - output.Write(reader.ReadInt32()); - output.WriteLine(); - break; - - case OpCode.LDSTR: - { - output.Write(opCode); - output.Write(" "); + case OpCode.ENTER: + output.Write(opCode); + output.Write(" "); + output.Write(reader.ReadInt32()); + output.WriteLine(); + break; - var strid = reader.ReadInt32(); - output.Write(strid); + case OpCode.LDSTR: + { + output.Write(opCode); + output.Write(" "); - if (options.WriteStringConstants) - { - var str = chunk.StringPool[strid]; + var strid = reader.ReadInt32(); + output.Write(strid); - if (str != null) - { - output.Write($" ({Literalize(str)})"); - } - else - { - output.Write($" ()"); - } - } + if (options.WriteStringConstants) + { + var str = chunk.StringPool[strid]; - output.WriteLine(); - break; + if (str != null) + { + output.Write($" ({Literalize(str)})"); + } + else + { + output.Write($" ()"); + } } - default: - output.WriteLine(opCode); - break; + output.WriteLine(); + break; } + + default: + output.WriteLine(opCode); + break; } } + } - output.WriteLine($"{indent} }}"); + output.WriteLine($"{indent} }}"); - if (chunk.SubChunks.Count > 0) + if (chunk.SubChunks.Count > 0) + { + output.WriteLine(); + output.WriteLine($"{indent} .SUBCHUNKS {{"); + for (var i = 0; i < chunk.SubChunkCount; i++) { - output.WriteLine(); - output.WriteLine($"{indent} .SUBCHUNKS {{"); - for (var i = 0; i < chunk.SubChunkCount; i++) - { - Disassemble(chunk.SubChunks[i], output, options, indentLevel + 4); - } - - output.WriteLine($"{indent} }}"); + Disassemble(chunk.SubChunks[i], output, options, indentLevel + 4); } - output.WriteLine($"{indent}}}"); + output.WriteLine($"{indent} }}"); } - private static void DumpAttributes(Chunk chunk, TextWriter output) - { - foreach (var attribute in chunk.Attributes) - { - output.Write($" .ATTR {attribute.Name}"); + output.WriteLine($"{indent}}}"); + } - if (attribute.Values.Count > 0) - { - output.Write("("); - output.Write( - string.Join( - ", ", - attribute.Values.Select(StringifyDynamicValue) - ) - ); - output.Write(")"); - } + private static void DumpAttributes(Chunk chunk, TextWriter output) + { + foreach (var attribute in chunk.Attributes) + { + output.Write($" .ATTR {attribute.Name}"); - output.WriteLine(); + if (attribute.Values.Count > 0) + { + output.Write("("); + output.Write( + string.Join( + ", ", + attribute.Values.Select(StringifyDynamicValue) + ) + ); + output.Write(")"); } + + output.WriteLine(); } + } - private static string StringifyDynamicValue(DynamicValue value) + private static string StringifyDynamicValue(DynamicValue value) + { + if (value.Type == DynamicValueType.String) { - if (value.Type == DynamicValueType.String) - { - return $"\"{value.String}\""; - } - - return value.ConvertToString().String!; + return $"\"{value.String}\""; } - private static string Literalize(string input) + return value.ConvertToString().String!; + } + + private static string Literalize(string input) + { + var literal = new StringBuilder(input.Length + 2); + literal.Append("\""); + foreach (var c in input) { - var literal = new StringBuilder(input.Length + 2); - literal.Append("\""); - foreach (var c in input) + switch (c) { - switch (c) - { - case '\"': - literal.Append("\\\""); - break; - case '\\': - literal.Append(@"\\"); - break; - case '\0': - literal.Append(@"\0"); - break; - case '\a': - literal.Append(@"\a"); - break; - case '\b': - literal.Append(@"\b"); - break; - case '\f': - literal.Append(@"\f"); - break; - case '\n': - literal.Append(@"\n"); - break; - case '\r': - literal.Append(@"\r"); - break; - case '\t': - literal.Append(@"\t"); - break; - case '\v': - literal.Append(@"\v"); - break; - default: - if (c >= 0x20 && c <= 0x7e) - { - literal.Append(c); - } - else - { - literal.Append(@"\u"); - literal.Append(((int)c).ToString("x4")); - } + case '\"': + literal.Append("\\\""); + break; + case '\\': + literal.Append(@"\\"); + break; + case '\0': + literal.Append(@"\0"); + break; + case '\a': + literal.Append(@"\a"); + break; + case '\b': + literal.Append(@"\b"); + break; + case '\f': + literal.Append(@"\f"); + break; + case '\n': + literal.Append(@"\n"); + break; + case '\r': + literal.Append(@"\r"); + break; + case '\t': + literal.Append(@"\t"); + break; + case '\v': + literal.Append(@"\v"); + break; + default: + if (c >= 0x20 && c <= 0x7e) + { + literal.Append(c); + } + else + { + literal.Append(@"\u"); + literal.Append(((int)c).ToString("x4")); + } - break; - } + break; } - - literal.Append("\""); - return literal.ToString(); } + + literal.Append("\""); + return literal.ToString(); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Error.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Error.cs index 5e1a60c8..0a65ef4e 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Error.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Error.cs @@ -1,60 +1,59 @@ +namespace EVIL.Ceres.ExecutionEngine.Diagnostics; + using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine.Diagnostics +public sealed class Error { - public sealed class Error - { - private Table UserData { get; } = new(); + private Table UserData { get; } = new(); - public int Length => UserData.Length; + public int Length => UserData.Length; - public string? Message + public string? Message + { + get { - get + if (UserData["msg"].Type == DynamicValueType.String) { - if (UserData["msg"].Type == DynamicValueType.String) - { - return UserData["msg"].String!; - } - - return null; + return UserData["msg"].String!; } - set => UserData["msg"] = value ?? DynamicValue.Nil; + return null; } - public DynamicValue this[DynamicValue key] - { - get => UserData[key]; - set => UserData[key] = value; - } + set => UserData["msg"] = value ?? DynamicValue.Nil; + } - public Error() - { - } + public DynamicValue this[DynamicValue key] + { + get => UserData[key]; + set => UserData[key] = value; + } - public Error(Table userData) - { - UserData = userData; - } + public Error() + { + } + + public Error(Table userData) + { + UserData = userData; + } - public Error(string message) - { - Message = message; - } + public Error(string message) + { + Message = message; + } - public Error(Table userData, string message) - { - UserData = userData; - Message = message; - } + public Error(Table userData, string message) + { + UserData = userData; + Message = message; + } - public bool Contains(DynamicValue key) - => UserData.Contains(key); + public bool Contains(DynamicValue key) + => UserData.Contains(key); - public bool IsDeeplyEqualTo(Error other) - => UserData.IsDeeplyEqualTo(other.UserData); - } + public bool IsDeeplyEqualTo(Error other) + => UserData.IsDeeplyEqualTo(other.UserData); } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/NativeFunction.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/NativeFunction.cs index 4777259e..298d95f8 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/NativeFunction.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/NativeFunction.cs @@ -1,7 +1,6 @@ +namespace EVIL.Ceres.ExecutionEngine.Diagnostics; + using EVIL.Ceres.ExecutionEngine.Concurrency; using EVIL.Ceres.ExecutionEngine.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine.Diagnostics -{ - public delegate DynamicValue NativeFunction(Fiber context, params DynamicValue[] args); -} \ No newline at end of file +public delegate DynamicValue NativeFunction(Fiber context, params DynamicValue[] args); \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/NativeStackFrame.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/NativeStackFrame.cs index 0e442831..cc87b372 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/NativeStackFrame.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/NativeStackFrame.cs @@ -1,20 +1,19 @@ -namespace EVIL.Ceres.ExecutionEngine.Diagnostics +namespace EVIL.Ceres.ExecutionEngine.Diagnostics; + +public sealed record NativeStackFrame : StackFrame { - public sealed record NativeStackFrame : StackFrame - { - public NativeFunction NativeFunction { get; } - public bool HasThrown { get; internal set; } + public NativeFunction NativeFunction { get; } + public bool HasThrown { get; internal set; } - public NativeStackFrame(NativeFunction nativeFunction) - { - NativeFunction = nativeFunction; - } + public NativeStackFrame(NativeFunction nativeFunction) + { + NativeFunction = nativeFunction; + } - public override void Dispose() - { - } - - public override string ToString() - => $"clr!{NativeFunction.Method.DeclaringType!.FullName}::{NativeFunction.Method.Name}"; + public override void Dispose() + { } + + public override string ToString() + => $"clr!{NativeFunction.Method.DeclaringType!.FullName}::{NativeFunction.Method.Name}"; } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/OpCode.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/OpCode.cs index d0fdbdc2..093caf1e 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/OpCode.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/OpCode.cs @@ -1,78 +1,77 @@ -namespace EVIL.Ceres.ExecutionEngine.Diagnostics +namespace EVIL.Ceres.ExecutionEngine.Diagnostics; + +public enum OpCode : byte { - public enum OpCode : byte - { - NOOP, - DUP, - ADD, - SUB, - MUL, - MOD, - DIV, - SHL, - SHR, - BOR, - BXOR, - BAND, - BNOT, - LDNIL, - LDTRUE, - LDFALSE, - LDZERO, - LDONE, - LDNUM, - LDSTR, - LDCNK, - LDTYPE, - ANEG, - POP, - RET, - INC, - DEC, - INVOKE, - TAILINVOKE, - SETGLOBAL, - GETGLOBAL, - SETLOCAL, - GETLOCAL, - SETARG, - GETARG, - GETCLOSURE, - SETCLOSURE, - LENGTH, - EXISTS, - TONUMBER, - TOSTRING, - TYPE, - LNOT, - LAND, - LOR, - DEQ, - DNE, - CEQ, - CNE, - CGT, - CLT, - CGE, - CLE, - FJMP, - TJMP, - JUMP, - ARRNEW, - TABNEW, - ELINIT, - ELSET, - INDEX, - TABCLN, - YIELD, - YRET, - XARGS, - EACH, - NEXT, - EEND, - ENTER, - THROW, - LEAVE, - ERRNEW - } + NOOP, + DUP, + ADD, + SUB, + MUL, + MOD, + DIV, + SHL, + SHR, + BOR, + BXOR, + BAND, + BNOT, + LDNIL, + LDTRUE, + LDFALSE, + LDZERO, + LDONE, + LDNUM, + LDSTR, + LDCNK, + LDTYPE, + ANEG, + POP, + RET, + INC, + DEC, + INVOKE, + TAILINVOKE, + SETGLOBAL, + GETGLOBAL, + SETLOCAL, + GETLOCAL, + SETARG, + GETARG, + GETCLOSURE, + SETCLOSURE, + LENGTH, + EXISTS, + TONUMBER, + TOSTRING, + TYPE, + LNOT, + LAND, + LOR, + DEQ, + DNE, + CEQ, + CNE, + CGT, + CLT, + CGE, + CLE, + FJMP, + TJMP, + JUMP, + ARRNEW, + TABNEW, + ELINIT, + ELSET, + INDEX, + TABCLN, + YIELD, + YRET, + XARGS, + EACH, + NEXT, + EEND, + ENTER, + THROW, + LEAVE, + ERRNEW } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/OpCodeEmittedEventArgs.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/OpCodeEmittedEventArgs.cs index 93efc618..bcea2b03 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/OpCodeEmittedEventArgs.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/OpCodeEmittedEventArgs.cs @@ -1,16 +1,15 @@ +namespace EVIL.Ceres.ExecutionEngine.Diagnostics; + using System; -namespace EVIL.Ceres.ExecutionEngine.Diagnostics +public sealed class OpCodeEmittedEventArgs : EventArgs { - public sealed class OpCodeEmittedEventArgs : EventArgs - { - public int IP { get; } - public OpCode OpCode { get; } + public int IP { get; } + public OpCode OpCode { get; } - internal OpCodeEmittedEventArgs(int ip, OpCode opCode) - { - IP = ip; - OpCode = opCode; - } + internal OpCodeEmittedEventArgs(int ip, OpCode opCode) + { + IP = ip; + OpCode = opCode; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ScriptStackFrame.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ScriptStackFrame.cs index f0f070f6..4aa6e732 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ScriptStackFrame.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ScriptStackFrame.cs @@ -1,186 +1,186 @@ -using System; +namespace EVIL.Ceres.ExecutionEngine.Diagnostics; + +using Collections_Array = EVIL.Ceres.ExecutionEngine.Collections.Array; +using Array = System.Array; + +using System; using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.Concurrency; using EVIL.Ceres.ExecutionEngine.TypeSystem; -using Array = EVIL.Ceres.ExecutionEngine.Collections.Array; -using Collections_Array = EVIL.Ceres.ExecutionEngine.Collections.Array; -namespace EVIL.Ceres.ExecutionEngine.Diagnostics +public sealed record ScriptStackFrame : StackFrame { - public sealed record ScriptStackFrame : StackFrame - { - private readonly BinaryReader _chunkReader; - private Collections_Array? _extraArguments; + private readonly BinaryReader _chunkReader; + private Collections_Array? _extraArguments; - private readonly Stack>> _collectionEnumerators = new(); + private readonly Stack>> _collectionEnumerators = new(); - public Fiber Fiber { get; } - public Chunk Chunk { get; } + public Fiber Fiber { get; } + public Chunk Chunk { get; } - public DynamicValue[] Arguments { get; } - public Collections_Array ExtraArguments => _extraArguments ??= GetExtraArgumentsArray(); + public DynamicValue[] Arguments { get; } + public Collections_Array ExtraArguments => _extraArguments ??= GetExtraArgumentsArray(); - public DynamicValue[]? Locals { get; } - public Stack BlockProtectorStack { get; } = new(); + public DynamicValue[]? Locals { get; } + public Stack BlockProtectorStack { get; } = new(); - public long PreviousOpCodeIP { get; private set; } - public long IP => _chunkReader.BaseStream.Position; + public long PreviousOpCodeIP { get; private set; } + public long IP => _chunkReader.BaseStream.Position; - public bool IsProtectedState => Chunk.Flags.HasFlag(ChunkFlags.HasProtectedBlocks) - && BlockProtectorStack.Count > 0; + public bool IsProtectedState => Chunk.Flags.HasFlag(ChunkFlags.HasProtectedBlocks) + && BlockProtectorStack.Count > 0; - public IEnumerator>? CurrentEnumerator + public IEnumerator>? CurrentEnumerator + { + get { - get - { - if (_collectionEnumerators.TryPeek(out var enumerator)) - return enumerator; + if (_collectionEnumerators.TryPeek(out var enumerator)) + return enumerator; - return null; - } + return null; } + } - internal ScriptStackFrame(Fiber fiber, Chunk chunk, DynamicValue[] args) - { - Fiber = fiber; - Chunk = chunk; + internal ScriptStackFrame(Fiber fiber, Chunk chunk, DynamicValue[] args) + { + Fiber = fiber; + Chunk = chunk; - if (chunk == null) - { - throw new InvalidOperationException("Attempt to invoke a null chunk."); - } + if (chunk == null) + { + throw new InvalidOperationException("Attempt to invoke a null chunk."); + } - if (chunk.ParameterCount > args.Length) - { - Arguments = new DynamicValue[chunk.ParameterCount]; - } - else - { - Arguments = new DynamicValue[args.Length]; - } + if (chunk.ParameterCount > args.Length) + { + Arguments = new DynamicValue[chunk.ParameterCount]; + } + else + { + Arguments = new DynamicValue[args.Length]; + } - for (var i = 0; i < Arguments.Length; i++) + for (var i = 0; i < Arguments.Length; i++) + { + if (Chunk.ParameterInitializers.TryGetValue(i, out var initializer)) { - if (Chunk.ParameterInitializers.TryGetValue(i, out var initializer)) - { - Arguments[i] = initializer; - } - - if (i < args.Length) - { - Arguments[i] = args[i]; - } + Arguments[i] = initializer; } - if (chunk.LocalCount > 0) + if (i < args.Length) { - Locals = new DynamicValue[chunk.LocalCount]; - System.Array.Fill(Locals, DynamicValue.Nil); + Arguments[i] = args[i]; } + } - _chunkReader = Chunk.SpawnCodeReader(); + if (chunk.LocalCount > 0) + { + Locals = new DynamicValue[chunk.LocalCount]; + Array.Fill(Locals, DynamicValue.Nil); } - internal void EnterProtectedBlock(int blockId) - => BlockProtectorStack.Push(Chunk.ProtectedBlocks[blockId]); + _chunkReader = Chunk.SpawnCodeReader(); + } - internal BlockProtectionInfo ExitProtectedBlock() - => BlockProtectorStack.Pop(); - - internal DynamicValue[] GetExtraArguments() - { - var size = Arguments.Length - Chunk.ParameterCount; - if (size < 0) size = 0; - var ret = new DynamicValue[size]; + internal void EnterProtectedBlock(int blockId) + => BlockProtectorStack.Push(Chunk.ProtectedBlocks[blockId]); - for (var i = Chunk.ParameterCount; i < Arguments.Length; i++) - { - ret[i - Chunk.ParameterCount] = Arguments[i]; - } + internal BlockProtectionInfo ExitProtectedBlock() + => BlockProtectorStack.Pop(); + + internal DynamicValue[] GetExtraArguments() + { + var size = Arguments.Length - Chunk.ParameterCount; + if (size < 0) size = 0; + var ret = new DynamicValue[size]; - return ret; + for (var i = Chunk.ParameterCount; i < Arguments.Length; i++) + { + ret[i - Chunk.ParameterCount] = Arguments[i]; } - internal Collections_Array GetExtraArgumentsArray() - { - var ret = new Collections_Array(Arguments.Length - Chunk.ParameterCount); + return ret; + } - for (var i = Chunk.ParameterCount; i < Arguments.Length; i++) - { - ret[i - Chunk.ParameterCount] = Arguments[i]; - } + internal Collections_Array GetExtraArgumentsArray() + { + var ret = new Collections_Array(Arguments.Length - Chunk.ParameterCount); - return ret; + for (var i = Chunk.ParameterCount; i < Arguments.Length; i++) + { + ret[i - Chunk.ParameterCount] = Arguments[i]; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PushEnumerator(Table table) - => _collectionEnumerators.Push(table.GetEnumerator()); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PushEnumerator(Collections_Array array) - => _collectionEnumerators.Push(array.GetEnumerator()); + return ret; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PopEnumerator() - => _collectionEnumerators.Pop(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void PushEnumerator(Table table) + => _collectionEnumerators.Push(table.GetEnumerator()); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void PushEnumerator(Collections_Array array) + => _collectionEnumerators.Push(array.GetEnumerator()); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void Return() - => _chunkReader.BaseStream.Seek(0, SeekOrigin.End); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void PopEnumerator() + => _collectionEnumerators.Pop(); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void Advance() - => _chunkReader.BaseStream.Position++; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void Return() + => _chunkReader.BaseStream.Seek(0, SeekOrigin.End); - internal OpCode PeekOpCode() - { - var opCode = FetchOpCode(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void Advance() + => _chunkReader.BaseStream.Position++; - _chunkReader.BaseStream.Position--; - return opCode; - } + internal OpCode PeekOpCode() + { + var opCode = FetchOpCode(); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal OpCode FetchOpCode() - { - PreviousOpCodeIP = IP; - return (OpCode)_chunkReader.ReadByte(); - } + _chunkReader.BaseStream.Position--; + return opCode; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal byte FetchByte() - => _chunkReader.ReadByte(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal OpCode FetchOpCode() + { + PreviousOpCodeIP = IP; + return (OpCode)_chunkReader.ReadByte(); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal double FetchDouble() - => _chunkReader.ReadDouble(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal byte FetchByte() + => _chunkReader.ReadByte(); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal int FetchInt32() - => _chunkReader.ReadInt32(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal double FetchDouble() + => _chunkReader.ReadDouble(); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal long FetchInt64() - => _chunkReader.ReadInt64(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal int FetchInt32() + => _chunkReader.ReadInt32(); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void JumpAbsolute(long address) - => _chunkReader.BaseStream.Seek(address, SeekOrigin.Begin); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal long FetchInt64() + => _chunkReader.ReadInt64(); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void JumpRelative(long offset) - => _chunkReader.BaseStream.Seek(offset, SeekOrigin.Current); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void JumpAbsolute(long address) + => _chunkReader.BaseStream.Seek(address, SeekOrigin.Begin); - public override void Dispose() - { - _chunkReader.Dispose(); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void JumpRelative(long offset) + => _chunkReader.BaseStream.Seek(offset, SeekOrigin.Current); - public override string ToString() - => $"{Chunk.Name}:({Chunk.DebugDatabase.GetLineForIP((int)PreviousOpCodeIP)}) @ {PreviousOpCodeIP:X8}"; + public override void Dispose() + { + _chunkReader.Dispose(); } + + public override string ToString() + => $"{Chunk.Name}:({Chunk.DebugDatabase.GetLineForIP((int)PreviousOpCodeIP)}) @ {PreviousOpCodeIP:X8}"; } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/StackFrame.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/StackFrame.cs index 06f06d9d..da80e7b2 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/StackFrame.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/StackFrame.cs @@ -1,12 +1,11 @@ +namespace EVIL.Ceres.ExecutionEngine.Diagnostics; + using System; -namespace EVIL.Ceres.ExecutionEngine.Diagnostics +public abstract record StackFrame : IDisposable { - public abstract record StackFrame : IDisposable - { - public T As() where T : StackFrame - => (T)this; + public T As() where T : StackFrame + => (T)this; - public abstract void Dispose(); - } + public abstract void Dispose(); } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/StringPool.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/StringPool.cs index 7d6be02e..0baaa457 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/StringPool.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/StringPool.cs @@ -1,75 +1,74 @@ +namespace EVIL.Ceres.ExecutionEngine.Diagnostics; + using System; using System.Collections.Generic; using System.Linq; -namespace EVIL.Ceres.ExecutionEngine.Diagnostics +public sealed class StringPool : IEquatable { - public sealed class StringPool : IEquatable - { - private readonly Dictionary _forward = new(); - private readonly Dictionary _backward = new(); + private readonly Dictionary _forward = new(); + private readonly Dictionary _backward = new(); - public int Count => _forward.Count; + public int Count => _forward.Count; - public string? this[int id] + public string? this[int id] + { + get { - get - { - if (!_forward.TryGetValue(id, out var str)) - return null; + if (!_forward.TryGetValue(id, out var str)) + return null; - return str; - } + return str; } + } - public StringPool() - { - } + public StringPool() + { + } - public StringPool(string[] values) - { - for (var i = 0; i < values.Length; i++) - FetchOrAdd(values[i]); - } + public StringPool(string[] values) + { + for (var i = 0; i < values.Length; i++) + FetchOrAdd(values[i]); + } - public long FetchOrAdd(string value) - { - if (_backward.TryGetValue(value, out int id)) - return id; + public long FetchOrAdd(string value) + { + if (_backward.TryGetValue(value, out int id)) + return id; - id = _forward.Count; + id = _forward.Count; - _forward.Add(id, value); - _backward.Add(value, id); + _forward.Add(id, value); + _backward.Add(value, id); - return id; - } + return id; + } - public string[] ToArray() - => _forward.Values.ToArray(); + public string[] ToArray() + => _forward.Values.ToArray(); - public bool Equals(StringPool? other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; + public bool Equals(StringPool? other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; - return _forward.SequenceEqual(other._forward) - && _backward.SequenceEqual(other._backward); - } + return _forward.SequenceEqual(other._forward) + && _backward.SequenceEqual(other._backward); + } - public override bool Equals(object? obj) - { - return ReferenceEquals(this, obj) - || obj is StringPool other && Equals(other); - } + public override bool Equals(object? obj) + { + return ReferenceEquals(this, obj) + || obj is StringPool other && Equals(other); + } - public override int GetHashCode() - => HashCode.Combine(_forward, _backward); + public override int GetHashCode() + => HashCode.Combine(_forward, _backward); - public static bool operator ==(StringPool? left, StringPool? right) - => Equals(left, right); + public static bool operator ==(StringPool? left, StringPool? right) + => Equals(left, right); - public static bool operator !=(StringPool? left, StringPool? right) - => !Equals(left, right); - } + public static bool operator !=(StringPool? left, StringPool? right) + => !Equals(left, right); } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/DivisionByZeroException.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/DivisionByZeroException.cs index c902e6ad..add1eeb1 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/DivisionByZeroException.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/DivisionByZeroException.cs @@ -1,10 +1,9 @@ -namespace EVIL.Ceres.ExecutionEngine +namespace EVIL.Ceres.ExecutionEngine; + +public class DivisionByZeroException : RecoverableVirtualMachineException { - public class DivisionByZeroException : RecoverableVirtualMachineException + internal DivisionByZeroException() + : base("Attempt to divide by zero.") { - internal DivisionByZeroException() - : base("Attempt to divide by zero.") - { - } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/ExecutionUnit.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/ExecutionUnit.cs index 01a3477a..aa5ee949 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/ExecutionUnit.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/ExecutionUnit.cs @@ -1,3 +1,7 @@ +namespace EVIL.Ceres.ExecutionEngine; + +using Array = System.Array; + using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -7,1590 +11,1586 @@ using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.CommonTypes.TypeSystem; -using Array = System.Array; -namespace EVIL.Ceres.ExecutionEngine +internal class ExecutionUnit { - internal class ExecutionUnit + private readonly Table _global; + private readonly Fiber _fiber; + private readonly CallStack _callStack; + private readonly Stack _evaluationStack; + + public ExecutionUnit( + Table global, + Fiber fiber, + Stack evaluationStack, + CallStack callStack) { - private readonly Table _global; - private readonly Fiber _fiber; - private readonly CallStack _callStack; - private readonly Stack _evaluationStack; - - public ExecutionUnit( - Table global, - Fiber fiber, - Stack evaluationStack, - CallStack callStack) - { - _global = global; - _fiber = fiber; - _evaluationStack = evaluationStack; - _callStack = callStack; - } + _global = global; + _fiber = fiber; + _evaluationStack = evaluationStack; + _callStack = callStack; + } - public void Step() - { - var frame = _callStack.Peek().As(); - var opCode = frame.FetchOpCode(); + public void Step() + { + var frame = _callStack.Peek().As(); + var opCode = frame.FetchOpCode(); - DynamicValue a; - DynamicValue b; - DynamicValue c; + DynamicValue a; + DynamicValue b; + DynamicValue c; - switch (opCode) + switch (opCode) + { + case OpCode.NOOP: { - case OpCode.NOOP: - { - break; - } + break; + } - case OpCode.DUP: - { - PushValue(PeekValue()); - break; - } + case OpCode.DUP: + { + PushValue(PeekValue()); + break; + } - case OpCode.LDNUM: - { - PushValue(frame.FetchDouble()); - break; - } + case OpCode.LDNUM: + { + PushValue(frame.FetchDouble()); + break; + } - case OpCode.LDNIL: - { - PushValue(DynamicValue.Nil); - break; - } + case OpCode.LDNIL: + { + PushValue(DynamicValue.Nil); + break; + } - case OpCode.LDONE: - { - PushValue(DynamicValue.One); - break; - } + case OpCode.LDONE: + { + PushValue(DynamicValue.One); + break; + } - case OpCode.LDZERO: - { - PushValue(DynamicValue.Zero); - break; - } + case OpCode.LDZERO: + { + PushValue(DynamicValue.Zero); + break; + } - case OpCode.LDTRUE: - { - PushValue(DynamicValue.True); - break; - } + case OpCode.LDTRUE: + { + PushValue(DynamicValue.True); + break; + } - case OpCode.LDFALSE: - { - PushValue(DynamicValue.False); - break; - } + case OpCode.LDFALSE: + { + PushValue(DynamicValue.False); + break; + } - case OpCode.LDSTR: - { - PushValue(frame.Chunk.StringPool[ - frame.FetchInt32() - ]!); + case OpCode.LDSTR: + { + PushValue(frame.Chunk.StringPool[ + frame.FetchInt32() + ]!); - break; - } + break; + } - case OpCode.LDCNK: - { - var clone = frame.Chunk.SubChunks[ - frame.FetchInt32() - ].Clone(); + case OpCode.LDCNK: + { + var clone = frame.Chunk.SubChunks[ + frame.FetchInt32() + ].Clone(); - var subChunkStack = new Queue(); - subChunkStack.Enqueue(clone); + var subChunkStack = new Queue(); + subChunkStack.Enqueue(clone); - while (subChunkStack.Any()) - { - var currentChunk = subChunkStack.Dequeue(); + while (subChunkStack.Any()) + { + var currentChunk = subChunkStack.Dequeue(); - for (var i = 0; i < currentChunk.ClosureCount; i++) - { - var closure = currentChunk.Closures[i]; + for (var i = 0; i < currentChunk.ClosureCount; i++) + { + var closure = currentChunk.Closures[i]; - ClosureContext closureContext; + ClosureContext closureContext; - if (closure.IsSharedScope) - { - closureContext = frame.Fiber.SetClosureContext(closure.EnclosedFunctionName); - } - else - { - closureContext = currentChunk.SetClosureContext(closure.EnclosedFunctionName); - } + if (closure.IsSharedScope) + { + closureContext = frame.Fiber.SetClosureContext(closure.EnclosedFunctionName); + } + else + { + closureContext = currentChunk.SetClosureContext(closure.EnclosedFunctionName); + } - ScriptStackFrame? sourceFrame = null; - for (var j = _callStack.Count - 1; j >= 0; j--) + ScriptStackFrame? sourceFrame = null; + for (var j = _callStack.Count - 1; j >= 0; j--) + { + var tmpFrame = _callStack[j].As(); + if (tmpFrame.Chunk.Name == closure.EnclosedFunctionName) { - var tmpFrame = _callStack[j].As(); - if (tmpFrame.Chunk.Name == closure.EnclosedFunctionName) - { - sourceFrame = tmpFrame; - break; - } + sourceFrame = tmpFrame; + break; } + } - if (sourceFrame == null) - { - continue; - } + if (sourceFrame == null) + { + continue; + } - if (closure.IsParameter) - { - closureContext.Values[closure.EnclosedId] = sourceFrame.Arguments[closure.EnclosedId]; - } - else if (closure.IsClosure) - { - // This is probably going to fuck up at some point :skull: - // I just don't know when. - // - // This is pain. First-class functions are pain. - // Curing testicular cancer was easier than implementing this shit. - // - var innerClosure = sourceFrame.Chunk.Closures[closure.EnclosedId]; + if (closure.IsParameter) + { + closureContext.Values[closure.EnclosedId] = sourceFrame.Arguments[closure.EnclosedId]; + } + else if (closure.IsClosure) + { + // This is probably going to fuck up at some point :skull: + // I just don't know when. + // + // This is pain. First-class functions are pain. + // Curing testicular cancer was easier than implementing this shit. + // + var innerClosure = sourceFrame.Chunk.Closures[closure.EnclosedId]; - if (innerClosure.IsSharedScope) - { - closureContext.Values[innerClosure.EnclosedId] = sourceFrame.Fiber - .ClosureContexts[innerClosure.EnclosedFunctionName].Values[innerClosure.EnclosedId]; - } - else - { - - closureContext.Values[innerClosure.EnclosedId] = sourceFrame.Chunk - .ClosureContexts[innerClosure.EnclosedFunctionName].Values[innerClosure.EnclosedId]; - } + if (innerClosure.IsSharedScope) + { + closureContext.Values[innerClosure.EnclosedId] = sourceFrame.Fiber + .ClosureContexts[innerClosure.EnclosedFunctionName].Values[innerClosure.EnclosedId]; } else { - closureContext.Values[closure.EnclosedId] = sourceFrame.Locals![closure.EnclosedId]; + + closureContext.Values[innerClosure.EnclosedId] = sourceFrame.Chunk + .ClosureContexts[innerClosure.EnclosedFunctionName].Values[innerClosure.EnclosedId]; } } - - foreach (var child in currentChunk.SubChunks) + else { - subChunkStack.Enqueue(child.Clone()); + closureContext.Values[closure.EnclosedId] = sourceFrame.Locals![closure.EnclosedId]; } } - - PushValue(clone); - break; + + foreach (var child in currentChunk.SubChunks) + { + subChunkStack.Enqueue(child.Clone()); + } } - case OpCode.LDTYPE: - { - PushValue((DynamicValueType)frame.FetchInt32()); - break; - } + PushValue(clone); + break; + } - case OpCode.ADD: - { - b = PopValue(); - a = PopValue(); + case OpCode.LDTYPE: + { + PushValue((DynamicValueType)frame.FetchInt32()); + break; + } + + case OpCode.ADD: + { + b = PopValue(); + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.AddMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.AddMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } + } - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.AddMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.AddMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } - - PushValue(a.Add(b)); - break; } + + PushValue(a.Add(b)); + break; + } - case OpCode.SUB: - { - b = PopValue(); - a = PopValue(); + case OpCode.SUB: + { + b = PopValue(); + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.SubtractMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.SubtractMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } + } - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.SubtractMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.SubtractMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } - - PushValue(a.Subtract(b)); - break; } - case OpCode.MUL: - { - b = PopValue(); - a = PopValue(); + PushValue(a.Subtract(b)); + break; + } + + case OpCode.MUL: + { + b = PopValue(); + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.MultiplyMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.MultiplyMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } + } - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.MultiplyMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.MultiplyMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } - - PushValue(a.Multiply(b)); - break; } - case OpCode.DIV: - { - b = PopValue(); - a = PopValue(); + PushValue(a.Multiply(b)); + break; + } + + case OpCode.DIV: + { + b = PopValue(); + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.DivideMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.DivideMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } + } - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.DivideMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.DivideMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } - - PushValue(a.DivideBy(b)); - break; } - case OpCode.MOD: - { - b = PopValue(); - a = PopValue(); + PushValue(a.DivideBy(b)); + break; + } + + case OpCode.MOD: + { + b = PopValue(); + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.ModuloMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.ModuloMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } + } - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.ModuloMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.ModuloMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } - - PushValue(a.Modulo(b)); - break; } - case OpCode.SHL: - { - b = PopValue(); - a = PopValue(); + PushValue(a.Modulo(b)); + break; + } + + case OpCode.SHL: + { + b = PopValue(); + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.ShiftLeftMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.ShiftLeftMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } + } - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.ShiftLeftMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.ShiftLeftMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } - - PushValue(a.ShiftLeft(b)); - break; } - case OpCode.SHR: - { - b = PopValue(); - a = PopValue(); + PushValue(a.ShiftLeft(b)); + break; + } + + case OpCode.SHR: + { + b = PopValue(); + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.ShiftRightMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.ShiftRightMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } + } - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.ShiftRightMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.ShiftRightMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } - - PushValue(a.ShiftRight(b)); - break; } - case OpCode.POP: - { - PopValue(); - break; - } + PushValue(a.ShiftRight(b)); + break; + } - case OpCode.ANEG: - { - a = PopValue(); + case OpCode.POP: + { + PopValue(); + break; + } + + case OpCode.ANEG: + { + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.ArithmeticNegateMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.ArithmeticNegateMetaKey, out var chunk)) - { - InvokeChunk(chunk, a); - break; - } + InvokeChunk(chunk, a); + break; } - - PushValue(a.ArithmeticallyNegate()); - break; } + + PushValue(a.ArithmeticallyNegate()); + break; + } - case OpCode.LNOT: - { - a = PopValue(); + case OpCode.LNOT: + { + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.LogicalNotMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.LogicalNotMetaKey, out var chunk)) - { - InvokeChunk(chunk, a); - break; - } + InvokeChunk(chunk, a); + break; } - - PushValue(a.LogicallyNegate()); - break; } + + PushValue(a.LogicallyNegate()); + break; + } - case OpCode.LOR: - { - b = PopValue(); - a = PopValue(); + case OpCode.LOR: + { + b = PopValue(); + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.LogicalOrMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.LogicalOrMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } + } - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.LogicalOrMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.LogicalOrMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } - - PushValue(a.LogicalOr(b)); - break; } - case OpCode.LAND: - { - b = PopValue(); - a = PopValue(); + PushValue(a.LogicalOr(b)); + break; + } + + case OpCode.LAND: + { + b = PopValue(); + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.LogicalAndMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.LogicalAndMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } + } - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.LogicalAndMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.LogicalAndMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } - - PushValue(a.LogicalAnd(b)); - break; } - case OpCode.BOR: - { - b = PopValue(); - a = PopValue(); + PushValue(a.LogicalAnd(b)); + break; + } + + case OpCode.BOR: + { + b = PopValue(); + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.BitwiseOrMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.BitwiseOrMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } + } - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.BitwiseOrMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.BitwiseOrMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } - - PushValue(a.BitwiseOr(b)); - break; } - case OpCode.BXOR: - { - b = PopValue(); - a = PopValue(); + PushValue(a.BitwiseOr(b)); + break; + } + + case OpCode.BXOR: + { + b = PopValue(); + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.BitwiseXorMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.BitwiseXorMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } + } - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.BitwiseXorMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.BitwiseXorMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } - - PushValue(a.BitwiseXor(b)); - break; } - case OpCode.BAND: - { - b = PopValue(); - a = PopValue(); + PushValue(a.BitwiseXor(b)); + break; + } + + case OpCode.BAND: + { + b = PopValue(); + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.BitwiseAndMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.BitwiseAndMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } + } - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.BitwiseAndMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.BitwiseAndMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } - - PushValue(a.BitwiseAnd(b)); - break; } - case OpCode.BNOT: - { - a = PopValue(); + PushValue(a.BitwiseAnd(b)); + break; + } + + case OpCode.BNOT: + { + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.BitwiseNotMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.BitwiseNotMetaKey, out var chunk)) - { - InvokeChunk(chunk, a); - break; - } + InvokeChunk(chunk, a); + break; } - - PushValue(a.BitwiseNegate()); - break; } - case OpCode.DEQ: - { - b = PopValue(); - a = PopValue(); + PushValue(a.BitwiseNegate()); + break; + } + + case OpCode.DEQ: + { + b = PopValue(); + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.DeepEqualMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.DeepEqualMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } + } - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.DeepEqualMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.DeepEqualMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } - - PushValue(a.IsDeeplyEqualTo(b)); - break; } - case OpCode.DNE: - { - b = PopValue(); - a = PopValue(); + PushValue(a.IsDeeplyEqualTo(b)); + break; + } + + case OpCode.DNE: + { + b = PopValue(); + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.DeepNotEqualMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.DeepNotEqualMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } + } - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.DeepNotEqualMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.DeepNotEqualMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } - - PushValue(a.IsDeeplyNotEqualTo(b)); - break; } - case OpCode.CEQ: - { - b = PopValue(); - a = PopValue(); + PushValue(a.IsDeeplyNotEqualTo(b)); + break; + } + + case OpCode.CEQ: + { + b = PopValue(); + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.EqualMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.EqualMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } + } - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.EqualMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.EqualMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } - - PushValue(a.IsEqualTo(b)); - break; } - case OpCode.CNE: - { - b = PopValue(); - a = PopValue(); + PushValue(a.IsEqualTo(b)); + break; + } + + case OpCode.CNE: + { + b = PopValue(); + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.NotEqualMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.NotEqualMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } + } - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.NotEqualMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.NotEqualMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } - - PushValue(a.IsNotEqualTo(b)); - break; } - case OpCode.CGT: - { - b = PopValue(); - a = PopValue(); + PushValue(a.IsNotEqualTo(b)); + break; + } - if (a.Type == DynamicValueType.Table) + case OpCode.CGT: + { + b = PopValue(); + a = PopValue(); + + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.GreaterThanMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.GreaterThanMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } + } - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.GreaterThanMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.GreaterThanMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } - - PushValue(a.IsGreaterThan(b)); - break; } + + PushValue(a.IsGreaterThan(b)); + break; + } - case OpCode.CGE: - { - b = PopValue(); - a = PopValue(); + case OpCode.CGE: + { + b = PopValue(); + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.GreaterEqualMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.GreaterEqualMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } + } - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.GreaterEqualMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.GreaterEqualMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } - - PushValue(a.IsGreaterThanOrEqualTo(b)); - break; } - case OpCode.CLT: - { - b = PopValue(); - a = PopValue(); + PushValue(a.IsGreaterThanOrEqualTo(b)); + break; + } + + case OpCode.CLT: + { + b = PopValue(); + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.LessThanMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.LessThanMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } + } - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.LessThanMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.LessThanMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } - - PushValue(a.IsLessThan(b)); - break; } - case OpCode.CLE: - { - b = PopValue(); - a = PopValue(); + PushValue(a.IsLessThan(b)); + break; + } + + case OpCode.CLE: + { + b = PopValue(); + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.LessEqualMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.LessEqualMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } + } - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.LessEqualMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.LessEqualMetaKey, out var chunk)) - { - InvokeChunk(chunk, a, b); - break; - } + InvokeChunk(chunk, a, b); + break; } - - PushValue(a.IsLessThanOrEqualTo(b)); - break; } - case OpCode.INVOKE: - { - a = PopValue(); + PushValue(a.IsLessThanOrEqualTo(b)); + break; + } - var argumentCount = frame.FetchInt32(); - var isVariadic = frame.FetchByte() == 1; + case OpCode.INVOKE: + { + a = PopValue(); - if (isVariadic) - { - argumentCount += frame.ExtraArguments.Length - 1; - // -1 because variadic specifier is treated as an argument - } + var argumentCount = frame.FetchInt32(); + var isVariadic = frame.FetchByte() == 1; + + if (isVariadic) + { + argumentCount += frame.ExtraArguments.Length - 1; + // -1 because variadic specifier is treated as an argument + } - var args = PopArguments(argumentCount); + var args = PopArguments(argumentCount); - if (a.Type == DynamicValueType.Table) - { - if (FindMetaFunction(a.Table!, Table.InvokeMetaKey, out var chunk)) - { - var overrideArgs = new DynamicValue[args.Length + 1]; - overrideArgs[0] = a; - Array.Copy( - args, 0, - overrideArgs, 1, - args.Length - ); - - InvokeChunk(chunk, overrideArgs); - break; - } - } - - if (a.Type == DynamicValueType.Chunk) - { - InvokeChunk(a.Chunk!, args); - break; - } - - if (a.Type == DynamicValueType.NativeFunction) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.InvokeMetaKey, out var chunk)) { - _callStack.Push(new NativeStackFrame(a.NativeFunction!)); - - _fiber.OnNativeFunctionInvoke?.Invoke( - _fiber, - a.NativeFunction! + var overrideArgs = new DynamicValue[args.Length + 1]; + overrideArgs[0] = a; + Array.Copy( + args, 0, + overrideArgs, 1, + args.Length ); - - var value = a.NativeFunction!.Invoke(_fiber, args); - - if (_callStack.Peek() is NativeStackFrame) - { - PushValue(value); - _callStack.Pop(); - } - else - { - /* We probably threw from native, nothing else to be done. */ - } + + InvokeChunk(chunk, overrideArgs); break; } - - throw new UnsupportedDynamicValueOperationException( - $"Attempt to invoke a {a.Type} value." - ); } - case OpCode.TAILINVOKE: + if (a.Type == DynamicValueType.Chunk) { - var args = frame.Arguments; - - for (var i = 0; i < frame.Arguments.Length; i++) - { - args[args.Length - i - 1] = PopValue(); - } - - _fiber.OnChunkInvoke?.Invoke( - _fiber, - _callStack.Peek().As().Chunk, - true - ); - - frame.JumpAbsolute(0); + InvokeChunk(a.Chunk!, args); break; } - case OpCode.SETGLOBAL: + if (a.Type == DynamicValueType.NativeFunction) { - b = PopValue(); - a = PopValue(); - _global[b] = a; + _callStack.Push(new NativeStackFrame(a.NativeFunction!)); + + _fiber.OnNativeFunctionInvoke?.Invoke( + _fiber, + a.NativeFunction! + ); + + var value = a.NativeFunction!.Invoke(_fiber, args); + if (_callStack.Peek() is NativeStackFrame) + { + PushValue(value); + _callStack.Pop(); + } + else + { + /* We probably threw from native, nothing else to be done. */ + } break; } - case OpCode.GETGLOBAL: - { - PushValue(_global[PopValue()]); - break; - } + throw new UnsupportedDynamicValueOperationException( + $"Attempt to invoke a {a.Type} value." + ); + } - case OpCode.SETLOCAL: - { - frame.Locals![frame.FetchInt32()] = PopValue(); - break; - } + case OpCode.TAILINVOKE: + { + var args = frame.Arguments; - case OpCode.GETLOCAL: + for (var i = 0; i < frame.Arguments.Length; i++) { - PushValue(frame.Locals![frame.FetchInt32()]); - break; + args[args.Length - i - 1] = PopValue(); } - case OpCode.SETARG: - { - frame.Arguments[frame.FetchInt32()] = PopValue(); - break; - } + _fiber.OnChunkInvoke?.Invoke( + _fiber, + _callStack.Peek().As().Chunk, + true + ); - case OpCode.GETARG: - { - PushValue(frame.Arguments[frame.FetchInt32()]); - break; - } + frame.JumpAbsolute(0); + break; + } - case OpCode.SETCLOSURE: - { - var closureId = frame.FetchInt32(); - var closureInfo = frame.Chunk.Closures[closureId]; + case OpCode.SETGLOBAL: + { + b = PopValue(); + a = PopValue(); + _global[b] = a; - ScriptStackFrame? targetFrame = null; + break; + } - for (var i = 0; i < _callStack.Count; i++) - { - var tmpScriptFrame = _callStack[i].As(); + case OpCode.GETGLOBAL: + { + PushValue(_global[PopValue()]); + break; + } - if (tmpScriptFrame.Chunk.Name == closureInfo.EnclosedFunctionName) - { - targetFrame = tmpScriptFrame; - break; - } - } + case OpCode.SETLOCAL: + { + frame.Locals![frame.FetchInt32()] = PopValue(); + break; + } + + case OpCode.GETLOCAL: + { + PushValue(frame.Locals![frame.FetchInt32()]); + break; + } + + case OpCode.SETARG: + { + frame.Arguments[frame.FetchInt32()] = PopValue(); + break; + } - var value = PopValue(); + case OpCode.GETARG: + { + PushValue(frame.Arguments[frame.FetchInt32()]); + break; + } - if (targetFrame != null) + case OpCode.SETCLOSURE: + { + var closureId = frame.FetchInt32(); + var closureInfo = frame.Chunk.Closures[closureId]; + + ScriptStackFrame? targetFrame = null; + + for (var i = 0; i < _callStack.Count; i++) + { + var tmpScriptFrame = _callStack[i].As(); + + if (tmpScriptFrame.Chunk.Name == closureInfo.EnclosedFunctionName) { - if (closureInfo.IsParameter) - { - targetFrame.Arguments[closureInfo.EnclosedId] = value; - } - else if (closureInfo.IsClosure) + targetFrame = tmpScriptFrame; + break; + } + } + + var value = PopValue(); + + if (targetFrame != null) + { + if (closureInfo.IsParameter) + { + targetFrame.Arguments[closureInfo.EnclosedId] = value; + } + else if (closureInfo.IsClosure) + { + while (closureInfo.IsClosure) { - while (closureInfo.IsClosure) - { - closureInfo = targetFrame.Chunk.Closures[closureInfo.EnclosedId]; + closureInfo = targetFrame.Chunk.Closures[closureInfo.EnclosedId]; - for (var i = 0; i < _callStack.Count; i++) - { - var tmpScriptFrame = _callStack[i].As(); + for (var i = 0; i < _callStack.Count; i++) + { + var tmpScriptFrame = _callStack[i].As(); - if (tmpScriptFrame.Chunk.Name == closureInfo.EnclosedFunctionName) - { - targetFrame = tmpScriptFrame; - break; - } + if (tmpScriptFrame.Chunk.Name == closureInfo.EnclosedFunctionName) + { + targetFrame = tmpScriptFrame; + break; } } + } - ClosureContext closureContext; - - if (closureInfo.IsSharedScope) - { - closureContext = targetFrame.Fiber.ClosureContexts[closureInfo.EnclosedFunctionName]; - } - else - { - closureContext = targetFrame.Chunk.ClosureContexts[closureInfo.EnclosedFunctionName]; - } + ClosureContext closureContext; - closureContext.Values[closureInfo.EnclosedId] = value; + if (closureInfo.IsSharedScope) + { + closureContext = targetFrame.Fiber.ClosureContexts[closureInfo.EnclosedFunctionName]; } else { - targetFrame.Locals![closureInfo.EnclosedId] = value; + closureContext = targetFrame.Chunk.ClosureContexts[closureInfo.EnclosedFunctionName]; } + + closureContext.Values[closureInfo.EnclosedId] = value; } else { - ClosureContext closureContext; + targetFrame.Locals![closureInfo.EnclosedId] = value; + } + } + else + { + ClosureContext closureContext; - if (closureInfo.IsSharedScope) + if (closureInfo.IsSharedScope) + { + closureContext = frame.Fiber.ClosureContexts[closureInfo.EnclosedFunctionName]; + } + else + { + if (closureInfo.IsClosure) { + var currentChunk = frame.Chunk; + while (currentChunk.Name != closureInfo.EnclosedFunctionName) + { + currentChunk = currentChunk.Parent!; + } + + closureInfo = currentChunk.Closures[closureInfo.EnclosedId]; closureContext = frame.Fiber.ClosureContexts[closureInfo.EnclosedFunctionName]; } else { - if (closureInfo.IsClosure) - { - var currentChunk = frame.Chunk; - while (currentChunk.Name != closureInfo.EnclosedFunctionName) - { - currentChunk = currentChunk.Parent!; - } - - closureInfo = currentChunk.Closures[closureInfo.EnclosedId]; - closureContext = frame.Fiber.ClosureContexts[closureInfo.EnclosedFunctionName]; - } - else - { - closureContext = frame.Chunk.ClosureContexts[closureInfo.EnclosedFunctionName]; - } + closureContext = frame.Chunk.ClosureContexts[closureInfo.EnclosedFunctionName]; } - - closureContext.Values[closureInfo.EnclosedId] = value; } - - break; + + closureContext.Values[closureInfo.EnclosedId] = value; } - case OpCode.GETCLOSURE: + break; + } + + case OpCode.GETCLOSURE: + { + var closureInfo = frame.Chunk.Closures[frame.FetchInt32()]; + + ScriptStackFrame? targetFrame = null; + for (var i = 0; i < _callStack.Count; i++) { - var closureInfo = frame.Chunk.Closures[frame.FetchInt32()]; + var tmpScriptFrame = _callStack[i].As(); - ScriptStackFrame? targetFrame = null; - for (var i = 0; i < _callStack.Count; i++) + if (tmpScriptFrame.Chunk.Name == closureInfo.EnclosedFunctionName) { - var tmpScriptFrame = _callStack[i].As(); - - if (tmpScriptFrame.Chunk.Name == closureInfo.EnclosedFunctionName) - { - targetFrame = tmpScriptFrame; - break; - } + targetFrame = tmpScriptFrame; + break; } + } - if (targetFrame != null) + if (targetFrame != null) + { + if (closureInfo.IsParameter) { - if (closureInfo.IsParameter) - { - PushValue(targetFrame.Arguments[closureInfo.EnclosedId]); - } - else if (closureInfo.IsClosure) + PushValue(targetFrame.Arguments[closureInfo.EnclosedId]); + } + else if (closureInfo.IsClosure) + { + while (closureInfo.IsClosure) { - while (closureInfo.IsClosure) - { - closureInfo = targetFrame.Chunk.Closures[closureInfo.EnclosedId]; + closureInfo = targetFrame.Chunk.Closures[closureInfo.EnclosedId]; - for (var i = 0; i < _callStack.Count; i++) - { - var tmpScriptFrame = _callStack[i].As(); + for (var i = 0; i < _callStack.Count; i++) + { + var tmpScriptFrame = _callStack[i].As(); - if (tmpScriptFrame.Chunk.Name == closureInfo.EnclosedFunctionName) - { - targetFrame = tmpScriptFrame; - break; - } + if (tmpScriptFrame.Chunk.Name == closureInfo.EnclosedFunctionName) + { + targetFrame = tmpScriptFrame; + break; } } + } - ClosureContext closureContext; - - if (closureInfo.IsSharedScope) - { - closureContext = targetFrame.Fiber.ClosureContexts[closureInfo.EnclosedFunctionName]; - } - else - { - closureContext = targetFrame.Chunk.ClosureContexts[closureInfo.EnclosedFunctionName]; - } + ClosureContext closureContext; - PushValue(closureContext.Values[closureInfo.EnclosedId]); + if (closureInfo.IsSharedScope) + { + closureContext = targetFrame.Fiber.ClosureContexts[closureInfo.EnclosedFunctionName]; } else { - PushValue(targetFrame.Locals![closureInfo.EnclosedId]); + closureContext = targetFrame.Chunk.ClosureContexts[closureInfo.EnclosedFunctionName]; } + + PushValue(closureContext.Values[closureInfo.EnclosedId]); } else { - ClosureContext closureContext; + PushValue(targetFrame.Locals![closureInfo.EnclosedId]); + } + } + else + { + ClosureContext closureContext; - if (closureInfo.IsSharedScope) - { - closureContext = frame.Fiber.ClosureContexts[closureInfo.EnclosedFunctionName]; - } - else /* Probably called from somewhere *outside* EVIL. */ + if (closureInfo.IsSharedScope) + { + closureContext = frame.Fiber.ClosureContexts[closureInfo.EnclosedFunctionName]; + } + else /* Probably called from somewhere *outside* EVIL. */ + { + if (closureInfo.IsClosure) { - if (closureInfo.IsClosure) - { - var currentChunk = frame.Chunk; - while (currentChunk.Name != closureInfo.EnclosedFunctionName) - { - currentChunk = currentChunk.Parent!; - } - - closureInfo = currentChunk.Closures[closureInfo.EnclosedId]; - closureContext = frame.Fiber.ClosureContexts[closureInfo.EnclosedFunctionName]; - } - else + var currentChunk = frame.Chunk; + while (currentChunk.Name != closureInfo.EnclosedFunctionName) { - closureContext = frame.Chunk.ClosureContexts[closureInfo.EnclosedFunctionName]; + currentChunk = currentChunk.Parent!; } - } - PushValue(closureContext.Values[closureInfo.EnclosedId]); - } + closureInfo = currentChunk.Closures[closureInfo.EnclosedId]; + closureContext = frame.Fiber.ClosureContexts[closureInfo.EnclosedFunctionName]; + } + else + { + closureContext = frame.Chunk.ClosureContexts[closureInfo.EnclosedFunctionName]; + } + } - break; + PushValue(closureContext.Values[closureInfo.EnclosedId]); } - case OpCode.LENGTH: - { - a = PopValue(); + break; + } + + case OpCode.LENGTH: + { + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.LengthMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.LengthMetaKey, out var chunk)) - { - InvokeChunk(chunk, a); - break; - } + InvokeChunk(chunk, a); + break; } - - PushValue(a.GetLength()); - break; } + + PushValue(a.GetLength()); + break; + } - case OpCode.TOSTRING: - { - a = PopValue(); + case OpCode.TOSTRING: + { + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.ToStringMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.ToStringMetaKey, out var chunk)) - { - InvokeChunk(chunk, a); - break; - } + InvokeChunk(chunk, a); + break; } - - PushValue(a.ConvertToString()); - break; } + + PushValue(a.ConvertToString()); + break; + } - case OpCode.TONUMBER: - { - a = PopValue(); + case OpCode.TONUMBER: + { + a = PopValue(); - if (a.Type == DynamicValueType.Table) + if (a.Type == DynamicValueType.Table) + { + if (FindMetaFunction(a.Table!, Table.ToNumberMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.ToNumberMetaKey, out var chunk)) - { - InvokeChunk(chunk, a); - break; - } + InvokeChunk(chunk, a); + break; } - - PushValue(a.ConvertToNumber()); - break; - } - - case OpCode.TYPE: - { - PushValue(PopValue().Type); - break; } + + PushValue(a.ConvertToNumber()); + break; + } - case OpCode.FJMP: - { - var labelId = frame.FetchInt32(); - - if (!DynamicValue.IsTruth(PopValue())) - { - frame.JumpAbsolute( - frame.Chunk.Labels[labelId] - ); - } + case OpCode.TYPE: + { + PushValue(PopValue().Type); + break; + } - break; - } + case OpCode.FJMP: + { + var labelId = frame.FetchInt32(); - case OpCode.TJMP: + if (!DynamicValue.IsTruth(PopValue())) { - var labelId = frame.FetchInt32(); + frame.JumpAbsolute( + frame.Chunk.Labels[labelId] + ); + } - if (DynamicValue.IsTruth(PopValue())) - { - frame.JumpAbsolute( - frame.Chunk.Labels[labelId] - ); - } + break; + } - break; - } + case OpCode.TJMP: + { + var labelId = frame.FetchInt32(); - case OpCode.JUMP: + if (DynamicValue.IsTruth(PopValue())) { frame.JumpAbsolute( - frame.Chunk.Labels[ - frame.FetchInt32() - ] + frame.Chunk.Labels[labelId] ); - break; } - case OpCode.EXISTS: - { - b = PopValue(); - a = PopValue(); + break; + } + + case OpCode.JUMP: + { + frame.JumpAbsolute( + frame.Chunk.Labels[ + frame.FetchInt32() + ] + ); + break; + } + + case OpCode.EXISTS: + { + b = PopValue(); + a = PopValue(); - if (b.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.Table) + { + if (FindMetaFunction(b.Table!, Table.ExistsMetaKey, out var chunk)) { - if (FindMetaFunction(b.Table!, Table.ExistsMetaKey, out var chunk)) - { - InvokeChunk(chunk, b, a); - break; - } + InvokeChunk(chunk, b, a); + break; } - - PushValue(b.Contains(a)); - break; } - case OpCode.RET: - { - _callStack.Pop(); - frame.Dispose(); + PushValue(b.Contains(a)); + break; + } - break; - } + case OpCode.RET: + { + _callStack.Pop(); + frame.Dispose(); - case OpCode.INC: - { - a = PopValue(); + break; + } - if (a.Type == DynamicValueType.Table) - { - if (FindMetaFunction(a.Table!, Table.IncrementMetaKey, out var chunk)) - { - InvokeChunk(chunk, a); - break; - } - } - - PushValue(a.Increment()); - break; - } + case OpCode.INC: + { + a = PopValue(); - case OpCode.DEC: + if (a.Type == DynamicValueType.Table) { - a = PopValue(); - - if (a.Type == DynamicValueType.Table) + if (FindMetaFunction(a.Table!, Table.IncrementMetaKey, out var chunk)) { - if (FindMetaFunction(a.Table!, Table.DecrementMetaKey, out var chunk)) - { - InvokeChunk(chunk, a); - break; - } + InvokeChunk(chunk, a); + break; } - - PushValue(a.Decrement()); - break; } + + PushValue(a.Increment()); + break; + } - case OpCode.TABNEW: + case OpCode.DEC: + { + a = PopValue(); + + if (a.Type == DynamicValueType.Table) { - PushValue(new Table()); - break; + if (FindMetaFunction(a.Table!, Table.DecrementMetaKey, out var chunk)) + { + InvokeChunk(chunk, a); + break; + } } + + PushValue(a.Decrement()); + break; + } - case OpCode.ARRNEW: - { - a = PopValue(); + case OpCode.TABNEW: + { + PushValue(new Table()); + break; + } - if (a.Type != DynamicValueType.Number) - { - throw new UnsupportedDynamicValueOperationException("Array size must be a Number."); - } + case OpCode.ARRNEW: + { + a = PopValue(); - PushValue(new Collections.Array((int)a.Number)); - break; + if (a.Type != DynamicValueType.Number) + { + throw new UnsupportedDynamicValueOperationException("Array size must be a Number."); } - case OpCode.ELINIT: - { - b = PopValue(); - a = PopValue(); - c = PeekValue(); + PushValue(new Collections.Array((int)a.Number)); + break; + } - c.SetEntry(b, a); - break; - } + case OpCode.ELINIT: + { + b = PopValue(); + a = PopValue(); + c = PeekValue(); - case OpCode.ELSET: - { - b = PopValue(); // Key - c = PopValue(); // Table - a = PopValue(); // Value + c.SetEntry(b, a); + break; + } + + case OpCode.ELSET: + { + b = PopValue(); // Key + c = PopValue(); // Table + a = PopValue(); // Value - if (c.Type == DynamicValueType.Table) + if (c.Type == DynamicValueType.Table) + { + if (FindMetaFunction(c.Table!, Table.SetMetaKey, out var chunk)) { - if (FindMetaFunction(c.Table!, Table.SetMetaKey, out var chunk)) - { - InvokeChunk(chunk, c, b, a); - break; - } + InvokeChunk(chunk, c, b, a); + break; } - - c.SetEntry(b, a); - break; } + + c.SetEntry(b, a); + break; + } - case OpCode.INDEX: - { - a = PopValue(); // Key - c = PopValue(); // Table + case OpCode.INDEX: + { + a = PopValue(); // Key + c = PopValue(); // Table - if (c.Type == DynamicValueType.String && a.Type == DynamicValueType.String) - { - c = _global.Index("str"); + if (c.Type == DynamicValueType.String && a.Type == DynamicValueType.String) + { + c = _global.Index("str"); - if (c.Type != DynamicValueType.Table) - { - throw new UnsupportedDynamicValueOperationException( - "Attempt to index a string value using a string, but no `str' support table found." - ); - } + if (c.Type != DynamicValueType.Table) + { + throw new UnsupportedDynamicValueOperationException( + "Attempt to index a string value using a string, but no `str' support table found." + ); } + } - if (c.Type == DynamicValueType.Table) + if (c.Type == DynamicValueType.Table) + { + if (!c.Table!.Contains(a)) { - if (!c.Table!.Contains(a)) - { - var mt = c.Table!.MetaTable; + var mt = c.Table!.MetaTable; - if (mt != null) - { - var value = mt[Table.GetMetaKey]; + if (mt != null) + { + var value = mt[Table.GetMetaKey]; - if (value.Type == DynamicValueType.Chunk) - { - InvokeChunk(value.Chunk!, c, a); - break; - } + if (value.Type == DynamicValueType.Chunk) + { + InvokeChunk(value.Chunk!, c, a); + break; + } - if (value.Type == DynamicValueType.Table) - { - PushValue(value.Table!.Index(a)); - break; - } + if (value.Type == DynamicValueType.Table) + { + PushValue(value.Table!.Index(a)); + break; } } } - - PushValue(c.Index(a)); - break; } - case OpCode.TABCLN: - { - var isDeepClone = frame.FetchByte() > 0; - a = PopValue(); + PushValue(c.Index(a)); + break; + } - if (a.Type != DynamicValueType.Table) - { - throw new UnsupportedDynamicValueOperationException( - $"Attempt to clone a {a.Type} value." - ); - } + case OpCode.TABCLN: + { + var isDeepClone = frame.FetchByte() > 0; + a = PopValue(); + + if (a.Type != DynamicValueType.Table) + { + throw new UnsupportedDynamicValueOperationException( + $"Attempt to clone a {a.Type} value." + ); + } - PushValue( - isDeepClone + PushValue( + isDeepClone ? a.Table!.DeepCopy() : a.Table!.ShallowCopy() - ); + ); - break; - } + break; + } - case OpCode.YIELD: - { - var argumentCount = frame.FetchInt32(); + case OpCode.YIELD: + { + var argumentCount = frame.FetchInt32(); - a = PopValue(); // chunk - var args = PopArguments(argumentCount); + a = PopValue(); // chunk + var args = PopArguments(argumentCount); - if (a.Type != DynamicValueType.Chunk) - { - throw new UnsupportedDynamicValueOperationException( - $"Attempt to yield to a {a.Type} value." - ); - } - - var fiber = _fiber.VirtualMachine.Scheduler.CreateFiber( - false, - closureContexts: (Dictionary)frame.Fiber.ClosureContexts + if (a.Type != DynamicValueType.Chunk) + { + throw new UnsupportedDynamicValueOperationException( + $"Attempt to yield to a {a.Type} value." ); - fiber.Schedule(a.Chunk!, args); - fiber.Resume(); - - PushValue(fiber); - _fiber.WaitFor(fiber); - break; } - case OpCode.YRET: - { - a = PopValue(); + var fiber = _fiber.VirtualMachine.Scheduler.CreateFiber( + false, + closureContexts: (Dictionary)frame.Fiber.ClosureContexts + ); + fiber.Schedule(a.Chunk!, args); + fiber.Resume(); - if (a.Type != DynamicValueType.Fiber) - { - throw new UnsupportedDynamicValueOperationException( - $"Attempt to resume from a {a.Type} value. " + - $"Messing with code generation now, are we?" - ); - } + PushValue(fiber); + _fiber.WaitFor(fiber); + break; + } - PushValue(a.Fiber!.PopValue()); - break; - } + case OpCode.YRET: + { + a = PopValue(); - case OpCode.XARGS: + if (a.Type != DynamicValueType.Fiber) { - var mode = frame.FetchByte(); - - if (mode == 0) - { - PushValue(frame.ExtraArguments); - } - else if (mode == 1) - { - for (var i = 0; i < frame.ExtraArguments.Length; i++) - { - PushValue(frame.ExtraArguments[i]); - } - } - break; + throw new UnsupportedDynamicValueOperationException( + $"Attempt to resume from a {a.Type} value. " + + $"Messing with code generation now, are we?" + ); } - case OpCode.EACH: - { - a = PopValue(); - - if (a.Type == DynamicValueType.String) - { - a = Collections.Array.FromString(a.String!); - } + PushValue(a.Fiber!.PopValue()); + break; + } - if (a.Type == DynamicValueType.Table) - { - frame.PushEnumerator(a.Table!); - } - else if (a.Type == DynamicValueType.Array) - { - frame.PushEnumerator(a.Array!); - } - else - { - throw new UnsupportedDynamicValueOperationException( - $"Attempt to iterate over a {a.Type} value." - ); - } + case OpCode.XARGS: + { + var mode = frame.FetchByte(); - break; + if (mode == 0) + { + PushValue(frame.ExtraArguments); } - - case OpCode.NEXT: + else if (mode == 1) { - var isKeyValue = frame.FetchInt32() != 0; - var enumerator = frame.CurrentEnumerator ?? throw new VirtualMachineException( - "Attempt to iterate without an active iterator." - ); - - var next = enumerator.MoveNext(); - - if (next) + for (var i = 0; i < frame.ExtraArguments.Length; i++) { - if (isKeyValue) - { - PushValue(enumerator.Current.Value); - PushValue(enumerator.Current.Key); - } - else - { - PushValue(enumerator.Current.Value); - } + PushValue(frame.ExtraArguments[i]); } - - PushValue(next); - break; } + break; + } + + case OpCode.EACH: + { + a = PopValue(); - case OpCode.EEND: + if (a.Type == DynamicValueType.String) { - frame.PopEnumerator(); - break; + a = Collections.Array.FromString(a.String!); } - case OpCode.ENTER: + if (a.Type == DynamicValueType.Table) { - var blockId = frame.FetchInt32(); - frame.EnterProtectedBlock(blockId); - break; + frame.PushEnumerator(a.Table!); } - - case OpCode.THROW: + else if (a.Type == DynamicValueType.Array) { - _fiber.UnwindTryHandle( - _callStack.ToArray() - ); - break; + frame.PushEnumerator(a.Array!); } - - case OpCode.LEAVE: + else { - frame.ExitProtectedBlock(); - break; + throw new UnsupportedDynamicValueOperationException( + $"Attempt to iterate over a {a.Type} value." + ); } - case OpCode.ERRNEW: - { - a = PopValue(); + break; + } - if (a.Type != DynamicValueType.Table) - { - throw new UnsupportedDynamicValueOperationException( - $"Attempt to create an Error out of a value type '{a.Type}'." - ); - } + case OpCode.NEXT: + { + var isKeyValue = frame.FetchInt32() != 0; + var enumerator = frame.CurrentEnumerator ?? throw new VirtualMachineException( + "Attempt to iterate without an active iterator." + ); - PushValue(new Error(a.Table!)); - break; - } + var next = enumerator.MoveNext(); - default: + if (next) { - throw new VirtualMachineException($"Invalid opcode '{opCode}'."); + if (isKeyValue) + { + PushValue(enumerator.Current.Value); + PushValue(enumerator.Current.Key); + } + else + { + PushValue(enumerator.Current.Value); + } } + + PushValue(next); + break; } - } - private bool FindMetaFunction(Table table, string op, [MaybeNullWhen(false)] out Chunk chunk) - { - if (!table.HasMetaTable) + case OpCode.EEND: + { + frame.PopEnumerator(); + break; + } + + case OpCode.ENTER: { - chunk = null; - return false; + var blockId = frame.FetchInt32(); + frame.EnterProtectedBlock(blockId); + break; } - var value = table.MetaTable![op]; - if (value.Type != DynamicValueType.Chunk) + case OpCode.THROW: { - chunk = null; - return false; + _fiber.UnwindTryHandle( + _callStack.ToArray() + ); + break; } - chunk = value.Chunk!; - return true; + case OpCode.LEAVE: + { + frame.ExitProtectedBlock(); + break; + } + + case OpCode.ERRNEW: + { + a = PopValue(); + + if (a.Type != DynamicValueType.Table) + { + throw new UnsupportedDynamicValueOperationException( + $"Attempt to create an Error out of a value type '{a.Type}'." + ); + } + + PushValue(new Error(a.Table!)); + break; + } + + default: + { + throw new VirtualMachineException($"Invalid opcode '{opCode}'."); + } } + } - private void InvokeChunk(Chunk chunk, params DynamicValue[] args) + private bool FindMetaFunction(Table table, string op, [MaybeNullWhen(false)] out Chunk chunk) + { + if (!table.HasMetaTable) { - _callStack.Push(new ScriptStackFrame(_fiber, chunk, args)); - _fiber.OnChunkInvoke?.Invoke( - _fiber, - chunk, - false - ); + chunk = null; + return false; } - private DynamicValue PopValue() + var value = table.MetaTable![op]; + if (value.Type != DynamicValueType.Chunk) { - lock (_evaluationStack) - { - return _evaluationStack.Pop(); - } + chunk = null; + return false; } - private DynamicValue PeekValue() + chunk = value.Chunk!; + return true; + } + + private void InvokeChunk(Chunk chunk, params DynamicValue[] args) + { + _callStack.Push(new ScriptStackFrame(_fiber, chunk, args)); + _fiber.OnChunkInvoke?.Invoke( + _fiber, + chunk, + false + ); + } + + private DynamicValue PopValue() + { + lock (_evaluationStack) { - lock (_evaluationStack) - { - return _evaluationStack.Peek(); - } + return _evaluationStack.Pop(); } + } - private void PushValue(DynamicValue value) + private DynamicValue PeekValue() + { + lock (_evaluationStack) { - lock (_evaluationStack) - { - _evaluationStack.Push(value); - } + return _evaluationStack.Peek(); } + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private DynamicValue[] PopArguments(int count) + private void PushValue(DynamicValue value) + { + lock (_evaluationStack) { - var args = new DynamicValue[count]; - for (var i = 0; i < count; i++) - { - args[count - i - 1] = PopValue(); - } + _evaluationStack.Push(value); + } + } - return args; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private DynamicValue[] PopArguments(int count) + { + var args = new DynamicValue[count]; + for (var i = 0; i < count; i++) + { + args[count - i - 1] = PopValue(); } + + return args; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Marshaling/IDynamicValueProvider.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Marshaling/IDynamicValueProvider.cs index d56cf9d9..bd685c56 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Marshaling/IDynamicValueProvider.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Marshaling/IDynamicValueProvider.cs @@ -1,9 +1,8 @@ -using EVIL.Ceres.ExecutionEngine.TypeSystem; +namespace EVIL.Ceres.ExecutionEngine.Marshaling; -namespace EVIL.Ceres.ExecutionEngine.Marshaling +using EVIL.Ceres.ExecutionEngine.TypeSystem; + +public interface IDynamicValueProvider { - public interface IDynamicValueProvider - { - DynamicValue ToDynamicValue(); - } + DynamicValue ToDynamicValue(); } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/RecoverableVirtualMachineException.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/RecoverableVirtualMachineException.cs index ac288466..cd2c5a31 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/RecoverableVirtualMachineException.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/RecoverableVirtualMachineException.cs @@ -1,17 +1,16 @@ -using System; +namespace EVIL.Ceres.ExecutionEngine; -namespace EVIL.Ceres.ExecutionEngine +using System; + +public class RecoverableVirtualMachineException : VirtualMachineException { - public class RecoverableVirtualMachineException : VirtualMachineException + internal RecoverableVirtualMachineException(string message, Exception innerException) + : base(message, innerException) { - internal RecoverableVirtualMachineException(string message, Exception innerException) - : base(message, innerException) - { - } + } - internal RecoverableVirtualMachineException(string message) - : base(message) - { - } + internal RecoverableVirtualMachineException(string message) + : base(message) + { } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValue.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValue.cs index 055c24d8..038a594b 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValue.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValue.cs @@ -1,3 +1,7 @@ +namespace EVIL.Ceres.ExecutionEngine.TypeSystem; + +using Collections_Array = EVIL.Ceres.ExecutionEngine.Collections.Array; + using System; using System.IO; using System.Text; @@ -7,352 +11,346 @@ using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.CommonTypes.TypeSystem; -using Array = EVIL.Ceres.ExecutionEngine.Collections.Array; -using Collections_Array = EVIL.Ceres.ExecutionEngine.Collections.Array; - -namespace EVIL.Ceres.ExecutionEngine.TypeSystem +public struct DynamicValue : IEquatable { - public struct DynamicValue : IEquatable - { - public static readonly DynamicValue Nil = new(); - public static readonly DynamicValue One = new((double)1); - public static readonly DynamicValue Zero = new((double)0); - public static readonly DynamicValue True = new(true); - public static readonly DynamicValue False = new(false); - public static readonly DynamicValue EmptyString = new(""); + public static readonly DynamicValue Nil = new(); + public static readonly DynamicValue One = new((double)1); + public static readonly DynamicValue Zero = new((double)0); + public static readonly DynamicValue True = new(true); + public static readonly DynamicValue False = new(false); + public static readonly DynamicValue EmptyString = new(""); - public DynamicValueType Type { get; } - - public double Number { get; } - public string? String { get; } - public bool Boolean { get; } - public Table? Table { get; } - public Collections_Array? Array { get; } - public Fiber? Fiber { get; } - public Chunk? Chunk { get; } - public Error? Error { get; } - public DynamicValueType TypeCode { get; } - public NativeFunction? NativeFunction { get; } - public object? NativeObject { get; } - - public DynamicValue() - { - Type = DynamicValueType.Nil; - } + public DynamicValueType Type { get; } + + public double Number { get; } + public string? String { get; } + public bool Boolean { get; } + public Table? Table { get; } + public Collections_Array? Array { get; } + public Fiber? Fiber { get; } + public Chunk? Chunk { get; } + public Error? Error { get; } + public DynamicValueType TypeCode { get; } + public NativeFunction? NativeFunction { get; } + public object? NativeObject { get; } + + public DynamicValue() + { + Type = DynamicValueType.Nil; + } - public DynamicValue(double value) - { - Number = value; - Type = DynamicValueType.Number; - } + public DynamicValue(double value) + { + Number = value; + Type = DynamicValueType.Number; + } - public DynamicValue(string value) - { - String = value; - Type = DynamicValueType.String; - } + public DynamicValue(string value) + { + String = value; + Type = DynamicValueType.String; + } - public DynamicValue(char value) - { - String = value.ToString(); - Type = DynamicValueType.String; - } + public DynamicValue(char value) + { + String = value.ToString(); + Type = DynamicValueType.String; + } - public DynamicValue(bool value) - { - Boolean = value; - Type = DynamicValueType.Boolean; - } + public DynamicValue(bool value) + { + Boolean = value; + Type = DynamicValueType.Boolean; + } - public DynamicValue(Table value) - { - Table = value; - Type = DynamicValueType.Table; - } + public DynamicValue(Table value) + { + Table = value; + Type = DynamicValueType.Table; + } - public DynamicValue(Collections_Array value) - { - Array = value; - Type = DynamicValueType.Array; - } + public DynamicValue(Collections_Array value) + { + Array = value; + Type = DynamicValueType.Array; + } - public DynamicValue(Fiber value) - { - Fiber = value; - Type = DynamicValueType.Fiber; - } + public DynamicValue(Fiber value) + { + Fiber = value; + Type = DynamicValueType.Fiber; + } - public DynamicValue(Chunk value) - { - Chunk = value; - Type = DynamicValueType.Chunk; - } + public DynamicValue(Chunk value) + { + Chunk = value; + Type = DynamicValueType.Chunk; + } - public DynamicValue(Error value) - { - Error = value; - Type = DynamicValueType.Error; - } + public DynamicValue(Error value) + { + Error = value; + Type = DynamicValueType.Error; + } - public DynamicValue(DynamicValueType value) - { - TypeCode = value; - Type = DynamicValueType.TypeCode; - } + public DynamicValue(DynamicValueType value) + { + TypeCode = value; + Type = DynamicValueType.TypeCode; + } - public DynamicValue(NativeFunction value) - { - NativeFunction = value; - Type = DynamicValueType.NativeFunction; - } + public DynamicValue(NativeFunction value) + { + NativeFunction = value; + Type = DynamicValueType.NativeFunction; + } - public DynamicValue(object? value) - { - NativeObject = value; - Type = DynamicValueType.NativeObject; - } + public DynamicValue(object? value) + { + NativeObject = value; + Type = DynamicValueType.NativeObject; + } - public void Serialize(Stream stream, bool throwOnUnsupported = false) - => DynamicValueSerializer.Serialize(this, stream, throwOnUnsupported); + public void Serialize(Stream stream, bool throwOnUnsupported = false) + => DynamicValueSerializer.Serialize(this, stream, throwOnUnsupported); - public static DynamicValue Deserialize(Stream stream) - => DynamicValueSerializer.Deserialize(stream); + public static DynamicValue Deserialize(Stream stream) + => DynamicValueSerializer.Deserialize(stream); - public static bool IsTruth(DynamicValue value) - => value != Nil - && value != Zero - && value != False; + public static bool IsTruth(DynamicValue value) + => value != Nil + && value != Zero + && value != False; - public override string ToString() - { - var sb = new StringBuilder(); + public override string ToString() + { + var sb = new StringBuilder(); - sb.Append($"<{Type}>"); + sb.Append($"<{Type}>"); - switch (Type) - { - case DynamicValueType.Number: - sb.Append(" "); - sb.Append(Number); - break; + switch (Type) + { + case DynamicValueType.Number: + sb.Append(" "); + sb.Append(Number); + break; - case DynamicValueType.String: - sb.Append(" "); - sb.Append($"\"{String}\""); - break; + case DynamicValueType.String: + sb.Append(" "); + sb.Append($"\"{String}\""); + break; - case DynamicValueType.Boolean: - sb.Append(" "); - sb.Append(Boolean); - break; + case DynamicValueType.Boolean: + sb.Append(" "); + sb.Append(Boolean); + break; - case DynamicValueType.Error: + case DynamicValueType.Error: + { + var msg = Error!["msg"]; + + if (msg == DynamicValueType.String) + { + sb.Append($"'{msg.String}'"); + } + else { - var msg = Error!["msg"]; - - if (msg == DynamicValueType.String) - { - sb.Append($"'{msg.String}'"); - } - else - { - sb.Append($"[{msg.Error!.Length} userdata record(s)]"); - } - - break; + sb.Append($"[{msg.Error!.Length} userdata record(s)]"); } + + break; + } - case DynamicValueType.Nil: - break; + case DynamicValueType.Nil: + break; - default: - sb.Append(" "); - sb.Append(this.ConvertToString()); - break; - } - - return sb.ToString(); + default: + sb.Append(" "); + sb.Append(this.ConvertToString()); + break; } - public bool Equals(DynamicValue other) - => Type == other.Type - && Number.Equals(other.Number) - && String == other.String - && Boolean == other.Boolean - && Equals(Table, other.Table) - && Equals(Array, other.Array) - && Equals(Fiber, other.Fiber) - && Equals(Chunk, other.Chunk) - && Equals(Error, other.Error) - && TypeCode == other.TypeCode - && Equals(NativeFunction, other.NativeFunction); - - public override bool Equals(object? obj) - => obj is DynamicValue other - && Equals(other); - - public override int GetHashCode() - { - var hashCode = new HashCode(); + return sb.ToString(); + } + + public bool Equals(DynamicValue other) + => Type == other.Type + && Number.Equals(other.Number) + && String == other.String + && Boolean == other.Boolean + && Equals(Table, other.Table) + && Equals(Array, other.Array) + && Equals(Fiber, other.Fiber) + && Equals(Chunk, other.Chunk) + && Equals(Error, other.Error) + && TypeCode == other.TypeCode + && Equals(NativeFunction, other.NativeFunction); + + public override bool Equals(object? obj) + => obj is DynamicValue other + && Equals(other); + + public override int GetHashCode() + { + var hashCode = new HashCode(); - hashCode.Add((int)Type); - hashCode.Add(Number); - hashCode.Add(String); - hashCode.Add(Boolean); - hashCode.Add(Table); - hashCode.Add(Array); - hashCode.Add(Fiber); - hashCode.Add(Chunk); - hashCode.Add(Error); - hashCode.Add(TypeCode); - hashCode.Add(NativeFunction); - hashCode.Add(NativeObject); + hashCode.Add((int)Type); + hashCode.Add(Number); + hashCode.Add(String); + hashCode.Add(Boolean); + hashCode.Add(Table); + hashCode.Add(Array); + hashCode.Add(Fiber); + hashCode.Add(Chunk); + hashCode.Add(Error); + hashCode.Add(TypeCode); + hashCode.Add(NativeFunction); + hashCode.Add(NativeObject); - return hashCode.ToHashCode(); - } + return hashCode.ToHashCode(); + } - public static bool operator ==(DynamicValue left, DynamicValue right) - => left.Equals(right); - - public static bool operator !=(DynamicValue left, DynamicValue right) - => !left.Equals(right); - - public static implicit operator DynamicValue(double value) => new(value); - public static implicit operator DynamicValue(string value) => new(value); - public static implicit operator DynamicValue(char value) => new(value.ToString()); - public static implicit operator DynamicValue(bool value) => new(value); - public static implicit operator DynamicValue(Table value) => new(value); - public static implicit operator DynamicValue(Collections_Array value) => new(value); - public static implicit operator DynamicValue(Fiber value) => new(value); - public static implicit operator DynamicValue(Chunk value) => new(value); - public static implicit operator DynamicValue(Error value) => new(value); - public static implicit operator DynamicValue(DynamicValueType value) => new(value); - public static implicit operator DynamicValue(NativeFunction value) => new(value); - public static DynamicValue FromObject(object value) => new(value); - - public static explicit operator double(DynamicValue value) - { - if (value.Type != DynamicValueType.Number) - throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a Number."); + public static bool operator ==(DynamicValue left, DynamicValue right) + => left.Equals(right); + + public static bool operator !=(DynamicValue left, DynamicValue right) + => !left.Equals(right); + + public static implicit operator DynamicValue(double value) => new(value); + public static implicit operator DynamicValue(string value) => new(value); + public static implicit operator DynamicValue(char value) => new(value.ToString()); + public static implicit operator DynamicValue(bool value) => new(value); + public static implicit operator DynamicValue(Table value) => new(value); + public static implicit operator DynamicValue(Collections_Array value) => new(value); + public static implicit operator DynamicValue(Fiber value) => new(value); + public static implicit operator DynamicValue(Chunk value) => new(value); + public static implicit operator DynamicValue(Error value) => new(value); + public static implicit operator DynamicValue(DynamicValueType value) => new(value); + public static implicit operator DynamicValue(NativeFunction value) => new(value); + public static DynamicValue FromObject(object value) => new(value); + + public static explicit operator double(DynamicValue value) + { + if (value.Type != DynamicValueType.Number) + throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a Number."); - return value.Number; - } + return value.Number; + } - public static explicit operator float(DynamicValue value) - { - if (value.Type != DynamicValueType.Number) - throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a Number."); + public static explicit operator float(DynamicValue value) + { + if (value.Type != DynamicValueType.Number) + throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a Number."); - return (float)value.Number; - } + return (float)value.Number; + } - public static explicit operator int(DynamicValue value) - { - if (value.Type != DynamicValueType.Number) - throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a Number."); + public static explicit operator int(DynamicValue value) + { + if (value.Type != DynamicValueType.Number) + throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a Number."); - return (int)value.Number; - } + return (int)value.Number; + } - public static explicit operator uint(DynamicValue value) - { - if (value.Type != DynamicValueType.Number) - throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a Number."); + public static explicit operator uint(DynamicValue value) + { + if (value.Type != DynamicValueType.Number) + throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a Number."); - return (uint)value.Number; - } + return (uint)value.Number; + } - public static explicit operator long(DynamicValue value) - { - if (value.Type != DynamicValueType.Number) - throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a Number."); + public static explicit operator long(DynamicValue value) + { + if (value.Type != DynamicValueType.Number) + throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a Number."); - return (long)value.Number; - } + return (long)value.Number; + } - public static explicit operator ulong(DynamicValue value) - { - if (value.Type != DynamicValueType.Number) - throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a Number."); + public static explicit operator ulong(DynamicValue value) + { + if (value.Type != DynamicValueType.Number) + throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a Number."); - return (ulong)value.Number; - } + return (ulong)value.Number; + } - public static explicit operator string(DynamicValue value) - { - return value.ConvertToString().String!; - } + public static explicit operator string(DynamicValue value) + { + return value.ConvertToString().String!; + } - public static explicit operator bool(DynamicValue value) - { - if (value.Type != DynamicValueType.Boolean) - throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a Boolean."); + public static explicit operator bool(DynamicValue value) + { + if (value.Type != DynamicValueType.Boolean) + throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a Boolean."); - return value.Boolean; - } + return value.Boolean; + } - public static explicit operator Table(DynamicValue value) - { - if (value.Type != DynamicValueType.Table) - throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a Table."); + public static explicit operator Table(DynamicValue value) + { + if (value.Type != DynamicValueType.Table) + throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a Table."); - return value.Table!; - } + return value.Table!; + } - public static explicit operator Collections_Array(DynamicValue value) - { - if (value.Type != DynamicValueType.Array) - throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to an Array."); + public static explicit operator Collections_Array(DynamicValue value) + { + if (value.Type != DynamicValueType.Array) + throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to an Array."); - return value.Array!; - } + return value.Array!; + } - public static explicit operator Fiber(DynamicValue value) - { - if (value.Type != DynamicValueType.Fiber) - throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a Fiber."); + public static explicit operator Fiber(DynamicValue value) + { + if (value.Type != DynamicValueType.Fiber) + throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a Fiber."); - return value.Fiber!; - } + return value.Fiber!; + } - public static explicit operator Chunk(DynamicValue value) - { - if (value.Type != DynamicValueType.Chunk) - throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a Chunk."); + public static explicit operator Chunk(DynamicValue value) + { + if (value.Type != DynamicValueType.Chunk) + throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a Chunk."); - return value.Chunk!; - } + return value.Chunk!; + } - public static explicit operator Error(DynamicValue value) - { - if (value.Type != DynamicValueType.Error) - throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to an Error."); + public static explicit operator Error(DynamicValue value) + { + if (value.Type != DynamicValueType.Error) + throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to an Error."); - return value.Error!; - } + return value.Error!; + } - public static explicit operator DynamicValueType(DynamicValue value) - { - if (value.Type != DynamicValueType.TypeCode) - throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a TypeCode"); + public static explicit operator DynamicValueType(DynamicValue value) + { + if (value.Type != DynamicValueType.TypeCode) + throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a TypeCode"); - return value.TypeCode; - } + return value.TypeCode; + } - public static explicit operator NativeFunction(DynamicValue value) - { - if (value.Type != DynamicValueType.NativeFunction) - throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a NativeFunction."); + public static explicit operator NativeFunction(DynamicValue value) + { + if (value.Type != DynamicValueType.NativeFunction) + throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a NativeFunction."); - return value.NativeFunction!; - } + return value.NativeFunction!; + } - public static object ToObject(DynamicValue value) - { - if (value.Type != DynamicValueType.NativeObject) - throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a NativeObject."); + public static object ToObject(DynamicValue value) + { + if (value.Type != DynamicValueType.NativeObject) + throw new InvalidCastException($"Cannot cast dynamic type '{value.Type}' to a NativeObject."); - return value.NativeObject!; - } - } + return value.NativeObject!; + } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Arithmetic.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Arithmetic.cs index 7ce32fcb..3b1a578a 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Arithmetic.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Arithmetic.cs @@ -1,119 +1,118 @@ +namespace EVIL.Ceres.ExecutionEngine.TypeSystem; + using System; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine.TypeSystem +public static partial class DynamicValueOperations { - public static partial class DynamicValueOperations + public static DynamicValue Add(this DynamicValue a, DynamicValue b) { - public static DynamicValue Add(this DynamicValue a, DynamicValue b) + if (a.Type == DynamicValueType.Number && b.Type == DynamicValueType.Number) { - if (a.Type == DynamicValueType.Number && b.Type == DynamicValueType.Number) - { - return new(a.Number + b.Number); - } - - if (a.Type == DynamicValueType.String && b.Type == DynamicValueType.String) - { - return new(a.String + b.String); - } - - throw new UnsupportedDynamicValueOperationException( - $"Attempt to add a {a.Type} to a {b.Type}." - ); + return new(a.Number + b.Number); } - public static DynamicValue Subtract(this DynamicValue a, DynamicValue b) + if (a.Type == DynamicValueType.String && b.Type == DynamicValueType.String) { - if (a.Type == DynamicValueType.Number && b.Type == DynamicValueType.Number) - { - return new(a.Number - b.Number); - } - - throw new UnsupportedDynamicValueOperationException( - $"Attempt to subtract a {b.Type} from a {a.Type}." - ); + return new(a.String + b.String); } - public static DynamicValue Multiply(this DynamicValue a, DynamicValue b) + throw new UnsupportedDynamicValueOperationException( + $"Attempt to add a {a.Type} to a {b.Type}." + ); + } + + public static DynamicValue Subtract(this DynamicValue a, DynamicValue b) + { + if (a.Type == DynamicValueType.Number && b.Type == DynamicValueType.Number) { - if (a.Type == DynamicValueType.Number && b.Type == DynamicValueType.Number) - { - return new(a.Number * b.Number); - } + return new(a.Number - b.Number); + } + + throw new UnsupportedDynamicValueOperationException( + $"Attempt to subtract a {b.Type} from a {a.Type}." + ); + } - throw new UnsupportedDynamicValueOperationException( - $"Attempt to multiply a {a.Type} by a {b.Type}." - ); + public static DynamicValue Multiply(this DynamicValue a, DynamicValue b) + { + if (a.Type == DynamicValueType.Number && b.Type == DynamicValueType.Number) + { + return new(a.Number * b.Number); } - public static DynamicValue DivideBy(this DynamicValue a, DynamicValue b) + throw new UnsupportedDynamicValueOperationException( + $"Attempt to multiply a {a.Type} by a {b.Type}." + ); + } + + public static DynamicValue DivideBy(this DynamicValue a, DynamicValue b) + { + if (a.Type == DynamicValueType.Number || b.Type == DynamicValueType.Number) { - if (a.Type == DynamicValueType.Number || b.Type == DynamicValueType.Number) + if (b.Number == 0) { - if (b.Number == 0) - { - throw new DivisionByZeroException(); - } - - return new(a.Number / b.Number); + throw new DivisionByZeroException(); } - - throw new UnsupportedDynamicValueOperationException( - $"Attempt to divide a {a.Type} by a {b.Type}." - ); + + return new(a.Number / b.Number); } + + throw new UnsupportedDynamicValueOperationException( + $"Attempt to divide a {a.Type} by a {b.Type}." + ); + } - public static DynamicValue Modulo(this DynamicValue a, DynamicValue b) + public static DynamicValue Modulo(this DynamicValue a, DynamicValue b) + { + if (a.Type == DynamicValueType.Number || b.Type == DynamicValueType.Number) { - if (a.Type == DynamicValueType.Number || b.Type == DynamicValueType.Number) + if (b.Number == 0) { - if (b.Number == 0) - { - throw new DivisionByZeroException(); - } - - return new(a.Number - b.Number * Math.Floor(a.Number / b.Number)); + throw new DivisionByZeroException(); } - throw new UnsupportedDynamicValueOperationException( - $"Attempt to perform a modulo operation using a {a.Type} and a {b.Type}." - ); + return new(a.Number - b.Number * Math.Floor(a.Number / b.Number)); } - public static DynamicValue ArithmeticallyNegate(this DynamicValue a) - { - if (a.Type == DynamicValueType.Number) - { - return new(-a.Number); - } + throw new UnsupportedDynamicValueOperationException( + $"Attempt to perform a modulo operation using a {a.Type} and a {b.Type}." + ); + } - throw new UnsupportedDynamicValueOperationException( - $"Attempt to arithmetically negate a {a.Type}." - ); + public static DynamicValue ArithmeticallyNegate(this DynamicValue a) + { + if (a.Type == DynamicValueType.Number) + { + return new(-a.Number); } - public static DynamicValue Increment(this DynamicValue a) + throw new UnsupportedDynamicValueOperationException( + $"Attempt to arithmetically negate a {a.Type}." + ); + } + + public static DynamicValue Increment(this DynamicValue a) + { + if (a.Type == DynamicValueType.Number) { - if (a.Type == DynamicValueType.Number) - { - return new(a.Number + 1); - } - - throw new UnsupportedDynamicValueOperationException( - $"Attempt to increment a {a.Type}." - ); + return new(a.Number + 1); } + + throw new UnsupportedDynamicValueOperationException( + $"Attempt to increment a {a.Type}." + ); + } - public static DynamicValue Decrement(this DynamicValue a) + public static DynamicValue Decrement(this DynamicValue a) + { + if (a.Type == DynamicValueType.Number) { - if (a.Type == DynamicValueType.Number) - { - return new(a.Number - 1); - } - - throw new UnsupportedDynamicValueOperationException( - $"Attempt to decrement a {a.Type}." - ); + return new(a.Number - 1); } + + throw new UnsupportedDynamicValueOperationException( + $"Attempt to decrement a {a.Type}." + ); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Bitwise.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Bitwise.cs index a0ab9420..2976d14e 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Bitwise.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Bitwise.cs @@ -1,70 +1,69 @@ +namespace EVIL.Ceres.ExecutionEngine.TypeSystem; + using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine.TypeSystem +public static partial class DynamicValueOperations { - public static partial class DynamicValueOperations + public static DynamicValue BitwiseNegate(this DynamicValue a) { - public static DynamicValue BitwiseNegate(this DynamicValue a) + if (a.Type == DynamicValueType.Number) { - if (a.Type == DynamicValueType.Number) - { - return new(~(long)a.Number); - } - - throw new UnsupportedDynamicValueOperationException( - $"Attempt to bitwise-not a {a.Type}." - ); + return new(~(long)a.Number); } + + throw new UnsupportedDynamicValueOperationException( + $"Attempt to bitwise-not a {a.Type}." + ); + } - public static DynamicValue BitwiseAnd(this DynamicValue a, DynamicValue b) + public static DynamicValue BitwiseAnd(this DynamicValue a, DynamicValue b) + { + if (a.Type == DynamicValueType.Number && b.Type == DynamicValueType.Number) { - if (a.Type == DynamicValueType.Number && b.Type == DynamicValueType.Number) - { - return new((long)a.Number & (long)b.Number); - } - - if (a.Type == DynamicValueType.Boolean && b.Type == DynamicValueType.Boolean) - { - return new(a.Boolean & b.Boolean); - } - - throw new UnsupportedDynamicValueOperationException( - $"Attempt to bitwise-and a {a.Type} and a {b.Type}." - ); + return new((long)a.Number & (long)b.Number); } - public static DynamicValue BitwiseOr(this DynamicValue a, DynamicValue b) + if (a.Type == DynamicValueType.Boolean && b.Type == DynamicValueType.Boolean) { - if (a.Type == DynamicValueType.Number && b.Type == DynamicValueType.Number) - { - return new((long)a.Number | (long)b.Number); - } + return new(a.Boolean & b.Boolean); + } - if (a.Type == DynamicValueType.Boolean && b.Type == DynamicValueType.Boolean) - { - return new(a.Boolean | b.Boolean); - } + throw new UnsupportedDynamicValueOperationException( + $"Attempt to bitwise-and a {a.Type} and a {b.Type}." + ); + } + + public static DynamicValue BitwiseOr(this DynamicValue a, DynamicValue b) + { + if (a.Type == DynamicValueType.Number && b.Type == DynamicValueType.Number) + { + return new((long)a.Number | (long)b.Number); + } - throw new UnsupportedDynamicValueOperationException( - $"Attempt to bitwise-or a {a.Type} and a {b.Type}." - ); + if (a.Type == DynamicValueType.Boolean && b.Type == DynamicValueType.Boolean) + { + return new(a.Boolean | b.Boolean); } + + throw new UnsupportedDynamicValueOperationException( + $"Attempt to bitwise-or a {a.Type} and a {b.Type}." + ); + } - public static DynamicValue BitwiseXor(this DynamicValue a, DynamicValue b) + public static DynamicValue BitwiseXor(this DynamicValue a, DynamicValue b) + { + if (a.Type == DynamicValueType.Number && b.Type == DynamicValueType.Number) { - if (a.Type == DynamicValueType.Number && b.Type == DynamicValueType.Number) - { - return new((long)a.Number ^ (long)b.Number); - } - - if (a.Type == DynamicValueType.Boolean && b.Type == DynamicValueType.Boolean) - { - return new(a.Boolean ^ b.Boolean); - } + return new((long)a.Number ^ (long)b.Number); + } - throw new UnsupportedDynamicValueOperationException( - $"Attempt to bitwise-or a {a.Type} and a {b.Type}." - ); + if (a.Type == DynamicValueType.Boolean && b.Type == DynamicValueType.Boolean) + { + return new(a.Boolean ^ b.Boolean); } + + throw new UnsupportedDynamicValueOperationException( + $"Attempt to bitwise-or a {a.Type} and a {b.Type}." + ); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Collection.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Collection.cs index 3b8bd640..80e3549f 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Collection.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Collection.cs @@ -1,37 +1,35 @@ -using EVIL.CommonTypes.TypeSystem; +namespace EVIL.Ceres.ExecutionEngine.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine.TypeSystem -{ - using EVIL.Ceres.ExecutionEngine.Marshaling; +using EVIL.Ceres.ExecutionEngine.Collections; +using EVIL.CommonTypes.TypeSystem; - public partial class DynamicValueOperations +public partial class DynamicValueOperations +{ + public static DynamicValue SetEntry(this DynamicValue a, DynamicValue key, DynamicValue value) { - public static DynamicValue SetEntry(this DynamicValue a, DynamicValue key, DynamicValue value) + if (a.Type == DynamicValueType.Table) { - if (a.Type == DynamicValueType.Table) - { - a.Table!.Set(key, value); - } - else if (a.Type == DynamicValueType.Array) - { - a.Array![key] = value; - } - else if (a.Type == DynamicValueType.Error) - { - a.Error![key] = value; - } - else if (a.Type == DynamicValueType.NativeObject && a.NativeObject is IWriteableObject writeable) - { - writeable.Set(key, value); - } - else - { - throw new UnsupportedDynamicValueOperationException( - $"Attempt to set an entry of a {a.Type} which is not an Array, a Table, nor a writeable object." - ); - } - - return value; + a.Table!.Set(key, value); + } + else if (a.Type == DynamicValueType.Array) + { + a.Array![key] = value; + } + else if (a.Type == DynamicValueType.Error) + { + a.Error![key] = value; + } + else if (a.Type == DynamicValueType.NativeObject && a.NativeObject is IWriteableObject writeable) + { + writeable.Set(key, value); } + else + { + throw new UnsupportedDynamicValueOperationException( + $"Attempt to set an entry of a {a.Type} which is not an Array, a Table, nor a writeable object." + ); + } + + return value; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Comparison.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Comparison.cs index a19639cd..7b36964a 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Comparison.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Comparison.cs @@ -1,206 +1,206 @@ -using EVIL.CommonTypes.TypeSystem; +namespace EVIL.Ceres.ExecutionEngine.TypeSystem; + using static EVIL.Ceres.ExecutionEngine.TypeSystem.DynamicValue; -namespace EVIL.Ceres.ExecutionEngine.TypeSystem +using EVIL.CommonTypes.TypeSystem; + +public static partial class DynamicValueOperations { - public static partial class DynamicValueOperations + public static DynamicValue IsDeeplyEqualTo(this DynamicValue a, DynamicValue b) { - public static DynamicValue IsDeeplyEqualTo(this DynamicValue a, DynamicValue b) - { - if (a.Type == DynamicValueType.Table && b.Type == DynamicValueType.Table) - { - return new(a.Table!.IsDeeplyEqualTo(b.Table!)); - } - - if (a.Type == DynamicValueType.Array && b.Type == DynamicValueType.Array) - { - return new(a.Array!.IsDeeplyEqualTo(b.Array!)); - } - - if (a.Type == DynamicValueType.Error && b.Type == DynamicValueType.Error) - { - return new(a.Error!.IsDeeplyEqualTo(b.Error!)); - } - - try - { - return IsEqualTo(a, b); - } - catch (UnsupportedDynamicValueOperationException) - { - throw new UnsupportedDynamicValueOperationException( - $"Attempt to deeply compare (<==>) a {a.Type} with a {b.Type}." - ); - } - } - - public static DynamicValue IsDeeplyNotEqualTo(this DynamicValue a, DynamicValue b) - { - if (a.Type == DynamicValueType.Table && b.Type == DynamicValueType.Table) - { - return new(!a.Table!.IsDeeplyEqualTo(b.Table!)); - } + if (a.Type == DynamicValueType.Table && b.Type == DynamicValueType.Table) + { + return new(a.Table!.IsDeeplyEqualTo(b.Table!)); + } + + if (a.Type == DynamicValueType.Array && b.Type == DynamicValueType.Array) + { + return new(a.Array!.IsDeeplyEqualTo(b.Array!)); + } + + if (a.Type == DynamicValueType.Error && b.Type == DynamicValueType.Error) + { + return new(a.Error!.IsDeeplyEqualTo(b.Error!)); + } + + try + { + return IsEqualTo(a, b); + } + catch (UnsupportedDynamicValueOperationException) + { + throw new UnsupportedDynamicValueOperationException( + $"Attempt to deeply compare (<==>) a {a.Type} with a {b.Type}." + ); + } + } + + public static DynamicValue IsDeeplyNotEqualTo(this DynamicValue a, DynamicValue b) + { + if (a.Type == DynamicValueType.Table && b.Type == DynamicValueType.Table) + { + return new(!a.Table!.IsDeeplyEqualTo(b.Table!)); + } - if (a.Type == DynamicValueType.Array && b.Type == DynamicValueType.Array) - { - return new(!a.Array!.IsDeeplyEqualTo(b.Array!)); - } + if (a.Type == DynamicValueType.Array && b.Type == DynamicValueType.Array) + { + return new(!a.Array!.IsDeeplyEqualTo(b.Array!)); + } - if (a.Type == DynamicValueType.Error && b.Type == DynamicValueType.Error) - { - return new(!a.Error!.IsDeeplyEqualTo(b.Error!)); - } - - try - { - return IsNotEqualTo(a, b); - } - catch (UnsupportedDynamicValueOperationException) - { - throw new UnsupportedDynamicValueOperationException( - $"Attempt to deeply compare () a {a.Type} with a {b.Type}." - ); - } + if (a.Type == DynamicValueType.Error && b.Type == DynamicValueType.Error) + { + return new(!a.Error!.IsDeeplyEqualTo(b.Error!)); } - public static DynamicValue IsEqualTo(this DynamicValue a, DynamicValue b) + try { - if (a.Type != b.Type) - return False; + return IsNotEqualTo(a, b); + } + catch (UnsupportedDynamicValueOperationException) + { + throw new UnsupportedDynamicValueOperationException( + $"Attempt to deeply compare () a {a.Type} with a {b.Type}." + ); + } + } + + public static DynamicValue IsEqualTo(this DynamicValue a, DynamicValue b) + { + if (a.Type != b.Type) + return False; - switch (a.Type) - { - case DynamicValueType.Nil: - return b.Type == DynamicValueType.Nil; + switch (a.Type) + { + case DynamicValueType.Nil: + return b.Type == DynamicValueType.Nil; - case DynamicValueType.Number: - return a.Number.Equals(b.Number); + case DynamicValueType.Number: + return a.Number.Equals(b.Number); - case DynamicValueType.String: - return a.String == b.String; + case DynamicValueType.String: + return a.String == b.String; - case DynamicValueType.Boolean: - return a.Boolean == b.Boolean; + case DynamicValueType.Boolean: + return a.Boolean == b.Boolean; - case DynamicValueType.Table: - return a.Table == b.Table; + case DynamicValueType.Table: + return a.Table == b.Table; - case DynamicValueType.Fiber: - return a.Fiber == b.Fiber; + case DynamicValueType.Fiber: + return a.Fiber == b.Fiber; - case DynamicValueType.Chunk: - return a.Chunk == b.Chunk; + case DynamicValueType.Chunk: + return a.Chunk == b.Chunk; - case DynamicValueType.Error: - return a.Error == b.Error; + case DynamicValueType.Error: + return a.Error == b.Error; - case DynamicValueType.TypeCode: - return a.TypeCode == b.TypeCode; + case DynamicValueType.TypeCode: + return a.TypeCode == b.TypeCode; - case DynamicValueType.NativeFunction: - return a.NativeFunction == b.NativeFunction; + case DynamicValueType.NativeFunction: + return a.NativeFunction == b.NativeFunction; - case DynamicValueType.NativeObject: - return a.NativeObject == b.NativeObject; - } - - throw new UnsupportedDynamicValueOperationException( - $"Attempt to compare (==) a {a.Type} with a {b.Type}." - ); + case DynamicValueType.NativeObject: + return a.NativeObject == b.NativeObject; } - public static DynamicValue IsNotEqualTo(this DynamicValue a, DynamicValue b) - { - if (a.Type != b.Type) - return True; + throw new UnsupportedDynamicValueOperationException( + $"Attempt to compare (==) a {a.Type} with a {b.Type}." + ); + } - switch (a.Type) - { - case DynamicValueType.Nil: - return b.Type != DynamicValueType.Nil; + public static DynamicValue IsNotEqualTo(this DynamicValue a, DynamicValue b) + { + if (a.Type != b.Type) + return True; + + switch (a.Type) + { + case DynamicValueType.Nil: + return b.Type != DynamicValueType.Nil; - case DynamicValueType.Number: - return !a.Number.Equals(b.Number); + case DynamicValueType.Number: + return !a.Number.Equals(b.Number); - case DynamicValueType.String: - return a.String != b.String; + case DynamicValueType.String: + return a.String != b.String; - case DynamicValueType.Boolean: - return a.Boolean != b.Boolean; + case DynamicValueType.Boolean: + return a.Boolean != b.Boolean; - case DynamicValueType.Table: - return a.Table != b.Table; + case DynamicValueType.Table: + return a.Table != b.Table; - case DynamicValueType.Fiber: - return a.Fiber != b.Fiber; + case DynamicValueType.Fiber: + return a.Fiber != b.Fiber; - case DynamicValueType.Chunk: - return a.Chunk != b.Chunk; + case DynamicValueType.Chunk: + return a.Chunk != b.Chunk; - case DynamicValueType.Error: - return a.Error != b.Error; + case DynamicValueType.Error: + return a.Error != b.Error; - case DynamicValueType.TypeCode: - return a.TypeCode != b.TypeCode; + case DynamicValueType.TypeCode: + return a.TypeCode != b.TypeCode; - case DynamicValueType.NativeFunction: - return a.NativeFunction != b.NativeFunction; + case DynamicValueType.NativeFunction: + return a.NativeFunction != b.NativeFunction; - case DynamicValueType.NativeObject: - return a.NativeObject != b.NativeObject; - } - - throw new UnsupportedDynamicValueOperationException( - $"Attempt to compare (!=) a {a.Type} with a {b.Type}." - ); + case DynamicValueType.NativeObject: + return a.NativeObject != b.NativeObject; } - public static DynamicValue IsGreaterThan(this DynamicValue a, DynamicValue b) - { - if (a.Type == DynamicValueType.Number && b.Type == DynamicValueType.Number) - { - return new(a.Number > b.Number); - } + throw new UnsupportedDynamicValueOperationException( + $"Attempt to compare (!=) a {a.Type} with a {b.Type}." + ); + } - throw new UnsupportedDynamicValueOperationException( - $"Attempt to compare (>) a {a.Type} with a {b.Type}." - ); + public static DynamicValue IsGreaterThan(this DynamicValue a, DynamicValue b) + { + if (a.Type == DynamicValueType.Number && b.Type == DynamicValueType.Number) + { + return new(a.Number > b.Number); } - public static DynamicValue IsLessThan(this DynamicValue a, DynamicValue b) - { - if (a.Type == DynamicValueType.Number && b.Type == DynamicValueType.Number) - { - return new(a.Number < b.Number); - } + throw new UnsupportedDynamicValueOperationException( + $"Attempt to compare (>) a {a.Type} with a {b.Type}." + ); + } - throw new UnsupportedDynamicValueOperationException( - $"Attempt to compare (<) a {a.Type} with a {b.Type}." - ); + public static DynamicValue IsLessThan(this DynamicValue a, DynamicValue b) + { + if (a.Type == DynamicValueType.Number && b.Type == DynamicValueType.Number) + { + return new(a.Number < b.Number); } - public static DynamicValue IsGreaterThanOrEqualTo(this DynamicValue a, DynamicValue b) - { - if (a.Type == DynamicValueType.Number && b.Type == DynamicValueType.Number) - { - return new(a.Number >= b.Number); - } + throw new UnsupportedDynamicValueOperationException( + $"Attempt to compare (<) a {a.Type} with a {b.Type}." + ); + } - throw new UnsupportedDynamicValueOperationException( - $"Attempt to compare (>=) a {a.Type} with a {b.Type}." - ); + public static DynamicValue IsGreaterThanOrEqualTo(this DynamicValue a, DynamicValue b) + { + if (a.Type == DynamicValueType.Number && b.Type == DynamicValueType.Number) + { + return new(a.Number >= b.Number); } - public static DynamicValue IsLessThanOrEqualTo(this DynamicValue a, DynamicValue b) - { - if (a.Type == DynamicValueType.Number && b.Type == DynamicValueType.Number) - { - return new(a.Number <= b.Number); - } + throw new UnsupportedDynamicValueOperationException( + $"Attempt to compare (>=) a {a.Type} with a {b.Type}." + ); + } - throw new UnsupportedDynamicValueOperationException( - $"Attempt to compare (<=) a {a.Type} with a {b.Type}." - ); + public static DynamicValue IsLessThanOrEqualTo(this DynamicValue a, DynamicValue b) + { + if (a.Type == DynamicValueType.Number && b.Type == DynamicValueType.Number) + { + return new(a.Number <= b.Number); } + + throw new UnsupportedDynamicValueOperationException( + $"Attempt to compare (<=) a {a.Type} with a {b.Type}." + ); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Conversion.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Conversion.cs index 008882bb..e35b54bf 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Conversion.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Conversion.cs @@ -1,122 +1,134 @@ -using System; +namespace EVIL.Ceres.ExecutionEngine.TypeSystem; + +using System; using System.Globalization; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine.TypeSystem +public static partial class DynamicValueOperations { - public static partial class DynamicValueOperations + public static DynamicValue ConvertToString(this DynamicValue a) { - public static DynamicValue ConvertToString(this DynamicValue a) + switch (a.Type) { - switch (a.Type) + case DynamicValueType.Nil: + return "nil"; + + case DynamicValueType.Number: + return a.Number.ToString(CultureInfo.InvariantCulture); + + case DynamicValueType.String: + return a.String!; + + case DynamicValueType.Boolean: + return a.Boolean.ToString().ToLowerInvariant(); + + case DynamicValueType.Table: + return $"Table {a.Table!.Length}"; + + case DynamicValueType.Array: + return $"Array {a.Array!.Length}"; + + case DynamicValueType.Fiber: { - case DynamicValueType.Nil: - return "nil"; - case DynamicValueType.Number: - return a.Number.ToString(CultureInfo.InvariantCulture); - case DynamicValueType.String: - return a.String!; - case DynamicValueType.Boolean: - return a.Boolean.ToString().ToLowerInvariant(); - case DynamicValueType.Table: - return $"Table {a.Table!.Length}"; - case DynamicValueType.Array: - return $"Array {a.Array!.Length}"; - case DynamicValueType.Fiber: + unsafe { - unsafe - { - var fib = a.Fiber!; - var reference = __makeref(fib); + var fib = a.Fiber!; + var reference = __makeref(fib); -#pragma warning disable 8500 - return $"Fiber {**(IntPtr**)&reference}"; -#pragma warning restore 8500 - } + #pragma warning disable 8500 + return $"Fiber {**(IntPtr**)&reference}"; + #pragma warning restore 8500 } - case DynamicValueType.Chunk: - return $"Function {a.Chunk!.Name}({a.Chunk.ParameterCount})"; - case DynamicValueType.Error: + } + case DynamicValueType.Chunk: + return $"Function {a.Chunk!.Name}({a.Chunk.ParameterCount})"; + + case DynamicValueType.Error: + { + if (a.Error!["msg"].Type == DynamicValueType.String) { - if (a.Error!["msg"].Type == DynamicValueType.String) - { - return $"Error[{a.Error["msg"].String}]"; - } - else - { - return $"Error[{a.Error.Length}]"; - } + return $"Error[{a.Error["msg"].String}]"; } - case DynamicValueType.TypeCode: - return a.TypeCode switch - { - DynamicValueType.Chunk => "Function", - DynamicValueType.TypeCode => "Type", - _ => a.TypeCode.ToString() - }; - case DynamicValueType.NativeFunction: - return $"NativeFunction {a.NativeFunction!.Method.DeclaringType!.FullName}::{a.NativeFunction!.Method.Name}"; - case DynamicValueType.NativeObject: + else { - if (a.NativeObject == null) - { - return "NativeObject null"; - } - - var typeName = a.NativeObject.GetType().FullName; - return $"NativeObject {typeName} ({a.NativeObject})"; + return $"Error[{a.Error.Length}]"; } - default: + } + + case DynamicValueType.TypeCode: + { + return a.TypeCode switch { - throw new UnsupportedDynamicValueOperationException( - $"Attempt to convert a {a.Type} to String." - ); + DynamicValueType.Chunk => "Function", + DynamicValueType.TypeCode => "Type", + _ => a.TypeCode.ToString() + }; + } + + case DynamicValueType.NativeFunction: + return $"NativeFunction {a.NativeFunction!.Method.DeclaringType!.FullName}::{a.NativeFunction!.Method.Name}"; + + case DynamicValueType.NativeObject: + { + if (a.NativeObject == null) + { + return "NativeObject null"; } + + var typeName = a.NativeObject.GetType().FullName; + return $"NativeObject {typeName} ({a.NativeObject})"; + } + + default: + { + throw new UnsupportedDynamicValueOperationException( + $"Attempt to convert a {a.Type} to String." + ); } } + } - public static DynamicValue ConvertToNumber(this DynamicValue a) + public static DynamicValue ConvertToNumber(this DynamicValue a) + { + switch (a.Type) { - switch (a.Type) + case DynamicValueType.String: { - case DynamicValueType.String: + try + { + return double.Parse(a.String!); + } + catch (FormatException) + { + return DynamicValue.Nil; + } + catch (OverflowException) + { + return DynamicValue.Nil; + } + catch (Exception e) { - try - { - return double.Parse(a.String!); - } - catch (FormatException) - { - return DynamicValue.Nil; - } - catch (OverflowException) - { - return DynamicValue.Nil; - } - catch (Exception e) - { - throw new MalformedNumberException( - $"Attempt to convert '{a.String}' to a Number.", - e - ); - } + throw new MalformedNumberException( + $"Attempt to convert '{a.String}' to a Number.", + e + ); } + } - case DynamicValueType.Boolean: - return a.Boolean ? 1 : 0; + case DynamicValueType.Boolean: + return a.Boolean ? 1 : 0; - case DynamicValueType.TypeCode: - return (int)a.TypeCode; + case DynamicValueType.TypeCode: + return (int)a.TypeCode; - case DynamicValueType.Number: - return a.Number; + case DynamicValueType.Number: + return a.Number; - default: - { - throw new UnsupportedDynamicValueOperationException( - $"Attempt to convert a {a.Type} to Number." - ); - } + default: + { + throw new UnsupportedDynamicValueOperationException( + $"Attempt to convert a {a.Type} to Number." + ); } } } diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Logical.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Logical.cs index 846e0816..6741be5d 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Logical.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Logical.cs @@ -1,14 +1,13 @@ -namespace EVIL.Ceres.ExecutionEngine.TypeSystem +namespace EVIL.Ceres.ExecutionEngine.TypeSystem; + +public static partial class DynamicValueOperations { - public static partial class DynamicValueOperations - { - public static DynamicValue LogicallyNegate(this DynamicValue a) - => new(!DynamicValue.IsTruth(a)); + public static DynamicValue LogicallyNegate(this DynamicValue a) + => new(!DynamicValue.IsTruth(a)); - public static DynamicValue LogicalAnd(this DynamicValue a, DynamicValue b) - => new(DynamicValue.IsTruth(a) && DynamicValue.IsTruth(b)); + public static DynamicValue LogicalAnd(this DynamicValue a, DynamicValue b) + => new(DynamicValue.IsTruth(a) && DynamicValue.IsTruth(b)); - public static DynamicValue LogicalOr(this DynamicValue a, DynamicValue b) - => new(DynamicValue.IsTruth(a) || DynamicValue.IsTruth(b)); - } + public static DynamicValue LogicalOr(this DynamicValue a, DynamicValue b) + => new(DynamicValue.IsTruth(a) || DynamicValue.IsTruth(b)); } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Utility.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Utility.cs index 3036fc6b..40200c44 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Utility.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/DynamicValueOperations.Utility.cs @@ -1,186 +1,184 @@ +namespace EVIL.Ceres.ExecutionEngine.TypeSystem; + using System; +using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine.TypeSystem +public static partial class DynamicValueOperations { - using EVIL.Ceres.ExecutionEngine.Marshaling; - - public static partial class DynamicValueOperations + public static DynamicValue Contains(this DynamicValue a, DynamicValue b) { - public static DynamicValue Contains(this DynamicValue a, DynamicValue b) + if (a.Type == DynamicValueType.String) { - if (a.Type == DynamicValueType.String) - { - if (b.Type == DynamicValueType.String) - { - return new(a.String!.Contains(b.String!, StringComparison.InvariantCulture)); - } - } - - if (a.Type == DynamicValueType.Table) + if (b.Type == DynamicValueType.String) { - if (b.Type == DynamicValueType.String || b.Type == DynamicValueType.Number) - { - return new(a.Table!.Contains(b)); - } - } - - if (a.Type == DynamicValueType.Array) - { - return new(a.Array!.IndexOf(b) >= 0); + return new(a.String!.Contains(b.String!, StringComparison.InvariantCulture)); } + } - if (a.Type == DynamicValueType.Error) + if (a.Type == DynamicValueType.Table) + { + if (b.Type == DynamicValueType.String || b.Type == DynamicValueType.Number) { - return new(a.Error!.Contains(b)); + return new(a.Table!.Contains(b)); } + } - throw new UnsupportedDynamicValueOperationException( - $"Attempt to check if a {a.Type} contains a {b.Type}." - ); + if (a.Type == DynamicValueType.Array) + { + return new(a.Array!.IndexOf(b) >= 0); } - public static DynamicValue GetLength(this DynamicValue a) + if (a.Type == DynamicValueType.Error) { - if (a.Type == DynamicValueType.String) - { - return new(a.String!.Length); - } + return new(a.Error!.Contains(b)); + } - if (a.Type == DynamicValueType.Array) - { - return new(a.Array!.Length); - } + throw new UnsupportedDynamicValueOperationException( + $"Attempt to check if a {a.Type} contains a {b.Type}." + ); + } - if (a.Type == DynamicValueType.Table) - { - return new(a.Table!.Length); - } + public static DynamicValue GetLength(this DynamicValue a) + { + if (a.Type == DynamicValueType.String) + { + return new(a.String!.Length); + } - if (a.Type == DynamicValueType.Error) - { - return new(a.Error!.Length); - } + if (a.Type == DynamicValueType.Array) + { + return new(a.Array!.Length); + } - throw new UnsupportedDynamicValueOperationException( - $"Attempt to get length of a {a.Type}." - ); + if (a.Type == DynamicValueType.Table) + { + return new(a.Table!.Length); } - public static DynamicValue Index(this DynamicValue a, DynamicValue key) + if (a.Type == DynamicValueType.Error) { - switch (a.Type) - { - case DynamicValueType.Table: - return a.Table![key]; + return new(a.Error!.Length); + } + + throw new UnsupportedDynamicValueOperationException( + $"Attempt to get length of a {a.Type}." + ); + } + + public static DynamicValue Index(this DynamicValue a, DynamicValue key) + { + switch (a.Type) + { + case DynamicValueType.Table: + return a.Table![key]; - case DynamicValueType.NativeObject when a.NativeObject is IIndexableObject indexable: - return indexable.Index(key); + case DynamicValueType.NativeObject when a.NativeObject is IIndexableObject indexable: + return indexable.Index(key); - case DynamicValueType.Array when key.Type != DynamicValueType.Number: - throw new UnsupportedDynamicValueOperationException( - $"Attempt to index an {a.Type} using a {key.Type}." - ); + case DynamicValueType.Array when key.Type != DynamicValueType.Number: + throw new UnsupportedDynamicValueOperationException( + $"Attempt to index an {a.Type} using a {key.Type}." + ); - case DynamicValueType.Array: - return a.Array![(int)key.Number]; + case DynamicValueType.Array: + return a.Array![(int)key.Number]; - case DynamicValueType.String when key.Type != DynamicValueType.Number: - throw new UnsupportedDynamicValueOperationException( - $"Attempt to index a {a.Type} using a {key.Type}." - ); + case DynamicValueType.String when key.Type != DynamicValueType.Number: + throw new UnsupportedDynamicValueOperationException( + $"Attempt to index a {a.Type} using a {key.Type}." + ); - case DynamicValueType.String when key.Number % 1 != 0: - throw new UnsupportedDynamicValueOperationException( - $"Attempt to index a {a.Type} using a fractional number." - ); + case DynamicValueType.String when key.Number % 1 != 0: + throw new UnsupportedDynamicValueOperationException( + $"Attempt to index a {a.Type} using a fractional number." + ); - case DynamicValueType.String when key.Number < 0 || key.Number >= a.String!.Length: - return DynamicValue.Nil; + case DynamicValueType.String when key.Number < 0 || key.Number >= a.String!.Length: + return DynamicValue.Nil; - case DynamicValueType.String: - return new(a.String![(int)key.Number]); + case DynamicValueType.String: + return new(a.String![(int)key.Number]); - case DynamicValueType.Chunk when key.Type != DynamicValueType.String: - throw new UnsupportedDynamicValueOperationException( - $"Chunks may only be indexed using a String." - ); + case DynamicValueType.Chunk when key.Type != DynamicValueType.String: + throw new UnsupportedDynamicValueOperationException( + $"Chunks may only be indexed using a String." + ); - case DynamicValueType.Chunk: - return a.Chunk![key.String!] ?? DynamicValue.Nil; + case DynamicValueType.Chunk: + return a.Chunk![key.String!] ?? DynamicValue.Nil; - case DynamicValueType.Error: - return a.Error![key]; + case DynamicValueType.Error: + return a.Error![key]; - default: - throw new UnsupportedDynamicValueOperationException( - $"Attempt to index a non-indexable {a.Type} value." - ); - } + default: + throw new UnsupportedDynamicValueOperationException( + $"Attempt to index a non-indexable {a.Type} value." + ); } + } - public static DynamicValue ShiftLeft(this DynamicValue a, DynamicValue b) + public static DynamicValue ShiftLeft(this DynamicValue a, DynamicValue b) + { + if (b.Type != DynamicValueType.Number) { - if (b.Type != DynamicValueType.Number) - { - throw new UnsupportedDynamicValueOperationException( - $"Attempt to left-shift a {a.Type} by a {b.Type}." - ); - } + throw new UnsupportedDynamicValueOperationException( + $"Attempt to left-shift a {a.Type} by a {b.Type}." + ); + } - if (a.Type == DynamicValueType.Number) - { - return new((long)a.Number << (int)b.Number); - } + if (a.Type == DynamicValueType.Number) + { + return new((long)a.Number << (int)b.Number); + } - if (a.Type == DynamicValueType.String) + if (a.Type == DynamicValueType.String) + { + var amount = (int)b.Number; + var str = a.String!; + + if (amount >= str.Length) { - var amount = (int)b.Number; - var str = a.String!; + return DynamicValue.EmptyString; + } - if (amount >= str.Length) - { - return DynamicValue.EmptyString; - } + return new(str.Substring(amount)); + } - return new(str.Substring(amount)); - } + throw new UnsupportedDynamicValueOperationException( + $"Attempt to left-shift a {a.Type}." + ); + } + public static DynamicValue ShiftRight(this DynamicValue a, DynamicValue b) + { + if (b.Type != DynamicValueType.Number) + { throw new UnsupportedDynamicValueOperationException( - $"Attempt to left-shift a {a.Type}." + $"Attempt to right-shift a {a.Type} by a {b.Type}." ); } - public static DynamicValue ShiftRight(this DynamicValue a, DynamicValue b) + if (a.Type == DynamicValueType.Number) { - if (b.Type != DynamicValueType.Number) - { - throw new UnsupportedDynamicValueOperationException( - $"Attempt to right-shift a {a.Type} by a {b.Type}." - ); - } + return new((long)a.Number >> (int)b.Number); + } - if (a.Type == DynamicValueType.Number) - { - return new((long)a.Number >> (int)b.Number); - } + if (a.Type == DynamicValueType.String) + { + var str = a.String!; + var amount = str.Length - (int)b.Number; - if (a.Type == DynamicValueType.String) + if (amount <= 0) { - var str = a.String!; - var amount = str.Length - (int)b.Number; - - if (amount <= 0) - { - return DynamicValue.EmptyString; - } - - return new(str.Substring(0, amount)); + return DynamicValue.EmptyString; } - throw new UnsupportedDynamicValueOperationException( - $"Attempt to right-shift a {a.Type}." - ); + return new(str.Substring(0, amount)); } + + throw new UnsupportedDynamicValueOperationException( + $"Attempt to right-shift a {a.Type}." + ); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/MalformedNumberException.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/MalformedNumberException.cs index c05304e9..dc120532 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/MalformedNumberException.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/TypeSystem/MalformedNumberException.cs @@ -1,12 +1,11 @@ -using System; +namespace EVIL.Ceres.ExecutionEngine.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine.TypeSystem +using System; + +public class MalformedNumberException : RecoverableVirtualMachineException { - public class MalformedNumberException : RecoverableVirtualMachineException + internal MalformedNumberException(string message, Exception innerException) + : base(message, innerException) { - internal MalformedNumberException(string message, Exception innerException) - : base(message, innerException) - { - } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/UserUnhandledExceptionException.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/UserUnhandledExceptionException.cs index e4eb815d..a91c5e81 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/UserUnhandledExceptionException.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/UserUnhandledExceptionException.cs @@ -1,18 +1,17 @@ +namespace EVIL.Ceres.ExecutionEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.ExecutionEngine.TypeSystem; -namespace EVIL.Ceres.ExecutionEngine +public class UserUnhandledExceptionException : VirtualMachineException { - public class UserUnhandledExceptionException : VirtualMachineException - { - public DynamicValue EvilExceptionObject { get; } - public StackFrame[] EvilStackTrace { get; } + public DynamicValue EvilExceptionObject { get; } + public StackFrame[] EvilStackTrace { get; } - internal UserUnhandledExceptionException(string message, DynamicValue evilExceptionObject, StackFrame[] evilStackTrace) - : base(message) - { - EvilExceptionObject = evilExceptionObject; - EvilStackTrace = evilStackTrace; - } + internal UserUnhandledExceptionException(string message, DynamicValue evilExceptionObject, StackFrame[] evilStackTrace) + : base(message) + { + EvilExceptionObject = evilExceptionObject; + EvilStackTrace = evilStackTrace; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/VirtualMachineException.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/VirtualMachineException.cs index 259f4e3d..9cc85351 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/VirtualMachineException.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/VirtualMachineException.cs @@ -1,17 +1,16 @@ +namespace EVIL.Ceres.ExecutionEngine; + using System; -namespace EVIL.Ceres.ExecutionEngine +public class VirtualMachineException : Exception { - public class VirtualMachineException : Exception + internal VirtualMachineException(string message, Exception innerException) + : base(message, innerException) { - internal VirtualMachineException(string message, Exception innerException) - : base(message, innerException) - { - } + } - internal VirtualMachineException(string message) - : base(message) - { - } + internal VirtualMachineException(string message) + : base(message) + { } -} \ No newline at end of file +} \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/ModuleInitializer.cs b/VirtualMachine/EVIL.Ceres/ModuleInitializer.cs index 78abd8bf..7d94d25f 100644 --- a/VirtualMachine/EVIL.Ceres/ModuleInitializer.cs +++ b/VirtualMachine/EVIL.Ceres/ModuleInitializer.cs @@ -1,26 +1,25 @@ -using System; +namespace EVIL.Ceres; + +using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -namespace EVIL.Ceres +internal static class ModuleInitializer { - internal static class ModuleInitializer - { - [DllImport("ntdll")] - private static extern int NtSetTimerResolution( - ulong desiredResolution, - bool setResolution, - ref ulong currentResolution - ); + [DllImport("ntdll")] + private static extern int NtSetTimerResolution( + ulong desiredResolution, + bool setResolution, + ref ulong currentResolution + ); - [ModuleInitializer] - public static void Initialize() + [ModuleInitializer] + public static void Initialize() + { + if (OperatingSystem.IsWindows()) { - if (OperatingSystem.IsWindows()) - { - ulong res = 0; - NtSetTimerResolution(1, true, ref res); - } - } + ulong res = 0; + NtSetTimerResolution(1, true, ref res); + } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/AttributeProcessor.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/AttributeProcessor.cs index a028d617..27efa11b 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/AttributeProcessor.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/AttributeProcessor.cs @@ -1,6 +1,5 @@ -using EVIL.Ceres.ExecutionEngine.Diagnostics; +namespace EVIL.Ceres.TranslationEngine; -namespace EVIL.Ceres.TranslationEngine -{ - public delegate void AttributeProcessor(ChunkAttribute attribute, Chunk chunk); -} \ No newline at end of file +using EVIL.Ceres.ExecutionEngine.Diagnostics; + +public delegate void AttributeProcessor(ChunkAttribute attribute, Chunk chunk); \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/AttributeProcessorException.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/AttributeProcessorException.cs index e436a289..e8529781 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/AttributeProcessorException.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/AttributeProcessorException.cs @@ -1,21 +1,20 @@ -using System; +namespace EVIL.Ceres.TranslationEngine; + +using System; using EVIL.Ceres.ExecutionEngine.Diagnostics; -namespace EVIL.Ceres.TranslationEngine +public class AttributeProcessorException : Exception { - public class AttributeProcessorException : Exception - { - public ChunkAttribute Attribute { get; } - public Chunk Chunk { get; } + public ChunkAttribute Attribute { get; } + public Chunk Chunk { get; } - internal AttributeProcessorException( - ChunkAttribute attribute, - Chunk chunk, - Exception innerException) - : base($"An error occured processing attribute '{attribute}' in chunk '{chunk}'.", innerException) - { - Attribute = attribute; - Chunk = chunk; - } + internal AttributeProcessorException( + ChunkAttribute attribute, + Chunk chunk, + Exception innerException) + : base($"An error occured processing attribute '{attribute}' in chunk '{chunk}'.", innerException) + { + Attribute = attribute; + Chunk = chunk; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Constant.Boolean.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Constant.Boolean.cs index f57fcba1..c7cabefc 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Constant.Boolean.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Constant.Boolean.cs @@ -1,17 +1,16 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Constants; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(BooleanConstant booleanConstant) { - public override void Visit(BooleanConstant booleanConstant) - { - Chunk.CodeGenerator.Emit( - booleanConstant.Value - ? OpCode.LDTRUE - : OpCode.LDFALSE - ); - } + Chunk.CodeGenerator.Emit( + booleanConstant.Value + ? OpCode.LDTRUE + : OpCode.LDFALSE + ); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Constant.Nil.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Constant.Nil.cs index 44db3290..65ab0ff5 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Constant.Nil.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Constant.Nil.cs @@ -1,13 +1,12 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Constants; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(NilConstant nilConstant) { - public override void Visit(NilConstant nilConstant) - { - Chunk.CodeGenerator.Emit(OpCode.LDNIL); - } + Chunk.CodeGenerator.Emit(OpCode.LDNIL); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Constant.Number.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Constant.Number.cs index 34cc9a97..7168ac73 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Constant.Number.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Constant.Number.cs @@ -1,27 +1,26 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Constants; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(NumberConstant numberConstant) { - public override void Visit(NumberConstant numberConstant) + if (numberConstant.Value.Equals(0)) + { + Chunk.CodeGenerator.Emit(OpCode.LDZERO); + } + else if (numberConstant.Value.Equals(1)) + { + Chunk.CodeGenerator.Emit(OpCode.LDONE); + } + else { - if (numberConstant.Value.Equals(0)) - { - Chunk.CodeGenerator.Emit(OpCode.LDZERO); - } - else if (numberConstant.Value.Equals(1)) - { - Chunk.CodeGenerator.Emit(OpCode.LDONE); - } - else - { - Chunk.CodeGenerator.Emit( - OpCode.LDNUM, - numberConstant.Value - ); - } + Chunk.CodeGenerator.Emit( + OpCode.LDNUM, + numberConstant.Value + ); } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Constant.String.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Constant.String.cs index 86a6eacd..693636e0 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Constant.String.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Constant.String.cs @@ -1,98 +1,97 @@ +namespace EVIL.Ceres.TranslationEngine; + using System.Linq; using System.Text.RegularExpressions; using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Constants; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler - { - private static Regex _stringSubstitutionRegex = new(@"(?\$(?[\p{L}_]([\p{L}\p{Nd}_]+)?))"); + private static Regex _stringSubstitutionRegex = new(@"(?\$(?[\p{L}_]([\p{L}\p{Nd}_]+)?))"); - public override void Visit(StringConstant stringConstant) + public override void Visit(StringConstant stringConstant) + { + if (stringConstant.IsInterpolated) { - if (stringConstant.IsInterpolated) - { - var additionCount = 0; - var templateString = stringConstant.Value; - var matches = _stringSubstitutionRegex.Matches(templateString); + var additionCount = 0; + var templateString = stringConstant.Value; + var matches = _stringSubstitutionRegex.Matches(templateString); - if (!matches.Any()) - { - var id = Chunk.StringPool.FetchOrAdd(stringConstant.Value); - Chunk.CodeGenerator.Emit( - OpCode.LDSTR, - (int)id - ); + if (!matches.Any()) + { + var id = Chunk.StringPool.FetchOrAdd(stringConstant.Value); + Chunk.CodeGenerator.Emit( + OpCode.LDSTR, + (int)id + ); - return; - } + return; + } - var endOfLastGroup = -1; + var endOfLastGroup = -1; - for (var i = 0; i < matches.Count; i++) - { - var match = matches[i]; - var group = match.Groups["substitution"]; - var symbolName = match.Groups["symbol_name"].Value; - var before = ""; - endOfLastGroup = group.Index + group.Length; + for (var i = 0; i < matches.Count; i++) + { + var match = matches[i]; + var group = match.Groups["substitution"]; + var symbolName = match.Groups["symbol_name"].Value; + var before = ""; + endOfLastGroup = group.Index + group.Length; - if (i == 0) - { - before = templateString.Substring(0, group.Index); - } - else - { - var prevMatch = matches[i - 1]; - var prevGroup = prevMatch.Groups["substitution"]; - var endOfPreviousGroup = prevGroup.Index + prevGroup.Length; - before = templateString.Substring(endOfPreviousGroup, group.Index - endOfPreviousGroup); - } - - if (before.Length > 0) - { - var id = Chunk.StringPool.FetchOrAdd(before); - Chunk.CodeGenerator.Emit( - OpCode.LDSTR, - (int)id - ); - } - - EmitVarGet(symbolName); - Chunk.CodeGenerator.Emit(OpCode.TOSTRING); - additionCount++; - - if (before.Length > 0) - { - Chunk.CodeGenerator.Emit(OpCode.ADD); - } + if (i == 0) + { + before = templateString.Substring(0, group.Index); + } + else + { + var prevMatch = matches[i - 1]; + var prevGroup = prevMatch.Groups["substitution"]; + var endOfPreviousGroup = prevGroup.Index + prevGroup.Length; + before = templateString.Substring(endOfPreviousGroup, group.Index - endOfPreviousGroup); } - var tail = templateString.Substring(endOfLastGroup); - if (tail.Length > 0) + if (before.Length > 0) { - var id = Chunk.StringPool.FetchOrAdd(tail); + var id = Chunk.StringPool.FetchOrAdd(before); Chunk.CodeGenerator.Emit( OpCode.LDSTR, (int)id ); - Chunk.CodeGenerator.Emit(OpCode.ADD); } - for (var i = 0; i < additionCount - 1; i++) + EmitVarGet(symbolName); + Chunk.CodeGenerator.Emit(OpCode.TOSTRING); + additionCount++; + + if (before.Length > 0) { Chunk.CodeGenerator.Emit(OpCode.ADD); } } - else + + var tail = templateString.Substring(endOfLastGroup); + if (tail.Length > 0) { - var id = Chunk.StringPool.FetchOrAdd(stringConstant.Value); + var id = Chunk.StringPool.FetchOrAdd(tail); Chunk.CodeGenerator.Emit( OpCode.LDSTR, (int)id ); + Chunk.CodeGenerator.Emit(OpCode.ADD); + } + + for (var i = 0; i < additionCount - 1; i++) + { + Chunk.CodeGenerator.Emit(OpCode.ADD); } } + else + { + var id = Chunk.StringPool.FetchOrAdd(stringConstant.Value); + Chunk.CodeGenerator.Emit( + OpCode.LDSTR, + (int)id + ); + } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Constant.TypeCode.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Constant.TypeCode.cs index 2d3b411a..fc1058d3 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Constant.TypeCode.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Constant.TypeCode.cs @@ -1,16 +1,15 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Constants; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(TypeCodeConstant typeCodeConstant) { - public override void Visit(TypeCodeConstant typeCodeConstant) - { - Chunk.CodeGenerator.Emit( - OpCode.LDTYPE, - (int)typeCodeConstant.Value - ); - } + Chunk.CodeGenerator.Emit( + OpCode.LDTYPE, + (int)typeCodeConstant.Value + ); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Array.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Array.cs index 627bc9a9..fdbed6e9 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Array.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Array.cs @@ -1,77 +1,76 @@ +namespace EVIL.Ceres.TranslationEngine; + using System.Linq; using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.TranslationEngine.Diagnostics; using EVIL.Grammar.AST.Constants; using EVIL.Grammar.AST.Expressions; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(ArrayExpression arrayExpression) { - public override void Visit(ArrayExpression arrayExpression) - { - int? knownSizeConstraint = null; + int? knownSizeConstraint = null; - if (arrayExpression.SizeExpression == null) + if (arrayExpression.SizeExpression == null) + { + Chunk.CodeGenerator.Emit( + OpCode.LDNUM, + (double)arrayExpression.Initializers.Count + ); + } + else + { + if (arrayExpression.SizeExpression.Reduce() is NumberConstant nc) { - Chunk.CodeGenerator.Emit( - OpCode.LDNUM, - (double)arrayExpression.Initializers.Count - ); + knownSizeConstraint = (int)nc.Value; } else { - if (arrayExpression.SizeExpression.Reduce() is NumberConstant nc) - { - knownSizeConstraint = (int)nc.Value; - } - else - { - Visit(arrayExpression.SizeExpression); - } + Visit(arrayExpression.SizeExpression); } + } - if (knownSizeConstraint != null) + if (knownSizeConstraint != null) + { + if (arrayExpression.Initializers.Count > knownSizeConstraint.Value) { - if (arrayExpression.Initializers.Count > knownSizeConstraint.Value) - { - Log.TerminateWithFatal( - "Attempt to initialize a constant size array with too many entries.", - CurrentFileName, - EvilMessageCode.TooManyInitializersForConstSizeArray, - arrayExpression.Line, - arrayExpression.Column - ); - } - - Chunk.CodeGenerator.Emit( - OpCode.LDNUM, - (double)knownSizeConstraint.Value + Log.TerminateWithFatal( + "Attempt to initialize a constant size array with too many entries.", + CurrentFileName, + EvilMessageCode.TooManyInitializersForConstSizeArray, + arrayExpression.Line, + arrayExpression.Column ); } + + Chunk.CodeGenerator.Emit( + OpCode.LDNUM, + (double)knownSizeConstraint.Value + ); + } - Chunk.CodeGenerator.Emit(OpCode.ARRNEW); - if (arrayExpression.Initializers.Any()) + Chunk.CodeGenerator.Emit(OpCode.ARRNEW); + if (arrayExpression.Initializers.Any()) + { + for (var i = 0; i < arrayExpression.Initializers.Count; i++) { - for (var i = 0; i < arrayExpression.Initializers.Count; i++) - { - Visit(arrayExpression.Initializers[i]); - - if (i == 0) - { - Chunk.CodeGenerator.Emit(OpCode.LDZERO); - } - else if (i == 1) - { - Chunk.CodeGenerator.Emit(OpCode.LDONE); - } - else - { - Chunk.CodeGenerator.Emit(OpCode.LDNUM, (double)i); - } + Visit(arrayExpression.Initializers[i]); - Chunk.CodeGenerator.Emit(OpCode.ELINIT); + if (i == 0) + { + Chunk.CodeGenerator.Emit(OpCode.LDZERO); + } + else if (i == 1) + { + Chunk.CodeGenerator.Emit(OpCode.LDONE); } + else + { + Chunk.CodeGenerator.Emit(OpCode.LDNUM, (double)i); + } + + Chunk.CodeGenerator.Emit(OpCode.ELINIT); } } } diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Assignment.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Assignment.cs index 704dfce8..e007f313 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Assignment.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Assignment.cs @@ -1,151 +1,150 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.TranslationEngine.Diagnostics; using EVIL.Grammar; using EVIL.Grammar.AST.Expressions; using EVIL.Grammar.AST.Statements; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(AssignmentExpression assignmentExpression) { - public override void Visit(AssignmentExpression assignmentExpression) + if (assignmentExpression.Left is SymbolReferenceExpression symRef) { - if (assignmentExpression.Left is SymbolReferenceExpression symRef) - { - ThrowIfVarReadOnly(symRef.Identifier); - - if (assignmentExpression.OperationType == AssignmentOperationType.Coalesce) - { - var valueNotNilLabel = Chunk.CreateLabel(); + ThrowIfVarReadOnly(symRef.Identifier); - EmitVarGet(symRef.Identifier); - Chunk.CodeGenerator.Emit(OpCode.DUP); - Chunk.CodeGenerator.Emit(OpCode.LDNIL); - Chunk.CodeGenerator.Emit(OpCode.CNE); - Chunk.CodeGenerator.Emit(OpCode.TJMP, valueNotNilLabel); - Chunk.CodeGenerator.Emit(OpCode.POP); - Visit(assignmentExpression.Right); - Chunk.CodeGenerator.Emit(OpCode.DUP); - EmitVarSet(symRef.Identifier); - Chunk.UpdateLabel(valueNotNilLabel, Chunk.CodeGenerator.IP); - - return; - } + if (assignmentExpression.OperationType == AssignmentOperationType.Coalesce) + { + var valueNotNilLabel = Chunk.CreateLabel(); - if (assignmentExpression.OperationType != AssignmentOperationType.Direct) - { - EmitVarGet(symRef.Identifier); - Visit(assignmentExpression.Right); + EmitVarGet(symRef.Identifier); + Chunk.CodeGenerator.Emit(OpCode.DUP); + Chunk.CodeGenerator.Emit(OpCode.LDNIL); + Chunk.CodeGenerator.Emit(OpCode.CNE); + Chunk.CodeGenerator.Emit(OpCode.TJMP, valueNotNilLabel); + Chunk.CodeGenerator.Emit(OpCode.POP); + Visit(assignmentExpression.Right); + Chunk.CodeGenerator.Emit(OpCode.DUP); + EmitVarSet(symRef.Identifier); + Chunk.UpdateLabel(valueNotNilLabel, Chunk.CodeGenerator.IP); - Chunk.CodeGenerator.Emit( - assignmentExpression.OperationType switch - { - AssignmentOperationType.Add => OpCode.ADD, - AssignmentOperationType.Subtract => OpCode.SUB, - AssignmentOperationType.Divide => OpCode.DIV, - AssignmentOperationType.Modulo => OpCode.MOD, - AssignmentOperationType.Multiply => OpCode.MUL, - AssignmentOperationType.BitwiseAnd => OpCode.BAND, - AssignmentOperationType.BitwiseOr => OpCode.BOR, - AssignmentOperationType.BitwiseXor => OpCode.BXOR, - AssignmentOperationType.ShiftLeft => OpCode.SHL, - AssignmentOperationType.ShiftRight => OpCode.SHR, - _ => Log.TerminateWithInternalFailure( - $"Invalid assignment operation type '{assignmentExpression.OperationType}'.", - CurrentFileName, - line: Line, - column: Column, - dummyReturn: OpCode.NOOP - ) - } - ); - } - else - { - Visit(assignmentExpression.Right); - } + return; + } - if (assignmentExpression.Parent is not ExpressionStatement) - { - Chunk.CodeGenerator.Emit(OpCode.DUP); - } + if (assignmentExpression.OperationType != AssignmentOperationType.Direct) + { + EmitVarGet(symRef.Identifier); + Visit(assignmentExpression.Right); - EmitVarSet(symRef.Identifier); + Chunk.CodeGenerator.Emit( + assignmentExpression.OperationType switch + { + AssignmentOperationType.Add => OpCode.ADD, + AssignmentOperationType.Subtract => OpCode.SUB, + AssignmentOperationType.Divide => OpCode.DIV, + AssignmentOperationType.Modulo => OpCode.MOD, + AssignmentOperationType.Multiply => OpCode.MUL, + AssignmentOperationType.BitwiseAnd => OpCode.BAND, + AssignmentOperationType.BitwiseOr => OpCode.BOR, + AssignmentOperationType.BitwiseXor => OpCode.BXOR, + AssignmentOperationType.ShiftLeft => OpCode.SHL, + AssignmentOperationType.ShiftRight => OpCode.SHR, + _ => Log.TerminateWithInternalFailure( + $"Invalid assignment operation type '{assignmentExpression.OperationType}'.", + CurrentFileName, + line: Line, + column: Column, + dummyReturn: OpCode.NOOP + ) + } + ); } - else if (assignmentExpression.Left is IndexerExpression ie) + else { - if (assignmentExpression.OperationType == AssignmentOperationType.Coalesce) - { - var valueNotNilLabel = Chunk.CreateLabel(); - - Visit(ie); - Chunk.CodeGenerator.Emit(OpCode.DUP); - Chunk.CodeGenerator.Emit(OpCode.LDNIL); - Chunk.CodeGenerator.Emit(OpCode.CNE); - Chunk.CodeGenerator.Emit(OpCode.TJMP, valueNotNilLabel); - Chunk.CodeGenerator.Emit(OpCode.POP); - Visit(assignmentExpression.Right); - Chunk.CodeGenerator.Emit(OpCode.DUP); - Visit(ie.Indexable); - Visit(ie.KeyExpression); - Chunk.CodeGenerator.Emit(OpCode.ELSET); - Chunk.UpdateLabel(valueNotNilLabel, Chunk.CodeGenerator.IP); - - return; - } - - if (assignmentExpression.OperationType != AssignmentOperationType.Direct) - { - Visit(ie); - Visit(assignmentExpression.Right); + Visit(assignmentExpression.Right); + } - Chunk.CodeGenerator.Emit( - assignmentExpression.OperationType switch - { - AssignmentOperationType.Add => OpCode.ADD, - AssignmentOperationType.Subtract => OpCode.SUB, - AssignmentOperationType.Divide => OpCode.DIV, - AssignmentOperationType.Modulo => OpCode.MOD, - AssignmentOperationType.Multiply => OpCode.MUL, - AssignmentOperationType.BitwiseAnd => OpCode.BAND, - AssignmentOperationType.BitwiseOr => OpCode.BOR, - AssignmentOperationType.BitwiseXor => OpCode.BXOR, - AssignmentOperationType.ShiftLeft => OpCode.SHL, - AssignmentOperationType.ShiftRight => OpCode.SHR, - _ => Log.TerminateWithInternalFailure( - $"Invalid assignment operation type '{assignmentExpression.OperationType}'.", - CurrentFileName, - line: Line, - column: Column, - dummyReturn: OpCode.NOOP - ) - } - ); - } - else - { - Visit(assignmentExpression.Right); - } + if (assignmentExpression.Parent is not ExpressionStatement) + { + Chunk.CodeGenerator.Emit(OpCode.DUP); + } - if (assignmentExpression.Parent is not ExpressionStatement) - { - Chunk.CodeGenerator.Emit(OpCode.DUP); - } + EmitVarSet(symRef.Identifier); + } + else if (assignmentExpression.Left is IndexerExpression ie) + { + if (assignmentExpression.OperationType == AssignmentOperationType.Coalesce) + { + var valueNotNilLabel = Chunk.CreateLabel(); + Visit(ie); + Chunk.CodeGenerator.Emit(OpCode.DUP); + Chunk.CodeGenerator.Emit(OpCode.LDNIL); + Chunk.CodeGenerator.Emit(OpCode.CNE); + Chunk.CodeGenerator.Emit(OpCode.TJMP, valueNotNilLabel); + Chunk.CodeGenerator.Emit(OpCode.POP); + Visit(assignmentExpression.Right); + Chunk.CodeGenerator.Emit(OpCode.DUP); Visit(ie.Indexable); Visit(ie.KeyExpression); Chunk.CodeGenerator.Emit(OpCode.ELSET); + Chunk.UpdateLabel(valueNotNilLabel, Chunk.CodeGenerator.IP); + + return; } - else + + if (assignmentExpression.OperationType != AssignmentOperationType.Direct) { - Log.TerminateWithFatal( - "Illegal assignment target.", - CurrentFileName, - EvilMessageCode.IllegalAssignmentTarget, - Line, - Column + Visit(ie); + Visit(assignmentExpression.Right); + + Chunk.CodeGenerator.Emit( + assignmentExpression.OperationType switch + { + AssignmentOperationType.Add => OpCode.ADD, + AssignmentOperationType.Subtract => OpCode.SUB, + AssignmentOperationType.Divide => OpCode.DIV, + AssignmentOperationType.Modulo => OpCode.MOD, + AssignmentOperationType.Multiply => OpCode.MUL, + AssignmentOperationType.BitwiseAnd => OpCode.BAND, + AssignmentOperationType.BitwiseOr => OpCode.BOR, + AssignmentOperationType.BitwiseXor => OpCode.BXOR, + AssignmentOperationType.ShiftLeft => OpCode.SHL, + AssignmentOperationType.ShiftRight => OpCode.SHR, + _ => Log.TerminateWithInternalFailure( + $"Invalid assignment operation type '{assignmentExpression.OperationType}'.", + CurrentFileName, + line: Line, + column: Column, + dummyReturn: OpCode.NOOP + ) + } ); } + else + { + Visit(assignmentExpression.Right); + } + + if (assignmentExpression.Parent is not ExpressionStatement) + { + Chunk.CodeGenerator.Emit(OpCode.DUP); + } + + Visit(ie.Indexable); + Visit(ie.KeyExpression); + Chunk.CodeGenerator.Emit(OpCode.ELSET); + } + else + { + Log.TerminateWithFatal( + "Illegal assignment target.", + CurrentFileName, + EvilMessageCode.IllegalAssignmentTarget, + Line, + Column + ); } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Binary.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Binary.cs index ad173733..dbac3ad3 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Binary.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Binary.cs @@ -1,164 +1,163 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar; using EVIL.Grammar.AST.Expressions; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(BinaryExpression binaryExpression) { - public override void Visit(BinaryExpression binaryExpression) + Visit(binaryExpression.Left); + Visit(binaryExpression.Right); + + switch (binaryExpression.Type) { - Visit(binaryExpression.Left); - Visit(binaryExpression.Right); - - switch (binaryExpression.Type) - { - case BinaryOperationType.Add: - { - Chunk.CodeGenerator.Emit(OpCode.ADD); - break; - } - - case BinaryOperationType.Subtract: - { - Chunk.CodeGenerator.Emit(OpCode.SUB); - break; - } - - case BinaryOperationType.Divide: - { - Chunk.CodeGenerator.Emit(OpCode.DIV); - break; - } - - case BinaryOperationType.Modulo: - { - Chunk.CodeGenerator.Emit(OpCode.MOD); - break; - } - - case BinaryOperationType.Multiply: - { - Chunk.CodeGenerator.Emit(OpCode.MUL); - break; - } - - case BinaryOperationType.BitwiseAnd: - { - Chunk.CodeGenerator.Emit(OpCode.BAND); - break; - } - - case BinaryOperationType.BitwiseOr: - { - Chunk.CodeGenerator.Emit(OpCode.BOR); - break; - } - - case BinaryOperationType.BitwiseXor: - { - Chunk.CodeGenerator.Emit(OpCode.BXOR); - break; - } - - case BinaryOperationType.ShiftLeft: - { - Chunk.CodeGenerator.Emit(OpCode.SHL); - break; - } - - case BinaryOperationType.ShiftRight: - { - Chunk.CodeGenerator.Emit(OpCode.SHR); - break; - } - - case BinaryOperationType.ExistsIn: - { - Chunk.CodeGenerator.Emit(OpCode.EXISTS); - break; - } - - case BinaryOperationType.DoesNotExistIn: - { - Chunk.CodeGenerator.Emit(OpCode.EXISTS); - Chunk.CodeGenerator.Emit(OpCode.LNOT); - - break; - } - - case BinaryOperationType.LogicalAnd: - { - Chunk.CodeGenerator.Emit(OpCode.LAND); - break; - } - - case BinaryOperationType.LogicalOr: - { - Chunk.CodeGenerator.Emit(OpCode.LOR); - break; - } - - case BinaryOperationType.DeepEqual: - { - Chunk.CodeGenerator.Emit(OpCode.DEQ); - break; - } - - case BinaryOperationType.DeepNotEqual: - { - Chunk.CodeGenerator.Emit(OpCode.DNE); - break; - } - - case BinaryOperationType.Equal: - { - Chunk.CodeGenerator.Emit(OpCode.CEQ); - break; - } - - case BinaryOperationType.NotEqual: - { - Chunk.CodeGenerator.Emit(OpCode.CNE); - break; - } - - case BinaryOperationType.Greater: - { - Chunk.CodeGenerator.Emit(OpCode.CGT); - break; - } - - case BinaryOperationType.Less: - { - Chunk.CodeGenerator.Emit(OpCode.CLT); - break; - } - - case BinaryOperationType.GreaterOrEqual: - { - Chunk.CodeGenerator.Emit(OpCode.CGE); - break; - } - - case BinaryOperationType.LessOrEqual: - { - Chunk.CodeGenerator.Emit(OpCode.CLE); - break; - } - - default: - { - Log.TerminateWithInternalFailure( - $"Invalid binary operation type '{binaryExpression.Type}'.", - CurrentFileName, - line: Line, - column: Column, - dummyReturn: OpCode.NOOP - ); - - break; - } + case BinaryOperationType.Add: + { + Chunk.CodeGenerator.Emit(OpCode.ADD); + break; + } + + case BinaryOperationType.Subtract: + { + Chunk.CodeGenerator.Emit(OpCode.SUB); + break; + } + + case BinaryOperationType.Divide: + { + Chunk.CodeGenerator.Emit(OpCode.DIV); + break; + } + + case BinaryOperationType.Modulo: + { + Chunk.CodeGenerator.Emit(OpCode.MOD); + break; + } + + case BinaryOperationType.Multiply: + { + Chunk.CodeGenerator.Emit(OpCode.MUL); + break; + } + + case BinaryOperationType.BitwiseAnd: + { + Chunk.CodeGenerator.Emit(OpCode.BAND); + break; + } + + case BinaryOperationType.BitwiseOr: + { + Chunk.CodeGenerator.Emit(OpCode.BOR); + break; + } + + case BinaryOperationType.BitwiseXor: + { + Chunk.CodeGenerator.Emit(OpCode.BXOR); + break; + } + + case BinaryOperationType.ShiftLeft: + { + Chunk.CodeGenerator.Emit(OpCode.SHL); + break; + } + + case BinaryOperationType.ShiftRight: + { + Chunk.CodeGenerator.Emit(OpCode.SHR); + break; + } + + case BinaryOperationType.ExistsIn: + { + Chunk.CodeGenerator.Emit(OpCode.EXISTS); + break; + } + + case BinaryOperationType.DoesNotExistIn: + { + Chunk.CodeGenerator.Emit(OpCode.EXISTS); + Chunk.CodeGenerator.Emit(OpCode.LNOT); + + break; + } + + case BinaryOperationType.LogicalAnd: + { + Chunk.CodeGenerator.Emit(OpCode.LAND); + break; + } + + case BinaryOperationType.LogicalOr: + { + Chunk.CodeGenerator.Emit(OpCode.LOR); + break; + } + + case BinaryOperationType.DeepEqual: + { + Chunk.CodeGenerator.Emit(OpCode.DEQ); + break; + } + + case BinaryOperationType.DeepNotEqual: + { + Chunk.CodeGenerator.Emit(OpCode.DNE); + break; + } + + case BinaryOperationType.Equal: + { + Chunk.CodeGenerator.Emit(OpCode.CEQ); + break; + } + + case BinaryOperationType.NotEqual: + { + Chunk.CodeGenerator.Emit(OpCode.CNE); + break; + } + + case BinaryOperationType.Greater: + { + Chunk.CodeGenerator.Emit(OpCode.CGT); + break; + } + + case BinaryOperationType.Less: + { + Chunk.CodeGenerator.Emit(OpCode.CLT); + break; + } + + case BinaryOperationType.GreaterOrEqual: + { + Chunk.CodeGenerator.Emit(OpCode.CGE); + break; + } + + case BinaryOperationType.LessOrEqual: + { + Chunk.CodeGenerator.Emit(OpCode.CLE); + break; + } + + default: + { + Log.TerminateWithInternalFailure( + $"Invalid binary operation type '{binaryExpression.Type}'.", + CurrentFileName, + line: Line, + column: Column, + dummyReturn: OpCode.NOOP + ); + + break; } } } diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.By.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.By.cs index 97d71727..31a059ba 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.By.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.By.cs @@ -1,71 +1,70 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.TranslationEngine.Diagnostics; using EVIL.Grammar.AST.Base; using EVIL.Grammar.AST.Expressions; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(ByExpression byExpression) { - public override void Visit(ByExpression byExpression) - { - Visit(byExpression.Qualifier); + Visit(byExpression.Qualifier); - var arms = byExpression.Arms; - var elseArm = byExpression.ElseArm; + var arms = byExpression.Arms; + var elseArm = byExpression.ElseArm; - var labels = new int[arms.Count]; - for (var i = 0; i < arms.Count; i++) - { - labels[i] = Chunk.CreateLabel(); - } + var labels = new int[arms.Count]; + for (var i = 0; i < arms.Count; i++) + { + labels[i] = Chunk.CreateLabel(); + } - var endLabel = Chunk.CreateLabel(); + var endLabel = Chunk.CreateLabel(); - for (var i = 0; i < arms.Count; i++) + for (var i = 0; i < arms.Count; i++) + { + if (i < arms.Count - 1) { - if (i < arms.Count - 1) - { - Chunk.CodeGenerator.Emit(OpCode.DUP); - } + Chunk.CodeGenerator.Emit(OpCode.DUP); + } - Visit(arms[i].Selector); - - Chunk.CodeGenerator.Emit(arms[i].DeepEquality ? OpCode.DEQ : OpCode.CEQ); - Chunk.CodeGenerator.Emit(OpCode.FJMP, labels[i]); + Visit(arms[i].Selector); - if (i < arms.Count - 1) - { - Chunk.CodeGenerator.Emit(OpCode.POP); - } + Chunk.CodeGenerator.Emit(arms[i].DeepEquality ? OpCode.DEQ : OpCode.CEQ); + Chunk.CodeGenerator.Emit(OpCode.FJMP, labels[i]); - Visit(arms[i].ValueArm); - - if (arms[i].ValueArm is Expression) - { - Chunk.CodeGenerator.Emit(OpCode.JUMP, endLabel); - Chunk.UpdateLabel(labels[i], Chunk.CodeGenerator.IP); - } + if (i < arms.Count - 1) + { + Chunk.CodeGenerator.Emit(OpCode.POP); } - if (elseArm != null) + Visit(arms[i].ValueArm); + + if (arms[i].ValueArm is Expression) { - Visit(elseArm); + Chunk.CodeGenerator.Emit(OpCode.JUMP, endLabel); + Chunk.UpdateLabel(labels[i], Chunk.CodeGenerator.IP); } - else - { - Log.EmitWarning( - "By-expression has no default arm and will always return `nil' if input matching fails. Consider adding a default arm using `else' keyword.", - CurrentFileName, - EvilMessageCode.NoDefaultByArm, - byExpression.Line, - byExpression.Column - ); + } + + if (elseArm != null) + { + Visit(elseArm); + } + else + { + Log.EmitWarning( + "By-expression has no default arm and will always return `nil' if input matching fails. Consider adding a default arm using `else' keyword.", + CurrentFileName, + EvilMessageCode.NoDefaultByArm, + byExpression.Line, + byExpression.Column + ); - Chunk.CodeGenerator.Emit(OpCode.LDNIL); - } - - Chunk.UpdateLabel(endLabel, Chunk.CodeGenerator.IP); + Chunk.CodeGenerator.Emit(OpCode.LDNIL); } + + Chunk.UpdateLabel(endLabel, Chunk.CodeGenerator.IP); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Coalescing.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Coalescing.cs index a705b3ab..e441813f 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Coalescing.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Coalescing.cs @@ -1,26 +1,25 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Expressions; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(CoalescingExpression coalescingExpression) { - public override void Visit(CoalescingExpression coalescingExpression) - { - var valueNotNilLabel = Chunk.CreateLabel(); + var valueNotNilLabel = Chunk.CreateLabel(); - Visit(coalescingExpression.Left); - Chunk.CodeGenerator.Emit(OpCode.DUP); - Chunk.CodeGenerator.Emit(OpCode.LDNIL); - Chunk.CodeGenerator.Emit(OpCode.CNE); - Chunk.CodeGenerator.Emit(OpCode.TJMP, valueNotNilLabel); - Chunk.CodeGenerator.Emit(OpCode.POP); - Visit(coalescingExpression.Right); + Visit(coalescingExpression.Left); + Chunk.CodeGenerator.Emit(OpCode.DUP); + Chunk.CodeGenerator.Emit(OpCode.LDNIL); + Chunk.CodeGenerator.Emit(OpCode.CNE); + Chunk.CodeGenerator.Emit(OpCode.TJMP, valueNotNilLabel); + Chunk.CodeGenerator.Emit(OpCode.POP); + Visit(coalescingExpression.Right); - Chunk.UpdateLabel( - valueNotNilLabel, - Chunk.CodeGenerator.IP - ); - } + Chunk.UpdateLabel( + valueNotNilLabel, + Chunk.CodeGenerator.IP + ); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Conditional.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Conditional.cs index 5c236c3b..3db406ca 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Conditional.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Conditional.cs @@ -1,24 +1,23 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Expressions; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(ConditionalExpression conditionalExpression) { - public override void Visit(ConditionalExpression conditionalExpression) - { - var elseLabel = Chunk.CreateLabel(); - var endLabel = Chunk.CreateLabel(); + var elseLabel = Chunk.CreateLabel(); + var endLabel = Chunk.CreateLabel(); - Visit(conditionalExpression.Condition); - Chunk.CodeGenerator.Emit(OpCode.FJMP, elseLabel); + Visit(conditionalExpression.Condition); + Chunk.CodeGenerator.Emit(OpCode.FJMP, elseLabel); - Visit(conditionalExpression.TrueExpression); - Chunk.CodeGenerator.Emit(OpCode.JUMP, endLabel); - Chunk.UpdateLabel(elseLabel, Chunk.CodeGenerator.IP); + Visit(conditionalExpression.TrueExpression); + Chunk.CodeGenerator.Emit(OpCode.JUMP, endLabel); + Chunk.UpdateLabel(elseLabel, Chunk.CodeGenerator.IP); - Visit(conditionalExpression.FalseExpression); - Chunk.UpdateLabel(endLabel, Chunk.CodeGenerator.IP); - } + Visit(conditionalExpression.FalseExpression); + Chunk.UpdateLabel(endLabel, Chunk.CodeGenerator.IP); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Decrementation.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Decrementation.cs index cb026479..de2ec780 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Decrementation.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Decrementation.cs @@ -1,36 +1,19 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.TranslationEngine.Diagnostics; using EVIL.Grammar.AST.Expressions; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(DecrementationExpression decrementationExpression) { - public override void Visit(DecrementationExpression decrementationExpression) + if (decrementationExpression.Target is SymbolReferenceExpression vre) { - if (decrementationExpression.Target is SymbolReferenceExpression vre) - { - ThrowIfVarReadOnly(vre.Identifier); + ThrowIfVarReadOnly(vre.Identifier); - EmitVarGet(vre.Identifier); - { - if (decrementationExpression.IsPrefix) - { - Chunk.CodeGenerator.Emit(OpCode.DEC); - Chunk.CodeGenerator.Emit(OpCode.DUP); - } - else - { - Chunk.CodeGenerator.Emit(OpCode.DUP); - Chunk.CodeGenerator.Emit(OpCode.DEC); - } - } - EmitVarSet(vre.Identifier); - } - else if (decrementationExpression.Target is IndexerExpression ie) + EmitVarGet(vre.Identifier); { - Visit(ie); - if (decrementationExpression.IsPrefix) { Chunk.CodeGenerator.Emit(OpCode.DEC); @@ -41,21 +24,37 @@ public override void Visit(DecrementationExpression decrementationExpression) Chunk.CodeGenerator.Emit(OpCode.DUP); Chunk.CodeGenerator.Emit(OpCode.DEC); } + } + EmitVarSet(vre.Identifier); + } + else if (decrementationExpression.Target is IndexerExpression ie) + { + Visit(ie); - Visit(ie.Indexable); - Visit(ie.KeyExpression); - Chunk.CodeGenerator.Emit(OpCode.ELSET); + if (decrementationExpression.IsPrefix) + { + Chunk.CodeGenerator.Emit(OpCode.DEC); + Chunk.CodeGenerator.Emit(OpCode.DUP); } else { - Log.TerminateWithFatal( - "Illegal decrementation target.", - CurrentFileName, - EvilMessageCode.IllegalDecrementationTarget, - Line, - Column - ); + Chunk.CodeGenerator.Emit(OpCode.DUP); + Chunk.CodeGenerator.Emit(OpCode.DEC); } + + Visit(ie.Indexable); + Visit(ie.KeyExpression); + Chunk.CodeGenerator.Emit(OpCode.ELSET); + } + else + { + Log.TerminateWithFatal( + "Illegal decrementation target.", + CurrentFileName, + EvilMessageCode.IllegalDecrementationTarget, + Line, + Column + ); } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Error.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Error.cs index 435bc377..0d745694 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Error.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Error.cs @@ -1,46 +1,45 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.TranslationEngine.Diagnostics; using EVIL.Grammar.AST.Expressions; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(ErrorExpression errorExpression) { - public override void Visit(ErrorExpression errorExpression) + if (errorExpression.UserDataTable == null && errorExpression.ImplicitMessageConstant == null) { - if (errorExpression.UserDataTable == null && errorExpression.ImplicitMessageConstant == null) - { - Log.TerminateWithFatal( - "An error expression must have at least an implicit message constant.", - CurrentFileName, - EvilMessageCode.MissingErrorInformation, - errorExpression.Line, - errorExpression.Column - ); + Log.TerminateWithFatal( + "An error expression must have at least an implicit message constant.", + CurrentFileName, + EvilMessageCode.MissingErrorInformation, + errorExpression.Line, + errorExpression.Column + ); - return; - } + return; + } - if (errorExpression.UserDataTable != null) - { - Visit(errorExpression.UserDataTable); - } - else - { - Chunk.CodeGenerator.Emit(OpCode.TABNEW); - } - - if (errorExpression.ImplicitMessageConstant != null) - { - Visit(errorExpression.ImplicitMessageConstant!); - Chunk.CodeGenerator.Emit( - OpCode.LDSTR, - (int)Chunk.StringPool.FetchOrAdd("msg") - ); - Chunk.CodeGenerator.Emit(OpCode.ELINIT); - } + if (errorExpression.UserDataTable != null) + { + Visit(errorExpression.UserDataTable); + } + else + { + Chunk.CodeGenerator.Emit(OpCode.TABNEW); + } - Chunk.CodeGenerator.Emit(OpCode.ERRNEW); + if (errorExpression.ImplicitMessageConstant != null) + { + Visit(errorExpression.ImplicitMessageConstant!); + Chunk.CodeGenerator.Emit( + OpCode.LDSTR, + (int)Chunk.StringPool.FetchOrAdd("msg") + ); + Chunk.CodeGenerator.Emit(OpCode.ELINIT); } + + Chunk.CodeGenerator.Emit(OpCode.ERRNEW); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.ExtraArguments.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.ExtraArguments.cs index d63fed3d..55ac1845 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.ExtraArguments.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.ExtraArguments.cs @@ -1,14 +1,13 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Expressions; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(ExtraArgumentsExpression extraArgumentsExpression) { - public override void Visit(ExtraArgumentsExpression extraArgumentsExpression) - { - var mode = extraArgumentsExpression.UnwrapOnStack ? (byte)1 : (byte)0; - Chunk.CodeGenerator.Emit(OpCode.XARGS, mode); - } + var mode = extraArgumentsExpression.UnwrapOnStack ? (byte)1 : (byte)0; + Chunk.CodeGenerator.Emit(OpCode.XARGS, mode); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Fn.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Fn.cs index 1626c417..b818c0f0 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Fn.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Fn.cs @@ -1,33 +1,32 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Expressions; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(FnExpression fnExpression) { - public override void Visit(FnExpression fnExpression) + var id = InAnonymousSubChunkDo(() => { - var id = InAnonymousSubChunkDo(() => + InNewClosedScopeDo(() => { - InNewClosedScopeDo(() => - { - Chunk.DebugDatabase.DefinedOnLine = fnExpression.Line; + Chunk.DebugDatabase.DefinedOnLine = fnExpression.Line; - if (fnExpression.ParameterList != null) - { - Visit(fnExpression.ParameterList); - } + if (fnExpression.ParameterList != null) + { + Visit(fnExpression.ParameterList); + } - Visit(fnExpression.Statement); + Visit(fnExpression.Statement); - FinalizeChunk(); - }); + FinalizeChunk(); }); + }); - Chunk.CodeGenerator.Emit( - OpCode.LDCNK, - id - ); - } + Chunk.CodeGenerator.Emit( + OpCode.LDCNK, + id + ); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Incrementation.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Incrementation.cs index 05b63c5c..36e0096e 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Incrementation.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Incrementation.cs @@ -1,60 +1,59 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.TranslationEngine.Diagnostics; using EVIL.Grammar.AST.Expressions; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(IncrementationExpression incrementationExpression) { - public override void Visit(IncrementationExpression incrementationExpression) + if (incrementationExpression.Target is SymbolReferenceExpression vre) { - if (incrementationExpression.Target is SymbolReferenceExpression vre) - { - ThrowIfVarReadOnly(vre.Identifier); + ThrowIfVarReadOnly(vre.Identifier); - EmitVarGet(vre.Identifier); - if (incrementationExpression.IsPrefix) - { - Chunk.CodeGenerator.Emit(OpCode.INC); - Chunk.CodeGenerator.Emit(OpCode.DUP); - EmitVarSet(vre.Identifier); - } - else - { - Chunk.CodeGenerator.Emit(OpCode.DUP); - Chunk.CodeGenerator.Emit(OpCode.INC); - EmitVarSet(vre.Identifier); - } + EmitVarGet(vre.Identifier); + if (incrementationExpression.IsPrefix) + { + Chunk.CodeGenerator.Emit(OpCode.INC); + Chunk.CodeGenerator.Emit(OpCode.DUP); + EmitVarSet(vre.Identifier); } - else if (incrementationExpression.Target is IndexerExpression ie) + else { - Visit(ie); - - if (incrementationExpression.IsPrefix) - { - Chunk.CodeGenerator.Emit(OpCode.INC); - Chunk.CodeGenerator.Emit(OpCode.DUP); - } - else - { - Chunk.CodeGenerator.Emit(OpCode.DUP); - Chunk.CodeGenerator.Emit(OpCode.INC); - } + Chunk.CodeGenerator.Emit(OpCode.DUP); + Chunk.CodeGenerator.Emit(OpCode.INC); + EmitVarSet(vre.Identifier); + } + } + else if (incrementationExpression.Target is IndexerExpression ie) + { + Visit(ie); - Visit(ie.Indexable); - Visit(ie.KeyExpression); - Chunk.CodeGenerator.Emit(OpCode.ELSET); + if (incrementationExpression.IsPrefix) + { + Chunk.CodeGenerator.Emit(OpCode.INC); + Chunk.CodeGenerator.Emit(OpCode.DUP); } else { - Log.TerminateWithFatal( - "Illegal incrementation target.", - CurrentFileName, - EvilMessageCode.IllegalIncrementationTarget, - Line, - Column - ); + Chunk.CodeGenerator.Emit(OpCode.DUP); + Chunk.CodeGenerator.Emit(OpCode.INC); } + + Visit(ie.Indexable); + Visit(ie.KeyExpression); + Chunk.CodeGenerator.Emit(OpCode.ELSET); + } + else + { + Log.TerminateWithFatal( + "Illegal incrementation target.", + CurrentFileName, + EvilMessageCode.IllegalIncrementationTarget, + Line, + Column + ); } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Indexer.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Indexer.cs index d25f261f..1afd4149 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Indexer.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Indexer.cs @@ -1,15 +1,14 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Expressions; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(IndexerExpression indexerExpression) { - public override void Visit(IndexerExpression indexerExpression) - { - Visit(indexerExpression.Indexable); - Visit(indexerExpression.KeyExpression); - Chunk.CodeGenerator.Emit(OpCode.INDEX); - } + Visit(indexerExpression.Indexable); + Visit(indexerExpression.KeyExpression); + Chunk.CodeGenerator.Emit(OpCode.INDEX); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Invocation.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Invocation.cs index 5dd32319..495427ea 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Invocation.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Invocation.cs @@ -1,36 +1,35 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Expressions; using EVIL.Grammar.AST.Statements; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(InvocationExpression invocationExpression) { - public override void Visit(InvocationExpression invocationExpression) - { - Visit(invocationExpression.ArgumentList); + Visit(invocationExpression.ArgumentList); - if (invocationExpression.Parent is RetStatement - && invocationExpression.Callee is SymbolReferenceExpression varRef - && varRef.Identifier == Chunk.Name - && !invocationExpression.ArgumentList.IsVariadic) - { - Chunk.CodeGenerator.Emit(OpCode.TAILINVOKE); - } - else - { - Visit(invocationExpression.Callee); - Chunk.CodeGenerator.Emit( - OpCode.INVOKE, - invocationExpression.ArgumentList.Arguments.Count - ); + if (invocationExpression.Parent is RetStatement + && invocationExpression.Callee is SymbolReferenceExpression varRef + && varRef.Identifier == Chunk.Name + && !invocationExpression.ArgumentList.IsVariadic) + { + Chunk.CodeGenerator.Emit(OpCode.TAILINVOKE); + } + else + { + Visit(invocationExpression.Callee); + Chunk.CodeGenerator.Emit( + OpCode.INVOKE, + invocationExpression.ArgumentList.Arguments.Count + ); - Chunk.CodeGenerator.Emit( - invocationExpression.ArgumentList.IsVariadic + Chunk.CodeGenerator.Emit( + invocationExpression.ArgumentList.IsVariadic ? (byte)1 : (byte)0 - ); - } + ); } } -} +} \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Is.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Is.cs index 8260822d..47dcabda 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Is.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Is.cs @@ -1,16 +1,15 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Expressions; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(IsExpression isExpression) { - public override void Visit(IsExpression isExpression) - { - Visit(isExpression.Target); - Chunk.CodeGenerator.Emit(OpCode.TYPE); - Chunk.CodeGenerator.Emit(OpCode.LDTYPE, (int)isExpression.Type.Value); - Chunk.CodeGenerator.Emit(isExpression.Invert ? OpCode.CNE : OpCode.CEQ); - } + Visit(isExpression.Target); + Chunk.CodeGenerator.Emit(OpCode.TYPE); + Chunk.CodeGenerator.Emit(OpCode.LDTYPE, (int)isExpression.Type.Value); + Chunk.CodeGenerator.Emit(isExpression.Invert ? OpCode.CNE : OpCode.CEQ); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Self.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Self.cs index 25793b04..0a403380 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Self.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Self.cs @@ -1,25 +1,24 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.TranslationEngine.Diagnostics; using EVIL.Grammar.AST.Expressions; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(SelfExpression selfExpression) { - public override void Visit(SelfExpression selfExpression) + if (!Chunk.IsSelfAware) { - if (!Chunk.IsSelfAware) - { - Log.TerminateWithFatal( - "Attempt to use `self' in a self-unaware function.", - CurrentFileName, - EvilMessageCode.SelfUsedInSelfUnawareFunction, - Line, - Column - ); - } - - Chunk.CodeGenerator.Emit(OpCode.GETARG, 0); + Log.TerminateWithFatal( + "Attempt to use `self' in a self-unaware function.", + CurrentFileName, + EvilMessageCode.SelfUsedInSelfUnawareFunction, + Line, + Column + ); } + + Chunk.CodeGenerator.Emit(OpCode.GETARG, 0); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.SelfFn.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.SelfFn.cs index ac81bc68..e589793f 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.SelfFn.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.SelfFn.cs @@ -1,36 +1,35 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Expressions; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(SelfFnExpression selfFnExpression) { - public override void Visit(SelfFnExpression selfFnExpression) + var id = InAnonymousSubChunkDo(() => { - var id = InAnonymousSubChunkDo(() => + InNewClosedScopeDo(() => { - InNewClosedScopeDo(() => - { - Chunk.DebugDatabase.DefinedOnLine = selfFnExpression.Line; + Chunk.DebugDatabase.DefinedOnLine = selfFnExpression.Line; - Chunk.MarkSelfAware(); - /* implicit `self' */ Chunk.AllocateParameter(); + Chunk.MarkSelfAware(); + /* implicit `self' */ Chunk.AllocateParameter(); - if (selfFnExpression.ParameterList != null) - { - Visit(selfFnExpression.ParameterList); - } + if (selfFnExpression.ParameterList != null) + { + Visit(selfFnExpression.ParameterList); + } - Visit(selfFnExpression.Statement); + Visit(selfFnExpression.Statement); - FinalizeChunk(); - }); + FinalizeChunk(); }); + }); - Chunk.CodeGenerator.Emit( - OpCode.LDCNK, - id - ); - } + Chunk.CodeGenerator.Emit( + OpCode.LDCNK, + id + ); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.SelfInvocation.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.SelfInvocation.cs index d02c90f7..9c959b13 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.SelfInvocation.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.SelfInvocation.cs @@ -1,34 +1,33 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Expressions; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(SelfInvocationExpression selfInvocationExpression) { - public override void Visit(SelfInvocationExpression selfInvocationExpression) - { - Visit(selfInvocationExpression.Indexable); - Visit(selfInvocationExpression.ArgumentList); + Visit(selfInvocationExpression.Indexable); + Visit(selfInvocationExpression.ArgumentList); - Visit(selfInvocationExpression.Indexable); + Visit(selfInvocationExpression.Indexable); - var identifierNameId = Chunk.StringPool.FetchOrAdd( - selfInvocationExpression.Identifier.Name - ); + var identifierNameId = Chunk.StringPool.FetchOrAdd( + selfInvocationExpression.Identifier.Name + ); - Chunk.CodeGenerator.Emit(OpCode.LDSTR, (int)identifierNameId); - Chunk.CodeGenerator.Emit(OpCode.INDEX); + Chunk.CodeGenerator.Emit(OpCode.LDSTR, (int)identifierNameId); + Chunk.CodeGenerator.Emit(OpCode.INDEX); - Chunk.CodeGenerator.Emit( - OpCode.INVOKE, - selfInvocationExpression.ArgumentList.Arguments.Count + 1 /* Implicit `self' */ - ); + Chunk.CodeGenerator.Emit( + OpCode.INVOKE, + selfInvocationExpression.ArgumentList.Arguments.Count + 1 /* Implicit `self' */ + ); - Chunk.CodeGenerator.Emit( - selfInvocationExpression.ArgumentList.IsVariadic - ? (byte)1 - : (byte)0 - ); - } + Chunk.CodeGenerator.Emit( + selfInvocationExpression.ArgumentList.IsVariadic + ? (byte)1 + : (byte)0 + ); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.SymbolReference.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.SymbolReference.cs index abdc903a..0dba41e5 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.SymbolReference.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.SymbolReference.cs @@ -1,12 +1,11 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Grammar.AST.Expressions; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(SymbolReferenceExpression symbolReferenceExpression) { - public override void Visit(SymbolReferenceExpression symbolReferenceExpression) - { - EmitVarGet(symbolReferenceExpression.Identifier); - } + EmitVarGet(symbolReferenceExpression.Identifier); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Table.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Table.cs index 27a0e3ff..09a23e8c 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Table.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Table.cs @@ -1,45 +1,44 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Expressions; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(TableExpression tableExpression) { - public override void Visit(TableExpression tableExpression) - { - Chunk.CodeGenerator.Emit(OpCode.TABNEW); + Chunk.CodeGenerator.Emit(OpCode.TABNEW); - if (tableExpression.Keyed) + if (tableExpression.Keyed) + { + foreach (var expr in tableExpression.Initializers) { - foreach (var expr in tableExpression.Initializers) - { - var kvpe = (KeyValuePairExpression)expr; - Visit(kvpe.ValueNode); - Visit(kvpe.KeyNode); - Chunk.CodeGenerator.Emit(OpCode.ELINIT); - } + var kvpe = (KeyValuePairExpression)expr; + Visit(kvpe.ValueNode); + Visit(kvpe.KeyNode); + Chunk.CodeGenerator.Emit(OpCode.ELINIT); } - else + } + else + { + for (var i = 0; i < tableExpression.Initializers.Count; i++) { - for (var i = 0; i < tableExpression.Initializers.Count; i++) - { - Visit(tableExpression.Initializers[i]); + Visit(tableExpression.Initializers[i]); - if (i == 0) - { - Chunk.CodeGenerator.Emit(OpCode.LDZERO); - } - else if (i == 1) - { - Chunk.CodeGenerator.Emit(OpCode.LDONE); - } - else - { - Chunk.CodeGenerator.Emit(OpCode.LDNUM, (double)i); - } - - Chunk.CodeGenerator.Emit(OpCode.ELINIT); + if (i == 0) + { + Chunk.CodeGenerator.Emit(OpCode.LDZERO); + } + else if (i == 1) + { + Chunk.CodeGenerator.Emit(OpCode.LDONE); } + else + { + Chunk.CodeGenerator.Emit(OpCode.LDNUM, (double)i); + } + + Chunk.CodeGenerator.Emit(OpCode.ELINIT); } } } diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.TypeOf.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.TypeOf.cs index 1055147d..1e84b852 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.TypeOf.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.TypeOf.cs @@ -1,14 +1,13 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Expressions; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(TypeOfExpression typeOfExpression) { - public override void Visit(TypeOfExpression typeOfExpression) - { - Visit(typeOfExpression.Target); - Chunk.CodeGenerator.Emit(OpCode.TYPE); - } + Visit(typeOfExpression.Target); + Chunk.CodeGenerator.Emit(OpCode.TYPE); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Unary.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Unary.cs index 6a083d8d..604cd564 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Unary.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Unary.cs @@ -1,36 +1,35 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar; using EVIL.Grammar.AST.Expressions; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(UnaryExpression unaryExpression) { - public override void Visit(UnaryExpression unaryExpression) - { - Visit(unaryExpression.Right); + Visit(unaryExpression.Right); - if (unaryExpression.Type != UnaryOperationType.Plus) - { - Chunk.CodeGenerator.Emit( - unaryExpression.Type switch - { - UnaryOperationType.Minus => OpCode.ANEG, - UnaryOperationType.Length => OpCode.LENGTH, - UnaryOperationType.BitwiseNot => OpCode.BNOT, - UnaryOperationType.LogicalNot => OpCode.LNOT, - UnaryOperationType.ToString => OpCode.TOSTRING, - UnaryOperationType.ToNumber => OpCode.TONUMBER, - _ => Log.TerminateWithInternalFailure( - $"Invalid unary operation type '{unaryExpression.Type}'.", - CurrentFileName, - line: Line, - column: Column, - dummyReturn: OpCode.NOOP - ) - } - ); - } + if (unaryExpression.Type != UnaryOperationType.Plus) + { + Chunk.CodeGenerator.Emit( + unaryExpression.Type switch + { + UnaryOperationType.Minus => OpCode.ANEG, + UnaryOperationType.Length => OpCode.LENGTH, + UnaryOperationType.BitwiseNot => OpCode.BNOT, + UnaryOperationType.LogicalNot => OpCode.LNOT, + UnaryOperationType.ToString => OpCode.TOSTRING, + UnaryOperationType.ToNumber => OpCode.TONUMBER, + _ => Log.TerminateWithInternalFailure( + $"Invalid unary operation type '{unaryExpression.Type}'.", + CurrentFileName, + line: Line, + column: Column, + dummyReturn: OpCode.NOOP + ) + } + ); } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Yield.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Yield.cs index 2224975a..2393dac5 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Yield.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Expression.Yield.cs @@ -1,21 +1,20 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Expressions; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(YieldExpression yieldExpression) { - public override void Visit(YieldExpression yieldExpression) - { - Visit(yieldExpression.ArgumentList); - Visit(yieldExpression.Target); + Visit(yieldExpression.ArgumentList); + Visit(yieldExpression.Target); - Chunk.CodeGenerator.Emit( - OpCode.YIELD, - yieldExpression.ArgumentList.Arguments.Count - ); + Chunk.CodeGenerator.Emit( + OpCode.YIELD, + yieldExpression.ArgumentList.Arguments.Count + ); - Chunk.CodeGenerator.Emit(OpCode.YRET); - } + Chunk.CodeGenerator.Emit(OpCode.YRET); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.List.Argument.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.List.Argument.cs index a567c0b7..cc820961 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.List.Argument.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.List.Argument.cs @@ -1,15 +1,14 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Grammar.AST.Miscellaneous; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(ArgumentList argumentList) { - public override void Visit(ArgumentList argumentList) + for (var i = 0; i < argumentList.Arguments.Count; i++) { - for (var i = 0; i < argumentList.Arguments.Count; i++) - { - Visit(argumentList.Arguments[i]); - } + Visit(argumentList.Arguments[i]); } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.List.Attribute.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.List.Attribute.cs index ffa6fb96..95640c19 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.List.Attribute.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.List.Attribute.cs @@ -1,13 +1,12 @@ -using EVIL.Grammar.AST.Statements.TopLevel; +namespace EVIL.Ceres.TranslationEngine; -namespace EVIL.Ceres.TranslationEngine +using EVIL.Grammar.AST.Statements.TopLevel; + +public partial class Compiler { - public partial class Compiler + public override void Visit(AttributeList attributeList) { - public override void Visit(AttributeList attributeList) - { - foreach (var attr in attributeList.Attributes) - Visit(attr); - } + foreach (var attr in attributeList.Attributes) + Visit(attr); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.List.Parameter.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.List.Parameter.cs index c888e359..48f6d910 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.List.Parameter.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.List.Parameter.cs @@ -1,57 +1,56 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.TranslationEngine.Diagnostics; using EVIL.Grammar.AST.Miscellaneous; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(ParameterList parameterList) { - public override void Visit(ParameterList parameterList) + for (var i = 0; i < parameterList.Parameters.Count; i++) { - for (var i = 0; i < parameterList.Parameters.Count; i++) - { - var parameter = parameterList.Parameters[i]; - var parameterId = Chunk.AllocateParameter(); + var parameter = parameterList.Parameters[i]; + var parameterId = Chunk.AllocateParameter(); - try - { - CurrentScope.DefineParameter( - parameter.Identifier.Name, - parameterId, - parameter.ReadWrite, - parameter.Line, - parameter.Column - ); - } - catch (DuplicateSymbolException dse) - { - Log.TerminateWithFatal( - $"The symbol '{parameter.Identifier.Name}' already exists in this scope " + - $"and is a {dse.ExistingSymbol.TypeName} (previously defined on line {dse.Line}, column {dse.Column}).", - CurrentFileName, - EvilMessageCode.DuplicateSymbolInScope, - parameter.Identifier.Line, - parameter.Identifier.Column, - dse - ); + try + { + CurrentScope.DefineParameter( + parameter.Identifier.Name, + parameterId, + parameter.ReadWrite, + parameter.Line, + parameter.Column + ); + } + catch (DuplicateSymbolException dse) + { + Log.TerminateWithFatal( + $"The symbol '{parameter.Identifier.Name}' already exists in this scope " + + $"and is a {dse.ExistingSymbol.TypeName} (previously defined on line {dse.Line}, column {dse.Column}).", + CurrentFileName, + EvilMessageCode.DuplicateSymbolInScope, + parameter.Identifier.Line, + parameter.Identifier.Column, + dse + ); + + // Return just in case - TerminateWithFatal should never return, ever. + return; + } - // Return just in case - TerminateWithFatal should never return, ever. - return; - } + Chunk.DebugDatabase.SetParameterName( + parameterId, + parameter.Identifier.Name, + parameter.ReadWrite + ); - Chunk.DebugDatabase.SetParameterName( + if (parameter.Initializer != null) + { + Chunk.InitializeParameter( parameterId, - parameter.Identifier.Name, - parameter.ReadWrite + ExtractConstantValueFrom(parameter.Initializer) ); - - if (parameter.Initializer != null) - { - Chunk.InitializeParameter( - parameterId, - ExtractConstantValueFrom(parameter.Initializer) - ); - } } } } diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Node.Attribute.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Node.Attribute.cs index 2d99dc78..beee9d50 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Node.Attribute.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Node.Attribute.cs @@ -1,44 +1,43 @@ +namespace EVIL.Ceres.TranslationEngine; + using System; using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Miscellaneous; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(AttributeNode attributeNode) { - public override void Visit(AttributeNode attributeNode) - { - var attribute = new ChunkAttribute(attributeNode.Identifier.Name); + var attribute = new ChunkAttribute(attributeNode.Identifier.Name); - foreach (var valueNode in attributeNode.Values) - { - attribute.Values.Add( - ExtractConstantValueFrom(valueNode) - ); - } + foreach (var valueNode in attributeNode.Values) + { + attribute.Values.Add( + ExtractConstantValueFrom(valueNode) + ); + } - foreach (var propertyKvp in attributeNode.Properties) - { - attribute.Properties.Add( - propertyKvp.Key.Name, - ExtractConstantValueFrom(propertyKvp.Value) - ); - } + foreach (var propertyKvp in attributeNode.Properties) + { + attribute.Properties.Add( + propertyKvp.Key.Name, + ExtractConstantValueFrom(propertyKvp.Value) + ); + } - Chunk.AddAttribute(attribute); + Chunk.AddAttribute(attribute); - if (_attributeProcessors.TryGetValue(attribute.Name, out var processors)) + if (_attributeProcessors.TryGetValue(attribute.Name, out var processors)) + { + foreach (var processor in processors) { - foreach (var processor in processors) + try + { + processor.Invoke(attribute, Chunk); + } + catch (Exception e) { - try - { - processor.Invoke(attribute, Chunk); - } - catch (Exception e) - { - throw new AttributeProcessorException(attribute, Chunk, e); - } + throw new AttributeProcessorException(attribute, Chunk, e); } } } diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Node.Program.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Node.Program.cs index 65cef8e1..3b14f9e3 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Node.Program.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Node.Program.cs @@ -1,15 +1,14 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Grammar.AST.Miscellaneous; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(ProgramNode programNode) { - public override void Visit(ProgramNode programNode) + foreach (var statement in programNode.Statements) { - foreach (var statement in programNode.Statements) - { - Visit(statement); - } + Visit(statement); } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Block.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Block.cs index e8573030..80d11065 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Block.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Block.cs @@ -1,18 +1,17 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Grammar.AST.Statements; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(BlockStatement blockStatement) { - public override void Visit(BlockStatement blockStatement) + InNewLocalScopeDo(() => { - InNewLocalScopeDo(() => + foreach (var node in blockStatement.Statements) { - foreach (var node in blockStatement.Statements) - { - Visit(node); - } - }); - } + Visit(node); + } + }); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Break.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Break.cs index 4c5f9565..86c4de42 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Break.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Break.cs @@ -1,13 +1,12 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Statements; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(BreakStatement breakStatement) { - public override void Visit(BreakStatement breakStatement) - { - Chunk.CodeGenerator.Emit(OpCode.JUMP, Loop.EndLabel); - } + Chunk.CodeGenerator.Emit(OpCode.JUMP, Loop.EndLabel); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.DoWhile.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.DoWhile.cs index e14696e1..01bd4c53 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.DoWhile.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.DoWhile.cs @@ -1,21 +1,20 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Statements; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(DoWhileStatement doWhileStatement) { - public override void Visit(DoWhileStatement doWhileStatement) + InNewLoopDo(Loop.LoopKind.DoWhile, () => { - InNewLoopDo(Loop.LoopKind.DoWhile, () => - { - Visit(doWhileStatement.Statement); + Visit(doWhileStatement.Statement); - Visit(doWhileStatement.Condition); - Chunk.CodeGenerator.Emit(OpCode.TJMP, Loop.StartLabel); + Visit(doWhileStatement.Condition); + Chunk.CodeGenerator.Emit(OpCode.TJMP, Loop.StartLabel); - Chunk.UpdateLabel(Loop.EndLabel, Chunk.CodeGenerator.IP); - }, false); - } + Chunk.UpdateLabel(Loop.EndLabel, Chunk.CodeGenerator.IP); + }, false); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Each.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Each.cs index ed6c5e3b..55d16252 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Each.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Each.cs @@ -1,27 +1,57 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.TranslationEngine.Diagnostics; using EVIL.Grammar.AST.Statements; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(EachStatement eachStatement) { - public override void Visit(EachStatement eachStatement) + InNewLocalScopeDo(() => { - InNewLocalScopeDo(() => + int keyLocal = Chunk.AllocateLocal(); + int valueLocal = -1; + var isKeyValue = false; + + try + { + CurrentScope.DefineLocal( + eachStatement.KeyIdentifier.Name, + keyLocal, + false, + eachStatement.KeyIdentifier.Line, + eachStatement.KeyIdentifier.Column + ); + } + catch (DuplicateSymbolException dse) + { + Log.TerminateWithFatal( + $"The symbol '{eachStatement.KeyIdentifier.Name}' already exists in this scope " + + $"and is a {dse.ExistingSymbol.TypeName} (previously defined on line {dse.Line}, column {dse.Column}).", + CurrentFileName, + EvilMessageCode.DuplicateSymbolInScope, + eachStatement.KeyIdentifier.Line, + eachStatement.KeyIdentifier.Column, + dse + ); + + // Return just in case - TerminateWithFatal should never return, ever. + return; + } + + if (eachStatement.ValueIdentifier != null) { - int keyLocal = Chunk.AllocateLocal(); - int valueLocal = -1; - var isKeyValue = false; + valueLocal = Chunk.AllocateLocal(); try { CurrentScope.DefineLocal( - eachStatement.KeyIdentifier.Name, - keyLocal, + eachStatement.ValueIdentifier.Name, + valueLocal, false, - eachStatement.KeyIdentifier.Line, - eachStatement.KeyIdentifier.Column + eachStatement.ValueIdentifier.Line, + eachStatement.ValueIdentifier.Column ); } catch (DuplicateSymbolException dse) @@ -31,8 +61,8 @@ public override void Visit(EachStatement eachStatement) $"and is a {dse.ExistingSymbol.TypeName} (previously defined on line {dse.Line}, column {dse.Column}).", CurrentFileName, EvilMessageCode.DuplicateSymbolInScope, - eachStatement.KeyIdentifier.Line, - eachStatement.KeyIdentifier.Column, + eachStatement.ValueIdentifier.Line, + eachStatement.ValueIdentifier.Column, dse ); @@ -40,60 +70,29 @@ public override void Visit(EachStatement eachStatement) return; } - if (eachStatement.ValueIdentifier != null) - { - valueLocal = Chunk.AllocateLocal(); - - try - { - CurrentScope.DefineLocal( - eachStatement.ValueIdentifier.Name, - valueLocal, - false, - eachStatement.ValueIdentifier.Line, - eachStatement.ValueIdentifier.Column - ); - } - catch (DuplicateSymbolException dse) - { - Log.TerminateWithFatal( - $"The symbol '{eachStatement.KeyIdentifier.Name}' already exists in this scope " + - $"and is a {dse.ExistingSymbol.TypeName} (previously defined on line {dse.Line}, column {dse.Column}).", - CurrentFileName, - EvilMessageCode.DuplicateSymbolInScope, - eachStatement.ValueIdentifier.Line, - eachStatement.ValueIdentifier.Column, - dse - ); + isKeyValue = true; + } - // Return just in case - TerminateWithFatal should never return, ever. - return; - } - - isKeyValue = true; - } - - Visit(eachStatement.Iterable); - Chunk.CodeGenerator.Emit(OpCode.EACH); + Visit(eachStatement.Iterable); + Chunk.CodeGenerator.Emit(OpCode.EACH); - InNewLoopDo(Loop.LoopKind.Each, () => - { - Chunk.UpdateLabel(Loop.StartLabel, Chunk.CodeGenerator.IP); - Chunk.CodeGenerator.Emit(OpCode.NEXT, isKeyValue ? 1 : 0); - Chunk.CodeGenerator.Emit(OpCode.FJMP, Loop.EndLabel); - Chunk.CodeGenerator.Emit(OpCode.SETLOCAL, keyLocal); + InNewLoopDo(Loop.LoopKind.Each, () => + { + Chunk.UpdateLabel(Loop.StartLabel, Chunk.CodeGenerator.IP); + Chunk.CodeGenerator.Emit(OpCode.NEXT, isKeyValue ? 1 : 0); + Chunk.CodeGenerator.Emit(OpCode.FJMP, Loop.EndLabel); + Chunk.CodeGenerator.Emit(OpCode.SETLOCAL, keyLocal); - if (isKeyValue) - { - Chunk.CodeGenerator.Emit(OpCode.SETLOCAL, valueLocal); - } + if (isKeyValue) + { + Chunk.CodeGenerator.Emit(OpCode.SETLOCAL, valueLocal); + } - Visit(eachStatement.Statement); - Chunk.CodeGenerator.Emit(OpCode.JUMP, Loop.StartLabel); - Chunk.UpdateLabel(Loop.EndLabel, Chunk.CodeGenerator.IP); - Chunk.CodeGenerator.Emit(OpCode.EEND); - }, false); - }); - } + Visit(eachStatement.Statement); + Chunk.CodeGenerator.Emit(OpCode.JUMP, Loop.StartLabel); + Chunk.UpdateLabel(Loop.EndLabel, Chunk.CodeGenerator.IP); + Chunk.CodeGenerator.Emit(OpCode.EEND); + }, false); + }); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Expression.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Expression.cs index d37a0b6d..cb2bedd8 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Expression.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Expression.cs @@ -1,19 +1,18 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Expressions; using EVIL.Grammar.AST.Statements; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(ExpressionStatement expressionStatement) { - public override void Visit(ExpressionStatement expressionStatement) - { - Visit(expressionStatement.Expression); + Visit(expressionStatement.Expression); - if (expressionStatement.Expression is not AssignmentExpression) - { - Chunk.CodeGenerator.Emit(OpCode.POP); - } + if (expressionStatement.Expression is not AssignmentExpression) + { + Chunk.CodeGenerator.Emit(OpCode.POP); } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.ExpressionBody.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.ExpressionBody.cs index 9505f4f8..207e1b50 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.ExpressionBody.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.ExpressionBody.cs @@ -1,14 +1,13 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Statements; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(ExpressionBodyStatement expressionBodyStatement) { - public override void Visit(ExpressionBodyStatement expressionBodyStatement) - { - Visit(expressionBodyStatement.Expression); - Chunk.CodeGenerator.Emit(OpCode.RET); - } + Visit(expressionBodyStatement.Expression); + Chunk.CodeGenerator.Emit(OpCode.RET); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Fn.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Fn.cs index 79170d6f..ee59d635 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Fn.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Fn.cs @@ -1,96 +1,95 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.TranslationEngine.Diagnostics; using EVIL.Grammar.AST.Statements.TopLevel; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(FnStatement fnStatement) { - public override void Visit(FnStatement fnStatement) + var localId = -1; + if (fnStatement.IsLocalDefinition) { - var localId = -1; - if (fnStatement.IsLocalDefinition) - { - localId = Chunk.AllocateLocal(); + localId = Chunk.AllocateLocal(); - try - { - CurrentScope.DefineLocal( - fnStatement.Identifier.Name, - localId, - false, - fnStatement.Line, - fnStatement.Column - ); - } - catch (DuplicateSymbolException dse) - { - Log.TerminateWithFatal( - $"The symbol '{fnStatement.Identifier.Name}' already exists in this scope " + - $"and is a {dse.ExistingSymbol.TypeName} (previously defined on line {dse.Line}, column {dse.Column}).", - CurrentFileName, - EvilMessageCode.DuplicateSymbolInScope, - fnStatement.Identifier.Line, - fnStatement.Identifier.Column, - dse - ); + try + { + CurrentScope.DefineLocal( + fnStatement.Identifier.Name, + localId, + false, + fnStatement.Line, + fnStatement.Column + ); + } + catch (DuplicateSymbolException dse) + { + Log.TerminateWithFatal( + $"The symbol '{fnStatement.Identifier.Name}' already exists in this scope " + + $"and is a {dse.ExistingSymbol.TypeName} (previously defined on line {dse.Line}, column {dse.Column}).", + CurrentFileName, + EvilMessageCode.DuplicateSymbolInScope, + fnStatement.Identifier.Line, + fnStatement.Identifier.Column, + dse + ); - // Return just in case - TerminateWithFatal should never return, ever. - return; - } + // Return just in case - TerminateWithFatal should never return, ever. + return; } + } - var id = InNamedSubChunkDo(fnStatement.Identifier.Name, () => + var id = InNamedSubChunkDo(fnStatement.Identifier.Name, () => + { + InNewClosedScopeDo(() => { - InNewClosedScopeDo(() => - { - Chunk.DebugDatabase.DefinedOnLine = fnStatement.Line; + Chunk.DebugDatabase.DefinedOnLine = fnStatement.Line; - InNewLocalScopeDo(() => + InNewLocalScopeDo(() => + { + if (fnStatement.ParameterList != null) { - if (fnStatement.ParameterList != null) - { - Visit(fnStatement.ParameterList); - } + Visit(fnStatement.ParameterList); + } - Visit(fnStatement.Statement); - }); + Visit(fnStatement.Statement); + }); - FinalizeChunk(); + FinalizeChunk(); - if (fnStatement.AttributeList != null) - { - Visit(fnStatement.AttributeList); - } - }); - }, out var wasExistingReplaced, out var replacedChunk); + if (fnStatement.AttributeList != null) + { + Visit(fnStatement.AttributeList); + } + }); + }, out var wasExistingReplaced, out var replacedChunk); - if (wasExistingReplaced) - { - Log.EmitWarning( - $"Named function '{replacedChunk.Name}' defined on line {fnStatement.Line} is " + - $"re-defining a previously defined function of the same name in {replacedChunk.DebugDatabase.DefinedInFile} on line {fnStatement.Line}.", - CurrentFileName, - EvilMessageCode.FnStatementRedefinedExistingChunk, - fnStatement.Line, - fnStatement.Column - ); - } + if (wasExistingReplaced) + { + Log.EmitWarning( + $"Named function '{replacedChunk.Name}' defined on line {fnStatement.Line} is " + + $"re-defining a previously defined function of the same name in {replacedChunk.DebugDatabase.DefinedInFile} on line {fnStatement.Line}.", + CurrentFileName, + EvilMessageCode.FnStatementRedefinedExistingChunk, + fnStatement.Line, + fnStatement.Column + ); + } - Chunk.CodeGenerator.Emit(OpCode.LDCNK, id); + Chunk.CodeGenerator.Emit(OpCode.LDCNK, id); - if (fnStatement.IsLocalDefinition) - { - Chunk.CodeGenerator.Emit(OpCode.SETLOCAL, localId); - } - else - { - Chunk.CodeGenerator.Emit( - OpCode.LDSTR, - (int)Chunk.StringPool.FetchOrAdd(fnStatement.Identifier.Name) - ); - Chunk.CodeGenerator.Emit(OpCode.SETGLOBAL); - } + if (fnStatement.IsLocalDefinition) + { + Chunk.CodeGenerator.Emit(OpCode.SETLOCAL, localId); + } + else + { + Chunk.CodeGenerator.Emit( + OpCode.LDSTR, + (int)Chunk.StringPool.FetchOrAdd(fnStatement.Identifier.Name) + ); + Chunk.CodeGenerator.Emit(OpCode.SETGLOBAL); } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.FnIndexed.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.FnIndexed.cs index d6a77855..06fd95f2 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.FnIndexed.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.FnIndexed.cs @@ -1,69 +1,68 @@ -using System.Linq; +namespace EVIL.Ceres.TranslationEngine; + +using System.Linq; using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.TranslationEngine.Diagnostics; using EVIL.Grammar.AST.Statements; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(FnIndexedStatement fnIndexedStatement) { - public override void Visit(FnIndexedStatement fnIndexedStatement) + var indexedChunkName = fnIndexedStatement.Indexer.BuildChainStringRepresentation(); + + if (Chunk.SubChunks.FirstOrDefault(x => x.Name.StartsWith(indexedChunkName)) != null) { - var indexedChunkName = fnIndexedStatement.Indexer.BuildChainStringRepresentation(); + var postfix = Chunk.SubChunks.Count(x => x.Name.StartsWith(indexedChunkName)); + indexedChunkName = $"{indexedChunkName}_{postfix}"; + } - if (Chunk.SubChunks.FirstOrDefault(x => x.Name.StartsWith(indexedChunkName)) != null) + var id = InNamedSubChunkDo( + $"{indexedChunkName}", + () => { - var postfix = Chunk.SubChunks.Count(x => x.Name.StartsWith(indexedChunkName)); - indexedChunkName = $"{indexedChunkName}_{postfix}"; - } - - var id = InNamedSubChunkDo( - $"{indexedChunkName}", - () => + InNewClosedScopeDo(() => { - InNewClosedScopeDo(() => - { - Chunk.DebugDatabase.DefinedOnLine = fnIndexedStatement.Line; + Chunk.DebugDatabase.DefinedOnLine = fnIndexedStatement.Line; - if (fnIndexedStatement.ParameterList != null) - { - Visit(fnIndexedStatement.ParameterList); - } + if (fnIndexedStatement.ParameterList != null) + { + Visit(fnIndexedStatement.ParameterList); + } - Visit(fnIndexedStatement.InnerStatement); - FinalizeChunk(); + Visit(fnIndexedStatement.InnerStatement); + FinalizeChunk(); - if (fnIndexedStatement.AttributeList != null) - { - Visit(fnIndexedStatement.AttributeList); - } - }); - }, out var wasExistingReplaced, out var replacedChunk - ); + if (fnIndexedStatement.AttributeList != null) + { + Visit(fnIndexedStatement.AttributeList); + } + }); + }, out var wasExistingReplaced, out var replacedChunk + ); - if (wasExistingReplaced) - { - Log.TerminateWithInternalFailure( - $"Indexed function '{replacedChunk.Name}' defined on line {fnIndexedStatement.Line} has " + - $"re-defined a previously defined function of the same name in {replacedChunk.DebugDatabase.DefinedInFile} on line {fnIndexedStatement.Line}.", - CurrentFileName, - EvilMessageCode.FnIndexedStatementRedefinedExistingChunk, - fnIndexedStatement.Line, - fnIndexedStatement.Column - ); + if (wasExistingReplaced) + { + Log.TerminateWithInternalFailure( + $"Indexed function '{replacedChunk.Name}' defined on line {fnIndexedStatement.Line} has " + + $"re-defined a previously defined function of the same name in {replacedChunk.DebugDatabase.DefinedInFile} on line {fnIndexedStatement.Line}.", + CurrentFileName, + EvilMessageCode.FnIndexedStatementRedefinedExistingChunk, + fnIndexedStatement.Line, + fnIndexedStatement.Column + ); - return; - } + return; + } - Chunk.CodeGenerator.Emit( - OpCode.LDCNK, - id - ); + Chunk.CodeGenerator.Emit( + OpCode.LDCNK, + id + ); - Visit(fnIndexedStatement.Indexer.Indexable); - Visit(fnIndexedStatement.Indexer.KeyExpression); + Visit(fnIndexedStatement.Indexer.Indexable); + Visit(fnIndexedStatement.Indexer.KeyExpression); - Chunk.CodeGenerator.Emit(OpCode.ELSET); - } + Chunk.CodeGenerator.Emit(OpCode.ELSET); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.FnTargeted.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.FnTargeted.cs index 19f4006c..3b962d8f 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.FnTargeted.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.FnTargeted.cs @@ -1,3 +1,5 @@ +namespace EVIL.Ceres.TranslationEngine; + using System.Linq; using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.TranslationEngine.Diagnostics; @@ -5,103 +7,100 @@ using EVIL.Grammar.AST.Miscellaneous; using EVIL.Grammar.AST.Statements; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(FnTargetedStatement fnTargetedStatement) { - public override void Visit(FnTargetedStatement fnTargetedStatement) - { - string primaryName; + string primaryName; - if (fnTargetedStatement.PrimaryTarget is SelfExpression) - { - primaryName = "self"; - } - else if (fnTargetedStatement.PrimaryTarget is IdentifierNode identifierNode) - { - primaryName = identifierNode.Name; - } - else - { - Log.TerminateWithInternalFailure( - $"Expected a self-expression or an identifier found an unsupported node type {fnTargetedStatement.PrimaryTarget.GetType().FullName}.", - CurrentFileName, - EvilMessageCode.UnexpectedSyntaxNodeFound, - fnTargetedStatement.Line, - fnTargetedStatement.Column - ); + if (fnTargetedStatement.PrimaryTarget is SelfExpression) + { + primaryName = "self"; + } + else if (fnTargetedStatement.PrimaryTarget is IdentifierNode identifierNode) + { + primaryName = identifierNode.Name; + } + else + { + Log.TerminateWithInternalFailure( + $"Expected a self-expression or an identifier found an unsupported node type {fnTargetedStatement.PrimaryTarget.GetType().FullName}.", + CurrentFileName, + EvilMessageCode.UnexpectedSyntaxNodeFound, + fnTargetedStatement.Line, + fnTargetedStatement.Column + ); - return; - } + return; + } - var targetedChunkName = $"{primaryName}::{fnTargetedStatement.SecondaryIdentifier.Name}"; + var targetedChunkName = $"{primaryName}::{fnTargetedStatement.SecondaryIdentifier.Name}"; - if (Chunk.SubChunks.FirstOrDefault(x => x.Name.StartsWith(targetedChunkName)) != null) - { - var postfix = Chunk.SubChunks.Count(x => x.Name.StartsWith(targetedChunkName)); - targetedChunkName = $"{targetedChunkName}_{postfix}"; - } + if (Chunk.SubChunks.FirstOrDefault(x => x.Name.StartsWith(targetedChunkName)) != null) + { + var postfix = Chunk.SubChunks.Count(x => x.Name.StartsWith(targetedChunkName)); + targetedChunkName = $"{targetedChunkName}_{postfix}"; + } - var id = InNamedSubChunkDo( - $"{targetedChunkName}", - () => + var id = InNamedSubChunkDo( + $"{targetedChunkName}", + () => + { + InNewClosedScopeDo(() => { - InNewClosedScopeDo(() => - { - Chunk.DebugDatabase.DefinedOnLine = fnTargetedStatement.Line; - Chunk.MarkSelfAware(); - /* implicit `self' */ Chunk.AllocateParameter(); + Chunk.DebugDatabase.DefinedOnLine = fnTargetedStatement.Line; + Chunk.MarkSelfAware(); + /* implicit `self' */ Chunk.AllocateParameter(); - if (fnTargetedStatement.ParameterList != null) - { - Visit(fnTargetedStatement.ParameterList); - } + if (fnTargetedStatement.ParameterList != null) + { + Visit(fnTargetedStatement.ParameterList); + } - Visit(fnTargetedStatement.InnerStatement); - FinalizeChunk(); + Visit(fnTargetedStatement.InnerStatement); + FinalizeChunk(); - if (fnTargetedStatement.AttributeList != null) - { - Visit(fnTargetedStatement.AttributeList); - } - }); - }, out var wasExistingReplaced, out var replacedChunk - ); + if (fnTargetedStatement.AttributeList != null) + { + Visit(fnTargetedStatement.AttributeList); + } + }); + }, out var wasExistingReplaced, out var replacedChunk + ); - if (wasExistingReplaced) - { - Log.TerminateWithInternalFailure( - $"Targeted function '{replacedChunk.Name}' defined on line {fnTargetedStatement.Line} has " + - $"re-defined a previously defined function of the same name in {replacedChunk.DebugDatabase.DefinedInFile} on line {fnTargetedStatement.Line}.", - CurrentFileName, - EvilMessageCode.FnTargetedStatementRedefinedExistingChunk, - fnTargetedStatement.Line, - fnTargetedStatement.Column - ); + if (wasExistingReplaced) + { + Log.TerminateWithInternalFailure( + $"Targeted function '{replacedChunk.Name}' defined on line {fnTargetedStatement.Line} has " + + $"re-defined a previously defined function of the same name in {replacedChunk.DebugDatabase.DefinedInFile} on line {fnTargetedStatement.Line}.", + CurrentFileName, + EvilMessageCode.FnTargetedStatementRedefinedExistingChunk, + fnTargetedStatement.Line, + fnTargetedStatement.Column + ); - return; - } + return; + } - Chunk.CodeGenerator.Emit( - OpCode.LDCNK, - id - ); + Chunk.CodeGenerator.Emit( + OpCode.LDCNK, + id + ); - if (fnTargetedStatement.IsSelfTargeting) - { - Visit(fnTargetedStatement.PrimaryTarget); - } - else - { - EmitVarGet(primaryName); - } + if (fnTargetedStatement.IsSelfTargeting) + { + Visit(fnTargetedStatement.PrimaryTarget); + } + else + { + EmitVarGet(primaryName); + } - Chunk.CodeGenerator.Emit( - OpCode.LDSTR, - (int)Chunk.StringPool.FetchOrAdd(fnTargetedStatement.SecondaryIdentifier.Name) - ); + Chunk.CodeGenerator.Emit( + OpCode.LDSTR, + (int)Chunk.StringPool.FetchOrAdd(fnTargetedStatement.SecondaryIdentifier.Name) + ); - Chunk.CodeGenerator.Emit(OpCode.ELSET); - } + Chunk.CodeGenerator.Emit(OpCode.ELSET); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.For.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.For.cs index af22399b..5b38b1d8 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.For.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.For.cs @@ -1,32 +1,31 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Statements; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(ForStatement forStatement) { - public override void Visit(ForStatement forStatement) + InNewLocalScopeDo(() => { - InNewLocalScopeDo(() => - { - foreach (var statement in forStatement.Assignments) - Visit(statement); + foreach (var statement in forStatement.Assignments) + Visit(statement); - InNewLoopDo(Loop.LoopKind.For, () => - { - Visit(forStatement.Condition); - Chunk.CodeGenerator.Emit(OpCode.FJMP, Loop.EndLabel); + InNewLoopDo(Loop.LoopKind.For, () => + { + Visit(forStatement.Condition); + Chunk.CodeGenerator.Emit(OpCode.FJMP, Loop.EndLabel); - Visit(forStatement.Statement); - Chunk.UpdateLabel(Loop.StartLabel, Chunk.CodeGenerator.IP); + Visit(forStatement.Statement); + Chunk.UpdateLabel(Loop.StartLabel, Chunk.CodeGenerator.IP); - foreach (var iterationStatement in forStatement.IterationStatements) - Visit(iterationStatement); + foreach (var iterationStatement in forStatement.IterationStatements) + Visit(iterationStatement); - Chunk.CodeGenerator.Emit(OpCode.JUMP, Loop.ExtraLabel); - Chunk.UpdateLabel(Loop.EndLabel, Chunk.CodeGenerator.IP); - }, true); - }); - } + Chunk.CodeGenerator.Emit(OpCode.JUMP, Loop.ExtraLabel); + Chunk.UpdateLabel(Loop.EndLabel, Chunk.CodeGenerator.IP); + }, true); + }); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.If.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.If.cs index e97f9d82..8925dc7f 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.If.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.If.cs @@ -1,3 +1,5 @@ +namespace EVIL.Ceres.TranslationEngine; + using System.Collections.Generic; using System.Linq; using EVIL.Ceres.ExecutionEngine.Diagnostics; @@ -6,84 +8,81 @@ using EVIL.Grammar.AST.Expressions; using EVIL.Grammar.AST.Statements; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(IfStatement ifStatement) { - public override void Visit(IfStatement ifStatement) - { - var statementEnd = Chunk.CreateLabel(); + var statementEnd = Chunk.CreateLabel(); - for (var i = 0; i < ifStatement.Conditions.Count; i++) - { - var statementStart = Chunk.CreateLabel(); - var caseEnd = Chunk.CreateLabel(); - var currentConditionExpression = ifStatement.Conditions[i]; + for (var i = 0; i < ifStatement.Conditions.Count; i++) + { + var statementStart = Chunk.CreateLabel(); + var caseEnd = Chunk.CreateLabel(); + var currentConditionExpression = ifStatement.Conditions[i]; - if (currentConditionExpression is BinaryExpression orBex - && orBex.Type == BinaryOperationType.LogicalOr) + if (currentConditionExpression is BinaryExpression orBex + && orBex.Type == BinaryOperationType.LogicalOr) + { + var stack = new Stack(); + stack.Push(orBex.Right); + stack.Push(orBex.Left); + + while (stack.Any()) { - var stack = new Stack(); - stack.Push(orBex.Right); - stack.Push(orBex.Left); + var node = stack.Pop(); - while (stack.Any()) + if (node is BinaryExpression innerBex && innerBex.Type == BinaryOperationType.LogicalOr) { - var node = stack.Pop(); - - if (node is BinaryExpression innerBex && innerBex.Type == BinaryOperationType.LogicalOr) - { - stack.Push(innerBex.Right); - stack.Push(innerBex.Left); - } - else - { - Visit(node); - Chunk.CodeGenerator.Emit( - OpCode.TJMP, - statementStart - ); - } + stack.Push(innerBex.Right); + stack.Push(innerBex.Left); + } + else + { + Visit(node); + Chunk.CodeGenerator.Emit( + OpCode.TJMP, + statementStart + ); } - - Chunk.CodeGenerator.Emit( - OpCode.JUMP, - caseEnd - ); - } - else - { - Visit(currentConditionExpression); - Chunk.CodeGenerator.Emit( - OpCode.FJMP, - caseEnd - ); } - - Chunk.UpdateLabel(statementStart, Chunk.CodeGenerator.IP); - - Visit(ifStatement.Statements[i]); + Chunk.CodeGenerator.Emit( OpCode.JUMP, - statementEnd + caseEnd ); - - Chunk.UpdateLabel(caseEnd, Chunk.CodeGenerator.IP); - } - - if (ifStatement.ElseBranch != null) - { - Visit(ifStatement.ElseBranch); } else { - Chunk.CodeGenerator.Emit(OpCode.NOOP); + Visit(currentConditionExpression); + Chunk.CodeGenerator.Emit( + OpCode.FJMP, + caseEnd + ); } - Chunk.UpdateLabel( - statementEnd, - Chunk.CodeGenerator.IP + Chunk.UpdateLabel(statementStart, Chunk.CodeGenerator.IP); + + Visit(ifStatement.Statements[i]); + Chunk.CodeGenerator.Emit( + OpCode.JUMP, + statementEnd ); + + Chunk.UpdateLabel(caseEnd, Chunk.CodeGenerator.IP); + } + + if (ifStatement.ElseBranch != null) + { + Visit(ifStatement.ElseBranch); } + else + { + Chunk.CodeGenerator.Emit(OpCode.NOOP); + } + + Chunk.UpdateLabel( + statementEnd, + Chunk.CodeGenerator.IP + ); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Ret.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Ret.cs index ee8172ec..91da11b4 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Ret.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Ret.cs @@ -1,28 +1,27 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Statements; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(RetStatement retStatement) { - public override void Visit(RetStatement retStatement) + if (retStatement.Expression != null) { - if (retStatement.Expression != null) - { - Visit(retStatement.Expression); + Visit(retStatement.Expression); - if (Chunk.CodeGenerator.TryPeekOpCode(out var opCode)) - { - if (opCode == OpCode.TAILINVOKE) - return; - } - } - else + if (Chunk.CodeGenerator.TryPeekOpCode(out var opCode)) { - Chunk.CodeGenerator.Emit(OpCode.LDNIL); + if (opCode == OpCode.TAILINVOKE) + return; } - - Chunk.CodeGenerator.Emit(OpCode.RET); } + else + { + Chunk.CodeGenerator.Emit(OpCode.LDNIL); + } + + Chunk.CodeGenerator.Emit(OpCode.RET); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Skip.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Skip.cs index 536cb1bd..410868e0 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Skip.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Skip.cs @@ -1,13 +1,12 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Statements; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(SkipStatement skipStatement) { - public override void Visit(SkipStatement skipStatement) - { - Chunk.CodeGenerator.Emit(OpCode.JUMP, Loop.StartLabel); - } + Chunk.CodeGenerator.Emit(OpCode.JUMP, Loop.StartLabel); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Throw.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Throw.cs index c6ceb2cd..021260ec 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Throw.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Throw.cs @@ -1,16 +1,15 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Statements; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(ThrowStatement throwStatement) { - public override void Visit(ThrowStatement throwStatement) - { - Chunk.MarkThrowing(); + Chunk.MarkThrowing(); - Visit(throwStatement.ThrownExpression); - Chunk.CodeGenerator.Emit(OpCode.THROW); - } + Visit(throwStatement.ThrownExpression); + Chunk.CodeGenerator.Emit(OpCode.THROW); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Try.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Try.cs index 7eb7131f..84736e1a 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Try.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Try.cs @@ -1,55 +1,54 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Statements; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(TryStatement tryStatement) { - public override void Visit(TryStatement tryStatement) - { - var statementEndLabel = Chunk.CreateLabel(); - var enterInsnLabel = Chunk.CreateLabel(); + var statementEndLabel = Chunk.CreateLabel(); + var enterInsnLabel = Chunk.CreateLabel(); - Chunk.CodeGenerator.Emit(OpCode.ENTER, Chunk.ProtectedBlocks.Count); + Chunk.CodeGenerator.Emit(OpCode.ENTER, Chunk.ProtectedBlocks.Count); - _blockProtectors.Push(Chunk.AllocateBlockProtector()); + _blockProtectors.Push(Chunk.AllocateBlockProtector()); + { + BlockProtector.EnterLabelId = enterInsnLabel; + BlockProtector.StartAddress = Chunk.CodeGenerator.IP; + Visit(tryStatement.InnerStatement); + BlockProtector.Length = Chunk.CodeGenerator.IP - BlockProtector.StartAddress; + Chunk.CodeGenerator.Emit(OpCode.LEAVE); + Chunk.CodeGenerator.Emit(OpCode.JUMP, statementEndLabel); + BlockProtector.HandlerAddress = Chunk.CodeGenerator.IP; + + InNewLocalScopeDo(() => { - BlockProtector.EnterLabelId = enterInsnLabel; - BlockProtector.StartAddress = Chunk.CodeGenerator.IP; - Visit(tryStatement.InnerStatement); - BlockProtector.Length = Chunk.CodeGenerator.IP - BlockProtector.StartAddress; Chunk.CodeGenerator.Emit(OpCode.LEAVE); - Chunk.CodeGenerator.Emit(OpCode.JUMP, statementEndLabel); - BlockProtector.HandlerAddress = Chunk.CodeGenerator.IP; - InNewLocalScopeDo(() => + if (tryStatement.HandlerExceptionLocal != null) { - Chunk.CodeGenerator.Emit(OpCode.LEAVE); + CurrentScope.DefineLocal( + tryStatement.HandlerExceptionLocal.Name, + Chunk.AllocateLocal(), + false, + tryStatement.HandlerExceptionLocal.Line, + tryStatement.HandlerExceptionLocal.Column + ); - if (tryStatement.HandlerExceptionLocal != null) - { - CurrentScope.DefineLocal( - tryStatement.HandlerExceptionLocal.Name, - Chunk.AllocateLocal(), - false, - tryStatement.HandlerExceptionLocal.Line, - tryStatement.HandlerExceptionLocal.Column - ); - - EmitVarSet(tryStatement.HandlerExceptionLocal.Name); - } - else - { - Chunk.CodeGenerator.Emit(OpCode.POP); - } + EmitVarSet(tryStatement.HandlerExceptionLocal.Name); + } + else + { + Chunk.CodeGenerator.Emit(OpCode.POP); + } - Visit(tryStatement.HandlerStatement); - }); - } - _blockProtectors.Pop(); - - Chunk.UpdateLabel(statementEndLabel, Chunk.CodeGenerator.IP); + Visit(tryStatement.HandlerStatement); + }); } + _blockProtectors.Pop(); + Chunk.UpdateLabel(statementEndLabel, Chunk.CodeGenerator.IP); } + } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Val.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Val.cs index cd1693bf..d4dd8703 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Val.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Val.cs @@ -1,54 +1,53 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.TranslationEngine.Diagnostics; using EVIL.Grammar.AST.Statements; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(ValStatement valStatement) { - public override void Visit(ValStatement valStatement) + foreach (var kvp in valStatement.Definitions) { - foreach (var kvp in valStatement.Definitions) - { - var localId = Chunk.AllocateLocal(); + var localId = Chunk.AllocateLocal(); - try - { - CurrentScope.DefineLocal( - kvp.Key.Name, - localId, - valStatement.ReadWrite, - valStatement.Line, - valStatement.Column - ); - } - catch (DuplicateSymbolException dse) - { - Log.TerminateWithFatal( - $"The symbol '{kvp.Key.Name}' already exists in this scope " + - $"and is a {dse.ExistingSymbol.TypeName} (previously defined on line {dse.Line}, column {dse.Column}).", - CurrentFileName, - EvilMessageCode.DuplicateSymbolInScope, - kvp.Key.Line, - kvp.Key.Column, - dse - ); + try + { + CurrentScope.DefineLocal( + kvp.Key.Name, + localId, + valStatement.ReadWrite, + valStatement.Line, + valStatement.Column + ); + } + catch (DuplicateSymbolException dse) + { + Log.TerminateWithFatal( + $"The symbol '{kvp.Key.Name}' already exists in this scope " + + $"and is a {dse.ExistingSymbol.TypeName} (previously defined on line {dse.Line}, column {dse.Column}).", + CurrentFileName, + EvilMessageCode.DuplicateSymbolInScope, + kvp.Key.Line, + kvp.Key.Column, + dse + ); - // Return just in case - TerminateWithFatal should never return, ever. - return; - } + // Return just in case - TerminateWithFatal should never return, ever. + return; + } - Chunk.DebugDatabase.SetLocalName(localId, kvp.Key.Name, valStatement.ReadWrite); + Chunk.DebugDatabase.SetLocalName(localId, kvp.Key.Name, valStatement.ReadWrite); - if (kvp.Value != null) - { - Visit(kvp.Value); + if (kvp.Value != null) + { + Visit(kvp.Value); - Chunk.CodeGenerator.Emit( - OpCode.SETLOCAL, - localId - ); - } + Chunk.CodeGenerator.Emit( + OpCode.SETLOCAL, + localId + ); } } } diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.While.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.While.cs index 8ac31d84..504eb32c 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.While.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.While.cs @@ -1,22 +1,21 @@ +namespace EVIL.Ceres.TranslationEngine; + using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Grammar.AST.Statements; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - public partial class Compiler + public override void Visit(WhileStatement whileStatement) { - public override void Visit(WhileStatement whileStatement) + InNewLoopDo(Loop.LoopKind.While, () => { - InNewLoopDo(Loop.LoopKind.While, () => - { - Visit(whileStatement.Condition); - Chunk.CodeGenerator.Emit(OpCode.FJMP, Loop.EndLabel); + Visit(whileStatement.Condition); + Chunk.CodeGenerator.Emit(OpCode.FJMP, Loop.EndLabel); - Visit(whileStatement.Statement); - Chunk.CodeGenerator.Emit(OpCode.JUMP, Loop.StartLabel); + Visit(whileStatement.Statement); + Chunk.CodeGenerator.Emit(OpCode.JUMP, Loop.StartLabel); - Chunk.UpdateLabel(Loop.EndLabel, Chunk.CodeGenerator.IP); - }, false); - } + Chunk.UpdateLabel(Loop.EndLabel, Chunk.CodeGenerator.IP); + }, false); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Utilities.Emit.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Utilities.Emit.cs index a349c5fe..94bf171a 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Utilities.Emit.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Utilities.Emit.cs @@ -1,231 +1,228 @@ -using EVIL.Ceres.ExecutionEngine.Diagnostics; +namespace EVIL.Ceres.TranslationEngine; + +using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.TranslationEngine.Diagnostics; using EVIL.Ceres.TranslationEngine.Scoping; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler { - using Scope = Scoping.Scope; - - public partial class Compiler + private void FinalizeChunk() { - private void FinalizeChunk() + if (Chunk.CodeGenerator.TryPeekOpCode(out var opCode)) { - if (Chunk.CodeGenerator.TryPeekOpCode(out var opCode)) + if (opCode == OpCode.RET || opCode == OpCode.TAILINVOKE) { - if (opCode == OpCode.RET || opCode == OpCode.TAILINVOKE) - { - return; - } + return; } - - /* Either we have no instructions in chunk, or it's not a RET. */ - Chunk.CodeGenerator.Emit(OpCode.LDNIL); - Chunk.CodeGenerator.Emit(OpCode.RET); } + + /* Either we have no instructions in chunk, or it's not a RET. */ + Chunk.CodeGenerator.Emit(OpCode.LDNIL); + Chunk.CodeGenerator.Emit(OpCode.RET); + } - private void EmitVarSet(string identifier) + private void EmitVarSet(string identifier) + { + var symbolInfo = FindSymbolInClosedScopes(identifier); + + if (symbolInfo != null) { - var symbolInfo = FindSymbolInClosedScopes(identifier); + var ownerScope = symbolInfo.Value.OwnerScope; + var level = symbolInfo.Value.ClosedScopeLevel; + var sym = symbolInfo.Value.Symbol; - if (symbolInfo != null) + if (level == 0) { - var ownerScope = symbolInfo.Value.OwnerScope; - var level = symbolInfo.Value.ClosedScopeLevel; - var sym = symbolInfo.Value.Symbol; - - if (level == 0) + switch (sym.Type) { - switch (sym.Type) + case Symbol.SymbolType.Local: { - case Symbol.SymbolType.Local: - { - Chunk.CodeGenerator.Emit( - OpCode.SETLOCAL, - sym.Id - ); - break; - } - - case Symbol.SymbolType.Parameter: - { - Chunk.CodeGenerator.Emit( - OpCode.SETARG, - sym.Id - ); - break; - } - - case Symbol.SymbolType.Closure: - { - Chunk.CodeGenerator.Emit( - OpCode.SETCLOSURE, - sym.Id - ); - break; - } + Chunk.CodeGenerator.Emit( + OpCode.SETLOCAL, + sym.Id + ); + break; } - } - else - { - var result = Chunk.AllocateClosure( - level, - sym.Id, - ownerScope.Chunk.Name, - sym.Type == Symbol.SymbolType.Parameter, - sym.Type == Symbol.SymbolType.Closure, - ReferenceEquals(ownerScope.Chunk, _rootChunk) - ); - try + case Symbol.SymbolType.Parameter: { - CurrentScope.DefineClosure( - sym.Name, - result.Id, - sym.ReadWrite, - sym.DefinedOnLine, - sym.DefinedOnColumn, - result.Closure + Chunk.CodeGenerator.Emit( + OpCode.SETARG, + sym.Id ); + break; } - catch (DuplicateSymbolException dse) + + case Symbol.SymbolType.Closure: { - Log.TerminateWithFatal( - $"The symbol '{sym.Name}' already exists in this scope " + - $"and is a {dse.ExistingSymbol.TypeName} (previously defined on line {dse.Line}, column {dse.Column}).", - CurrentFileName, - EvilMessageCode.DuplicateSymbolInScope, - sym.DefinedOnLine, - sym.DefinedOnColumn, - dse + Chunk.CodeGenerator.Emit( + OpCode.SETCLOSURE, + sym.Id ); + break; } - - Chunk.CodeGenerator.Emit( - OpCode.SETCLOSURE, - result.Id - ); } } else { - Chunk.CodeGenerator.Emit( - OpCode.LDSTR, - (int)Chunk.StringPool.FetchOrAdd(identifier) + var result = Chunk.AllocateClosure( + level, + sym.Id, + ownerScope.Chunk.Name, + sym.Type == Symbol.SymbolType.Parameter, + sym.Type == Symbol.SymbolType.Closure, + ReferenceEquals(ownerScope.Chunk, _rootChunk) ); - Chunk.CodeGenerator.Emit(OpCode.SETGLOBAL); + try + { + CurrentScope.DefineClosure( + sym.Name, + result.Id, + sym.ReadWrite, + sym.DefinedOnLine, + sym.DefinedOnColumn, + result.Closure + ); + } + catch (DuplicateSymbolException dse) + { + Log.TerminateWithFatal( + $"The symbol '{sym.Name}' already exists in this scope " + + $"and is a {dse.ExistingSymbol.TypeName} (previously defined on line {dse.Line}, column {dse.Column}).", + CurrentFileName, + EvilMessageCode.DuplicateSymbolInScope, + sym.DefinedOnLine, + sym.DefinedOnColumn, + dse + ); + } + + Chunk.CodeGenerator.Emit( + OpCode.SETCLOSURE, + result.Id + ); } } + else + { + Chunk.CodeGenerator.Emit( + OpCode.LDSTR, + (int)Chunk.StringPool.FetchOrAdd(identifier) + ); + + Chunk.CodeGenerator.Emit(OpCode.SETGLOBAL); + } + } - private void EmitVarGet(string identifier) + private void EmitVarGet(string identifier) + { + var symbolInfo = FindSymbolInClosedScopes(identifier); + + if (symbolInfo != null) { - var symbolInfo = FindSymbolInClosedScopes(identifier); + var ownerScope = symbolInfo.Value.OwnerScope; + var level = symbolInfo.Value.ClosedScopeLevel; + var sym = symbolInfo.Value.Symbol; - if (symbolInfo != null) + if (level == 0) { - var ownerScope = symbolInfo.Value.OwnerScope; - var level = symbolInfo.Value.ClosedScopeLevel; - var sym = symbolInfo.Value.Symbol; - - if (level == 0) + switch (sym.Type) { - switch (sym.Type) + case Symbol.SymbolType.Local: { - case Symbol.SymbolType.Local: - { - Chunk.CodeGenerator.Emit( - OpCode.GETLOCAL, - sym.Id - ); - break; - } - - case Symbol.SymbolType.Parameter: - { - Chunk.CodeGenerator.Emit( - OpCode.GETARG, - sym.Id - ); - break; - } - - case Symbol.SymbolType.Closure: - { - Chunk.CodeGenerator.Emit( - OpCode.GETCLOSURE, - sym.Id - ); - - break; - } + Chunk.CodeGenerator.Emit( + OpCode.GETLOCAL, + sym.Id + ); + break; } - } - else - { - var result = Chunk.AllocateClosure( - level, - sym.Id, - ownerScope.Chunk.Name, - sym.Type == Symbol.SymbolType.Parameter, - sym.Type == Symbol.SymbolType.Closure, - ReferenceEquals(ownerScope.Chunk, _rootChunk) - ); - try + case Symbol.SymbolType.Parameter: { - CurrentScope.DefineClosure( - sym.Name, - result.Id, - sym.ReadWrite, - sym.DefinedOnLine, - sym.DefinedOnColumn, - result.Closure + Chunk.CodeGenerator.Emit( + OpCode.GETARG, + sym.Id ); + break; } - catch (DuplicateSymbolException dse) + + case Symbol.SymbolType.Closure: { - Log.TerminateWithFatal( - $"The symbol '{sym.Name}' already exists in this scope " + - $"and is a {dse.ExistingSymbol.TypeName} (previously defined on line {dse.Line}, column {dse.Column}).", - CurrentFileName, - EvilMessageCode.DuplicateSymbolInScope, - sym.DefinedOnLine, - sym.DefinedOnColumn, - dse + Chunk.CodeGenerator.Emit( + OpCode.GETCLOSURE, + sym.Id ); - } - Chunk.CodeGenerator.Emit( - OpCode.GETCLOSURE, - result.Id - ); + break; + } } } else { - Chunk.CodeGenerator.Emit( - OpCode.LDSTR, - (int)Chunk.StringPool.FetchOrAdd(identifier) + var result = Chunk.AllocateClosure( + level, + sym.Id, + ownerScope.Chunk.Name, + sym.Type == Symbol.SymbolType.Parameter, + sym.Type == Symbol.SymbolType.Closure, + ReferenceEquals(ownerScope.Chunk, _rootChunk) ); - Chunk.CodeGenerator.Emit(OpCode.GETGLOBAL); + try + { + CurrentScope.DefineClosure( + sym.Name, + result.Id, + sym.ReadWrite, + sym.DefinedOnLine, + sym.DefinedOnColumn, + result.Closure + ); + } + catch (DuplicateSymbolException dse) + { + Log.TerminateWithFatal( + $"The symbol '{sym.Name}' already exists in this scope " + + $"and is a {dse.ExistingSymbol.TypeName} (previously defined on line {dse.Line}, column {dse.Column}).", + CurrentFileName, + EvilMessageCode.DuplicateSymbolInScope, + sym.DefinedOnLine, + sym.DefinedOnColumn, + dse + ); + } + + Chunk.CodeGenerator.Emit( + OpCode.GETCLOSURE, + result.Id + ); } } + else + { + Chunk.CodeGenerator.Emit( + OpCode.LDSTR, + (int)Chunk.StringPool.FetchOrAdd(identifier) + ); + + Chunk.CodeGenerator.Emit(OpCode.GETGLOBAL); + } + } - private (int ClosedScopeLevel, Scoping.Symbol Symbol, Scope OwnerScope)? FindSymbolInClosedScopes(string identifier) + private (int ClosedScopeLevel, Scoping.Symbol Symbol, Scope OwnerScope)? FindSymbolInClosedScopes(string identifier) + { + for (var i = 0; i < _closedScopes.Count; i++) { - for (var i = 0; i < _closedScopes.Count; i++) - { - var scope = _closedScopes[i]; - var result = scope.Find(identifier); + var scope = _closedScopes[i]; + var result = scope.Find(identifier); - if (result != null) - { - return (i, result.Value.Symbol, scope); - } + if (result != null) + { + return (i, result.Value.Symbol, scope); } - - return null; } + + return null; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Utlities.Safeguards.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Utlities.Safeguards.cs index c83b95b4..63cfd062 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Utlities.Safeguards.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Utlities.Safeguards.cs @@ -1,24 +1,23 @@ -using EVIL.Ceres.TranslationEngine.Diagnostics; +namespace EVIL.Ceres.TranslationEngine; -namespace EVIL.Ceres.TranslationEngine +using EVIL.Ceres.TranslationEngine.Diagnostics; + +public partial class Compiler { - public partial class Compiler + private void ThrowIfVarReadOnly(string identifier) { - private void ThrowIfVarReadOnly(string identifier) + if (!CurrentScope.IsSymbolWriteable(identifier, out var result)) { - if (!CurrentScope.IsSymbolWriteable(identifier, out var result)) - { - var sym = result!.Value.Symbol; + var sym = result!.Value.Symbol; - Log.TerminateWithFatal( - $"Attempt to set a value of a read-only {sym.Type.ToString().ToLower()} `{sym.Name}' " + - $"(defined on line {sym.DefinedOnLine})", - CurrentFileName, - EvilMessageCode.AttemptToWriteReadOnlyLocal, - Line, - Column - ); - } + Log.TerminateWithFatal( + $"Attempt to set a value of a read-only {sym.Type.ToString().ToLower()} `{sym.Name}' " + + $"(defined on line {sym.DefinedOnLine})", + CurrentFileName, + EvilMessageCode.AttemptToWriteReadOnlyLocal, + Line, + Column + ); } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.cs index e7126951..d0783b7e 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.cs @@ -1,3 +1,5 @@ +namespace EVIL.Ceres.TranslationEngine; + using System; using System.Collections.Generic; using System.Linq; @@ -15,253 +17,250 @@ using EVIL.Grammar.Traversal; using EVIL.Lexical; -namespace EVIL.Ceres.TranslationEngine +public partial class Compiler : AstVisitor { - public partial class Compiler : AstVisitor - { - private Chunk _rootChunk = null!; + private Chunk _rootChunk = null!; - private readonly Stack _chunks = new(); - private Dictionary> _attributeProcessors = new(); + private readonly Stack _chunks = new(); + private Dictionary> _attributeProcessors = new(); - private readonly Stack _blockProtectors = new(); - private readonly Stack _loopDescent = new(); - private readonly List _closedScopes = new(); + private readonly Stack _blockProtectors = new(); + private readonly Stack _loopDescent = new(); + private readonly List _closedScopes = new(); - private Scope CurrentScope + private Scope CurrentScope + { + get { - get + if (!_closedScopes.Any()) { - if (!_closedScopes.Any()) - { - throw new InvalidOperationException("Internal error: no scopes defined."); - } - - return _closedScopes[0]; + throw new InvalidOperationException("Internal error: no scopes defined."); } - set - { - if (!_closedScopes.Any()) - { - throw new InvalidOperationException("Internal error: no scopes defined"); - } + return _closedScopes[0]; + } - _closedScopes[0] = value; + set + { + if (!_closedScopes.Any()) + { + throw new InvalidOperationException("Internal error: no scopes defined"); } + + _closedScopes[0] = value; } + } - private Chunk Chunk => _chunks.Peek(); - private Loop Loop => _loopDescent.Peek(); - private BlockProtectionInfo BlockProtector => _blockProtectors.Peek(); + private Chunk Chunk => _chunks.Peek(); + private Loop Loop => _loopDescent.Peek(); + private BlockProtectionInfo BlockProtector => _blockProtectors.Peek(); - private int Line { get; set; } - private int Column { get; set; } + private int Line { get; set; } + private int Column { get; set; } - public string CurrentFileName { get; private set; } = string.Empty; + public string CurrentFileName { get; private set; } = string.Empty; - public CompilerLog Log { get; } = new(); - public bool OptimizeCodeGeneration { get; set; } + public CompilerLog Log { get; } = new(); + public bool OptimizeCodeGeneration { get; set; } - public Compiler(bool optimizeCodeGeneration = false) - { - OptimizeCodeGeneration = optimizeCodeGeneration; - } - - public Chunk Compile(string source, string fileName = "") - { - CurrentFileName = fileName; - var parser = new Parser(); + public Compiler(bool optimizeCodeGeneration = false) + { + OptimizeCodeGeneration = optimizeCodeGeneration; + } - try - { - var program = parser.Parse(source); - return Compile(program, fileName); - } - catch (LexerException le) - { - Log.TerminateWithFatal( - le.Message, - CurrentFileName, - EvilMessageCode.LexerError, - line: le.Line, - column: le.Column, - innerException: le - ); - } - catch (ParserException pe) - { - Log.TerminateWithFatal( - pe.Message, - CurrentFileName, - EvilMessageCode.ParserError, - line: pe.Line, - column: pe.Column, - innerException: pe - ); - } + public Chunk Compile(string source, string fileName = "") + { + CurrentFileName = fileName; + var parser = new Parser(); - // Dummy return to keep compiler happy. - return null!; + try + { + var program = parser.Parse(source); + return Compile(program, fileName); } - - public Chunk Compile(ProgramNode programNode, string fileName = "") + catch (LexerException le) { - CurrentFileName = fileName; - _closedScopes.Clear(); - _chunks.Clear(); - - return InRootChunkDo(() => Visit(programNode)); + Log.TerminateWithFatal( + le.Message, + CurrentFileName, + EvilMessageCode.LexerError, + line: le.Line, + column: le.Column, + innerException: le + ); } - - private void OnChunkOpCodeEmitted(int ip, OpCode opCode) + catch (ParserException pe) { - Chunk.DebugDatabase.AddDebugRecord(Line, ip); + Log.TerminateWithFatal( + pe.Message, + CurrentFileName, + EvilMessageCode.ParserError, + line: pe.Line, + column: pe.Column, + innerException: pe + ); } - private Chunk InRootChunkDo(Action action) - { - var fileNameBytes = Encoding.UTF8 - .GetBytes(CurrentFileName + Random.Shared.Next()); - - var hash = SHA1.HashData(fileNameBytes); - var chunkName = "!_root_chunk"; - var sb = new StringBuilder(); - for (var i = 0; i < hash.Length; i++) - { - sb.Append(hash[i].ToString("X2")); - } - chunkName += "!" + sb; + // Dummy return to keep compiler happy. + return null!; + } - _rootChunk = new Chunk(chunkName); - _rootChunk.DebugDatabase.DefinedInFile = CurrentFileName; - _rootChunk.CodeGenerator.OpCodeEmitted = OnChunkOpCodeEmitted; + public Chunk Compile(ProgramNode programNode, string fileName = "") + { + CurrentFileName = fileName; + _closedScopes.Clear(); + _chunks.Clear(); - _chunks.Push(_rootChunk); - { - InNewClosedScopeDo(action); - FinalizeChunk(); - } - - return _chunks.Pop(); + return InRootChunkDo(() => Visit(programNode)); + } + + private void OnChunkOpCodeEmitted(int ip, OpCode opCode) + { + Chunk.DebugDatabase.AddDebugRecord(Line, ip); + } + + private Chunk InRootChunkDo(Action action) + { + var fileNameBytes = Encoding.UTF8 + .GetBytes(CurrentFileName + Random.Shared.Next()); + + var hash = SHA1.HashData(fileNameBytes); + var chunkName = "!_root_chunk"; + var sb = new StringBuilder(); + for (var i = 0; i < hash.Length; i++) + { + sb.Append(hash[i].ToString("X2")); } + chunkName += "!" + sb; + + _rootChunk = new Chunk(chunkName); + _rootChunk.DebugDatabase.DefinedInFile = CurrentFileName; + _rootChunk.CodeGenerator.OpCodeEmitted = OnChunkOpCodeEmitted; - private void InNewLocalScopeDo(Action action) + _chunks.Push(_rootChunk); { - CurrentScope = CurrentScope.Descend(); - { - action(); - } - CurrentScope = CurrentScope.Parent!; + InNewClosedScopeDo(action); + FinalizeChunk(); } + + return _chunks.Pop(); + } - private void InNewClosedScopeDo(Action action) + private void InNewLocalScopeDo(Action action) + { + CurrentScope = CurrentScope.Descend(); { - _closedScopes.Insert(0, Scope.CreateRoot(Chunk)); - { - action(); - } - _closedScopes.RemoveAt(0); + action(); } + CurrentScope = CurrentScope.Parent!; + } - private int InAnonymousSubChunkDo(Action action) + private void InNewClosedScopeDo(Action action) + { + _closedScopes.Insert(0, Scope.CreateRoot(Chunk)); { - var result = Chunk.AllocateAnonymousSubChunk(); - result.SubChunk.DebugDatabase.DefinedInFile = CurrentFileName; - result.SubChunk.CodeGenerator.OpCodeEmitted = OnChunkOpCodeEmitted; + action(); + } + _closedScopes.RemoveAt(0); + } - _chunks.Push(result.SubChunk); - { - action(); - } - _chunks.Pop(); + private int InAnonymousSubChunkDo(Action action) + { + var result = Chunk.AllocateAnonymousSubChunk(); + result.SubChunk.DebugDatabase.DefinedInFile = CurrentFileName; + result.SubChunk.CodeGenerator.OpCodeEmitted = OnChunkOpCodeEmitted; - return result.Id; + _chunks.Push(result.SubChunk); + { + action(); } + _chunks.Pop(); - private int InNamedSubChunkDo(string name, Action action, out bool wasReplaced, out Chunk replacedChunk) - { - var result = Chunk.AllocateNamedSubChunk(name, out wasReplaced, out replacedChunk); - result.SubChunk.DebugDatabase.DefinedInFile = CurrentFileName; - result.SubChunk.CodeGenerator.OpCodeEmitted = OnChunkOpCodeEmitted; + return result.Id; + } - _chunks.Push(result.SubChunk); - { - action(); - } - _chunks.Pop(); + private int InNamedSubChunkDo(string name, Action action, out bool wasReplaced, out Chunk replacedChunk) + { + var result = Chunk.AllocateNamedSubChunk(name, out wasReplaced, out replacedChunk); + result.SubChunk.DebugDatabase.DefinedInFile = CurrentFileName; + result.SubChunk.CodeGenerator.OpCodeEmitted = OnChunkOpCodeEmitted; - return result.Id; + _chunks.Push(result.SubChunk); + { + action(); } + _chunks.Pop(); + + return result.Id; + } - private void InNewLoopDo(Loop.LoopKind kind, Action action, bool needsExtraLabel) + private void InNewLoopDo(Loop.LoopKind kind, Action action, bool needsExtraLabel) + { + _loopDescent.Push(new Loop(Chunk, kind, needsExtraLabel)); { - _loopDescent.Push(new Loop(Chunk, kind, needsExtraLabel)); - { - action(); - } - _loopDescent.Pop(); + action(); } + _loopDescent.Pop(); + } - public override void Visit(AstNode node) + public override void Visit(AstNode node) + { + Line = node.Line; + Column = node.Column; + + if (node is Expression expression && OptimizeCodeGeneration) { - Line = node.Line; - Column = node.Column; + node = expression.Reduce(); + } - if (node is Expression expression && OptimizeCodeGeneration) - { - node = expression.Reduce(); - } + base.Visit(node); + } - base.Visit(node); + public void RegisterAttributeProcessor(string attributeName, AttributeProcessor processor) + { + if (!_attributeProcessors.TryGetValue(attributeName, out var list)) + { + list = new List(); + _attributeProcessors.Add(attributeName, list); } - public void RegisterAttributeProcessor(string attributeName, AttributeProcessor processor) - { - if (!_attributeProcessors.TryGetValue(attributeName, out var list)) - { - list = new List(); - _attributeProcessors.Add(attributeName, list); - } + list.Add(processor); + } - list.Add(processor); + private DynamicValue ExtractConstantValueFrom(AstNode valueNode) + { + if (valueNode is BooleanConstant boolConst) + { + return boolConst.Value; } - - private DynamicValue ExtractConstantValueFrom(AstNode valueNode) + else if (valueNode is NilConstant) { - if (valueNode is BooleanConstant boolConst) - { - return boolConst.Value; - } - else if (valueNode is NilConstant) - { - return DynamicValue.Nil; - } - else if (valueNode is NumberConstant numConst) - { - return numConst.Value; - } - else if (valueNode is StringConstant stringConst) - { - return stringConst.Value; - } - else if (valueNode is TypeCodeConstant typeCodeConst) - { - return typeCodeConst.Value; - } - else - { - Log.TerminateWithInternalFailure( - $"Unexpected constant value node type '{valueNode.GetType().FullName}'.", - CurrentFileName, - line: valueNode.Line, - column: valueNode.Column, - dummyReturn: DynamicValue.Zero - ); - - // Dummy return to keep compiler happy. - return DynamicValue.Zero; - } + return DynamicValue.Nil; + } + else if (valueNode is NumberConstant numConst) + { + return numConst.Value; + } + else if (valueNode is StringConstant stringConst) + { + return stringConst.Value; + } + else if (valueNode is TypeCodeConstant typeCodeConst) + { + return typeCodeConst.Value; + } + else + { + Log.TerminateWithInternalFailure( + $"Unexpected constant value node type '{valueNode.GetType().FullName}'.", + CurrentFileName, + line: valueNode.Line, + column: valueNode.Column, + dummyReturn: DynamicValue.Zero + ); + + // Dummy return to keep compiler happy. + return DynamicValue.Zero; } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/CompilerException.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/CompilerException.cs index 23936656..29b736b5 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/CompilerException.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/CompilerException.cs @@ -1,22 +1,21 @@ +namespace EVIL.Ceres.TranslationEngine; + using System; using EVIL.Ceres.TranslationEngine.Diagnostics; -namespace EVIL.Ceres.TranslationEngine +public class CompilerException : Exception { - public class CompilerException : Exception - { - public CompilerLog Log { get; } + public CompilerLog Log { get; } - public CompilerException(CompilerLog log) - : base("A fatal compiler compiler error occurred.") - { - Log = log; - } + public CompilerException(CompilerLog log) + : base("A fatal compiler compiler error occurred.") + { + Log = log; + } - public CompilerException(CompilerLog log, Exception? innerException) - : base("A fatal compiler compiler error occurred.", innerException) - { - Log = log; - } + public CompilerException(CompilerLog log, Exception? innerException) + : base("A fatal compiler compiler error occurred.", innerException) + { + Log = log; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Diagnostics/CompilerLog.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Diagnostics/CompilerLog.cs index 3a15e105..2322ca62 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Diagnostics/CompilerLog.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Diagnostics/CompilerLog.cs @@ -1,4 +1,8 @@ -using System; +namespace EVIL.Ceres.TranslationEngine.Diagnostics; + +using Array = EVIL.Ceres.ExecutionEngine.Collections.Array; + +using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -6,171 +10,167 @@ using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.Marshaling; using EVIL.Ceres.ExecutionEngine.TypeSystem; -using Array = EVIL.Ceres.ExecutionEngine.Collections.Array; -using EvilArray = EVIL.Ceres.ExecutionEngine.Collections.Array; -namespace EVIL.Ceres.TranslationEngine.Diagnostics +public sealed class CompilerLog : IDynamicValueProvider { - public sealed class CompilerLog : IDynamicValueProvider - { - private readonly List _messages = new(); + private readonly List _messages = new(); - public CompilerMessageSeverity MinimumSeverityLevel { get; set; } = CompilerMessageSeverity.Warning; + public CompilerMessageSeverity MinimumSeverityLevel { get; set; } = CompilerMessageSeverity.Warning; - public IReadOnlyList Messages => _messages; + public IReadOnlyList Messages => _messages; - public event EventHandler? MessageEmitted; + public event EventHandler? MessageEmitted; - public int VerboseCount => _messages.Count(x => x.Severity == CompilerMessageSeverity.Verbose); - public int WarningCount => _messages.Count(x => x.Severity == CompilerMessageSeverity.Warning); + public int VerboseCount => _messages.Count(x => x.Severity == CompilerMessageSeverity.Verbose); + public int WarningCount => _messages.Count(x => x.Severity == CompilerMessageSeverity.Warning); - public bool HasAnyMessages => VerboseCount > 0 || WarningCount > 0; + public bool HasAnyMessages => VerboseCount > 0 || WarningCount > 0; - public void Clear() - => _messages.Clear(); - - public void EmitVerbose( - string message, - string? fileName = null, - int messageCode = 0, - int line = 0, - int column = 0) - { - if (MinimumSeverityLevel > CompilerMessageSeverity.Verbose) - return; + public void Clear() + => _messages.Clear(); + + public void EmitVerbose( + string message, + string? fileName = null, + int messageCode = 0, + int line = 0, + int column = 0) + { + if (MinimumSeverityLevel > CompilerMessageSeverity.Verbose) + return; - var messageObject = new CompilerMessage( - CompilerMessageSeverity.Verbose, - message, - fileName, - messageCode, - line, - column - ); - - _messages.Add(messageObject); - MessageEmitted?.Invoke(this, new(messageObject)); - } + var messageObject = new CompilerMessage( + CompilerMessageSeverity.Verbose, + message, + fileName, + messageCode, + line, + column + ); + + _messages.Add(messageObject); + MessageEmitted?.Invoke(this, new(messageObject)); + } - public void EmitWarning( - string message, - string? fileName = null, - int messageCode = 0, - int line = 0, - int column = 0) - { - if (MinimumSeverityLevel > CompilerMessageSeverity.Warning) - return; + public void EmitWarning( + string message, + string? fileName = null, + int messageCode = 0, + int line = 0, + int column = 0) + { + if (MinimumSeverityLevel > CompilerMessageSeverity.Warning) + return; - var messageObject = new CompilerMessage( - CompilerMessageSeverity.Warning, - message, - fileName, - messageCode, - line, - column - ); + var messageObject = new CompilerMessage( + CompilerMessageSeverity.Warning, + message, + fileName, + messageCode, + line, + column + ); - _messages.Add(messageObject); - MessageEmitted?.Invoke(this, new(messageObject)); - } + _messages.Add(messageObject); + MessageEmitted?.Invoke(this, new(messageObject)); + } - [DoesNotReturn] - public void TerminateWithFatal( - string message, - string? fileName = null, - int messageCode = 0, - int line = 0, - int column = 0, - Exception? innerException = null) - { - var messageObject = new CompilerMessage( - CompilerMessageSeverity.Fatal, - message, - fileName, - messageCode, - line, - column - ); + [DoesNotReturn] + public void TerminateWithFatal( + string message, + string? fileName = null, + int messageCode = 0, + int line = 0, + int column = 0, + Exception? innerException = null) + { + var messageObject = new CompilerMessage( + CompilerMessageSeverity.Fatal, + message, + fileName, + messageCode, + line, + column + ); - _messages.Add(messageObject); - MessageEmitted?.Invoke(this, new(messageObject)); + _messages.Add(messageObject); + MessageEmitted?.Invoke(this, new(messageObject)); - throw new CompilerException(this, innerException); - } + throw new CompilerException(this, innerException); + } - [DoesNotReturn] - public T TerminateWithInternalFailure( - string message, - string? fileName = null, - int messageCode = 0, - int line = 0, - int column = 0, - Exception? innerException = null, - T dummyReturn = default!) - { - var messageObject = new CompilerMessage( - CompilerMessageSeverity.InternalFailure, - message, - fileName, - messageCode, - line, - column - ); + [DoesNotReturn] + public T TerminateWithInternalFailure( + string message, + string? fileName = null, + int messageCode = 0, + int line = 0, + int column = 0, + Exception? innerException = null, + T dummyReturn = default!) + { + var messageObject = new CompilerMessage( + CompilerMessageSeverity.InternalFailure, + message, + fileName, + messageCode, + line, + column + ); - _messages.Add(messageObject); - MessageEmitted?.Invoke(this, new(messageObject)); + _messages.Add(messageObject); + MessageEmitted?.Invoke(this, new(messageObject)); - throw new CompilerException(this, innerException); + throw new CompilerException(this, innerException); - #pragma warning disable CS0162 - /* Keeps compiler happy! */ - return dummyReturn; - #pragma warning restore CS0162 - } + #pragma warning disable CS0162 + // ReSharper disable once HeuristicUnreachableCode + /* Keeps compiler happy! */ + return dummyReturn; + #pragma warning restore CS0162 + } - public string ToString(Func? lineProcessor) - { - var sb = new StringBuilder(); + public string ToString(Func? lineProcessor) + { + var sb = new StringBuilder(); - foreach (var message in _messages) + foreach (var message in _messages) + { + if (lineProcessor != null) { - if (lineProcessor != null) - { - sb.AppendLine(lineProcessor(message.ToString())); - } - else - { - sb.AppendLine($"{message.ToString()}"); - } + sb.AppendLine(lineProcessor(message.ToString())); + } + else + { + sb.AppendLine($"{message.ToString()}"); } - - return sb.ToString(); } - public override string ToString() - => ToString(null); + return sb.ToString(); + } + + public override string ToString() + => ToString(null); + + public DynamicValue ToDynamicValue() + { + var ret = new Array(Messages.Count); - public DynamicValue ToDynamicValue() + for (var i = 0; i < Messages.Count; i++) { - var ret = new Array(Messages.Count); + var msg = Messages[i]; - for (var i = 0; i < Messages.Count; i++) + ret[i] = new Table { - var msg = Messages[i]; - - ret[i] = new Table - { - { "severity", (int)msg.Severity }, - { "message", msg.Message }, - { "file_name", msg.FileName ?? DynamicValue.Nil }, - { "message_code", msg.MessageCode }, - { "line", msg.Line }, - { "column", msg.Column } - }; - } - - return ret; + { "severity", (int)msg.Severity }, + { "message", msg.Message }, + { "file_name", msg.FileName ?? DynamicValue.Nil }, + { "message_code", msg.MessageCode }, + { "line", msg.Line }, + { "column", msg.Column } + }; } + + return ret; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Diagnostics/CompilerMessage.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Diagnostics/CompilerMessage.cs index 5683a333..795aaab2 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Diagnostics/CompilerMessage.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Diagnostics/CompilerMessage.cs @@ -1,43 +1,42 @@ -using System.Text; +namespace EVIL.Ceres.TranslationEngine.Diagnostics; -namespace EVIL.Ceres.TranslationEngine.Diagnostics +using System.Text; + +public sealed record CompilerMessage( + CompilerMessageSeverity Severity, + string Message, + string? FileName = null, + int MessageCode = 0, + int Line = 0, + int Column = 0 +) { - public sealed record CompilerMessage( - CompilerMessageSeverity Severity, - string Message, - string? FileName = null, - int MessageCode = 0, - int Line = 0, - int Column = 0 - ) + public override string ToString() { - public override string ToString() - { - var sb = new StringBuilder(); + var sb = new StringBuilder(); - if (MessageCode > 0) - { - sb.Append($"EV{MessageCode:D4}"); - } + if (MessageCode > 0) + { + sb.Append($"EV{MessageCode:D4}"); + } - sb.Append($" :: {Severity}"); - if (Line > 0) - { - sb.Append($" :: line {Line}"); + sb.Append($" :: {Severity}"); + if (Line > 0) + { + sb.Append($" :: line {Line}"); - if (Column > 0) - { - sb.Append($", column {Column}"); - } - } - - if (!string.IsNullOrEmpty(FileName)) + if (Column > 0) { - sb.Append($" :: {FileName}"); + sb.Append($", column {Column}"); } + } - sb.Append($" :: {Message}"); - return sb.ToString(); + if (!string.IsNullOrEmpty(FileName)) + { + sb.Append($" :: {FileName}"); } + + sb.Append($" :: {Message}"); + return sb.ToString(); } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Diagnostics/CompilerMessageEmitEventArgs.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Diagnostics/CompilerMessageEmitEventArgs.cs index 0c2c9f0a..1f28e6ce 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Diagnostics/CompilerMessageEmitEventArgs.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Diagnostics/CompilerMessageEmitEventArgs.cs @@ -1,14 +1,13 @@ -using System; +namespace EVIL.Ceres.TranslationEngine.Diagnostics; -namespace EVIL.Ceres.TranslationEngine.Diagnostics +using System; + +public sealed class CompilerMessageEmitEventArgs : EventArgs { - public sealed class CompilerMessageEmitEventArgs : EventArgs - { - public CompilerMessage Message { get; } + public CompilerMessage Message { get; } - public CompilerMessageEmitEventArgs(CompilerMessage message) - { - Message = message; - } + public CompilerMessageEmitEventArgs(CompilerMessage message) + { + Message = message; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Diagnostics/CompilerMessageSeverity.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Diagnostics/CompilerMessageSeverity.cs index f9278143..3fe4e364 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Diagnostics/CompilerMessageSeverity.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Diagnostics/CompilerMessageSeverity.cs @@ -1,10 +1,9 @@ -namespace EVIL.Ceres.TranslationEngine.Diagnostics +namespace EVIL.Ceres.TranslationEngine.Diagnostics; + +public enum CompilerMessageSeverity { - public enum CompilerMessageSeverity - { - Verbose, - Warning, - Fatal, - InternalFailure - } + Verbose, + Warning, + Fatal, + InternalFailure } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Diagnostics/EvilMessageCode.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Diagnostics/EvilMessageCode.cs index 7eb43875..48227392 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Diagnostics/EvilMessageCode.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Diagnostics/EvilMessageCode.cs @@ -1,25 +1,24 @@ -namespace EVIL.Ceres.TranslationEngine.Diagnostics +namespace EVIL.Ceres.TranslationEngine.Diagnostics; + +public static class EvilMessageCode { - public static class EvilMessageCode - { - public const int DuplicateSymbolInScope = 0001; - public const int AttemptToWriteReadOnlyLocal = 0002; - public const int IllegalIncrementationTarget = 0003; - public const int IllegalDecrementationTarget = 0004; - public const int IllegalAssignmentTarget = 0005; - public const int LexerError = 0006; - public const int ParserError = 0007; - public const int IncludeFoundButNoIncludeProcessorsPresent = 0008; - public const int IncludedFileRedefinedExistingChunk = 0009; - public const int IncludeProcessorThrew = 0010; - public const int FnStatementRedefinedExistingChunk = 0011; - public const int SelfUsedInSelfUnawareFunction = 0012; - public const int TooManyInitializersForConstSizeArray = 0013; - public const int NoDefaultByArm = 0014; - public const int MissingErrorInformation = 0015; - public const int FnTargetedStatementRedefinedExistingChunk = 0016; - public const int UnexpectedSyntaxNodeFound = 0017; - public const int FnIndexedStatementRedefinedExistingChunk = 0018; - public const int KeyedExpansionTableExpected = 0019; - } + public const int DuplicateSymbolInScope = 0001; + public const int AttemptToWriteReadOnlyLocal = 0002; + public const int IllegalIncrementationTarget = 0003; + public const int IllegalDecrementationTarget = 0004; + public const int IllegalAssignmentTarget = 0005; + public const int LexerError = 0006; + public const int ParserError = 0007; + public const int IncludeFoundButNoIncludeProcessorsPresent = 0008; + public const int IncludedFileRedefinedExistingChunk = 0009; + public const int IncludeProcessorThrew = 0010; + public const int FnStatementRedefinedExistingChunk = 0011; + public const int SelfUsedInSelfUnawareFunction = 0012; + public const int TooManyInitializersForConstSizeArray = 0013; + public const int NoDefaultByArm = 0014; + public const int MissingErrorInformation = 0015; + public const int FnTargetedStatementRedefinedExistingChunk = 0016; + public const int UnexpectedSyntaxNodeFound = 0017; + public const int FnIndexedStatementRedefinedExistingChunk = 0018; + public const int KeyedExpansionTableExpected = 0019; } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/DuplicateSymbolException.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/DuplicateSymbolException.cs index d76fc500..56748ad5 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/DuplicateSymbolException.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/DuplicateSymbolException.cs @@ -1,20 +1,19 @@ +namespace EVIL.Ceres.TranslationEngine; + using System; using EVIL.Ceres.TranslationEngine.Scoping; -namespace EVIL.Ceres.TranslationEngine +public class DuplicateSymbolException : Exception { - public class DuplicateSymbolException : Exception - { - internal Symbol ExistingSymbol { get; } + internal Symbol ExistingSymbol { get; } - public string SymbolName => ExistingSymbol.Name; - public int Line => ExistingSymbol.DefinedOnLine; - public int Column => ExistingSymbol.DefinedOnColumn; + public string SymbolName => ExistingSymbol.Name; + public int Line => ExistingSymbol.DefinedOnLine; + public int Column => ExistingSymbol.DefinedOnColumn; - internal DuplicateSymbolException(Symbol existingSymbol, string message) - : base(message) - { - ExistingSymbol = existingSymbol; - } + internal DuplicateSymbolException(Symbol existingSymbol, string message) + : base(message) + { + ExistingSymbol = existingSymbol; } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Loop.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Loop.cs index d7025b42..99fe0792 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Loop.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Loop.cs @@ -1,36 +1,35 @@ -using EVIL.Ceres.ExecutionEngine.Diagnostics; +namespace EVIL.Ceres.TranslationEngine; -namespace EVIL.Ceres.TranslationEngine +using EVIL.Ceres.ExecutionEngine.Diagnostics; + +internal class Loop { - internal class Loop + public enum LoopKind { - public enum LoopKind - { - For, - While, - DoWhile, - Each - } + For, + While, + DoWhile, + Each + } - public Chunk Chunk { get; } - public LoopKind Kind { get; } + public Chunk Chunk { get; } + public LoopKind Kind { get; } - public int StartLabel { get; } - public int EndLabel { get; } - public int ExtraLabel { get; } + public int StartLabel { get; } + public int EndLabel { get; } + public int ExtraLabel { get; } - internal Loop(Chunk chunk, LoopKind kind, bool needsExtraLabel) - { - Chunk = chunk; - Kind = kind; + internal Loop(Chunk chunk, LoopKind kind, bool needsExtraLabel) + { + Chunk = chunk; + Kind = kind; - StartLabel = Chunk.CreateLabel(); - EndLabel = Chunk.CreateLabel(); + StartLabel = Chunk.CreateLabel(); + EndLabel = Chunk.CreateLabel(); - if (needsExtraLabel) - { - ExtraLabel = Chunk.CreateLabel(); - } + if (needsExtraLabel) + { + ExtraLabel = Chunk.CreateLabel(); } } } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Scoping/Scope.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Scoping/Scope.cs index 9c3165ba..3f31cc98 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Scoping/Scope.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Scoping/Scope.cs @@ -1,160 +1,159 @@ +namespace EVIL.Ceres.TranslationEngine.Scoping; + using System.Collections.Generic; using EVIL.Ceres.ExecutionEngine.Diagnostics; -namespace EVIL.Ceres.TranslationEngine.Scoping +internal class Scope { - internal class Scope + public Chunk Chunk { get; } + public Scope? Parent { get; } + + public Dictionary Symbols { get; } = new(); + public Dictionary Closures { get; } = new(); + + private Scope(Chunk functionName) { - public Chunk Chunk { get; } - public Scope? Parent { get; } + Chunk = functionName; + } - public Dictionary Symbols { get; } = new(); - public Dictionary Closures { get; } = new(); + private Scope(Chunk functionName, Scope parent) + : this(functionName) + { + Parent = parent; + } - private Scope(Chunk functionName) - { - Chunk = functionName; - } + public Symbol DefineLocal( + string name, + int id, + bool writeable, + int definedOnLine, + int definedOnColumn) + { + var sym = Find(name); - private Scope(Chunk functionName, Scope parent) - : this(functionName) + if (sym != null && !sym.Value.IsClosure) { - Parent = parent; + throw new DuplicateSymbolException( + sym.Value.Symbol, + $"Symbol '{name}' was already defined in the current scope." + ); } - public Symbol DefineLocal( - string name, - int id, - bool writeable, - int definedOnLine, - int definedOnColumn) - { - var sym = Find(name); - - if (sym != null && !sym.Value.IsClosure) - { - throw new DuplicateSymbolException( - sym.Value.Symbol, - $"Symbol '{name}' was already defined in the current scope." - ); - } - - var symbol = new Symbol( - name, - id, - Symbol.SymbolType.Local, - writeable, - definedOnLine, - definedOnColumn, - null - ); + var symbol = new Symbol( + name, + id, + Symbol.SymbolType.Local, + writeable, + definedOnLine, + definedOnColumn, + null + ); - Symbols.Add(name, symbol); - return symbol; - } + Symbols.Add(name, symbol); + return symbol; + } - public Symbol DefineParameter( - string name, - int id, - bool writeable, - int definedOnLine, - int definedOnColumn) + public Symbol DefineParameter( + string name, + int id, + bool writeable, + int definedOnLine, + int definedOnColumn) + { + var sym = Find(name); + + if (sym != null && !sym.Value.IsClosure) { - var sym = Find(name); - - if (sym != null && !sym.Value.IsClosure) - { - throw new DuplicateSymbolException( - sym.Value.Symbol, - $"Symbol '{name}' was already defined in the current scope." - ); - } - - var symbol = new Symbol( - name, - id, - Symbol.SymbolType.Parameter, - writeable, - definedOnLine, - definedOnColumn, - null + throw new DuplicateSymbolException( + sym.Value.Symbol, + $"Symbol '{name}' was already defined in the current scope." ); - - Symbols.Add(name, symbol); - return symbol; } - public Symbol DefineClosure( - string name, - int id, - bool writeable, - int definedOnLine, - int definedOnColumn, - ClosureInfo closureInfo - ) + var symbol = new Symbol( + name, + id, + Symbol.SymbolType.Parameter, + writeable, + definedOnLine, + definedOnColumn, + null + ); + + Symbols.Add(name, symbol); + return symbol; + } + + public Symbol DefineClosure( + string name, + int id, + bool writeable, + int definedOnLine, + int definedOnColumn, + ClosureInfo closureInfo + ) + { + var sym = Find(name); + + if (sym != null) { - var sym = Find(name); - - if (sym != null) - { - throw new DuplicateSymbolException( - sym.Value.Symbol, - $"Closure '{name}' was already defined in the current scope." - ); - } - - var symbol = new Symbol( - name, - id, - Symbol.SymbolType.Closure, - writeable, - definedOnLine, - definedOnColumn, - closureInfo + throw new DuplicateSymbolException( + sym.Value.Symbol, + $"Closure '{name}' was already defined in the current scope." ); - - Closures.Add(name, symbol); - return symbol; } - public (bool IsClosure, Symbol Symbol)? Find(string name) - { - var currentScope = this; + var symbol = new Symbol( + name, + id, + Symbol.SymbolType.Closure, + writeable, + definedOnLine, + definedOnColumn, + closureInfo + ); + + Closures.Add(name, symbol); + return symbol; + } - while (currentScope != null) - { - if (currentScope.Symbols.TryGetValue(name, out var symbol)) - return (false, symbol); + public (bool IsClosure, Symbol Symbol)? Find(string name) + { + var currentScope = this; - if (currentScope.Closures.TryGetValue(name, out var closure)) - return (true, closure); - - currentScope = currentScope.Parent; - } + while (currentScope != null) + { + if (currentScope.Symbols.TryGetValue(name, out var symbol)) + return (false, symbol); - return null; + if (currentScope.Closures.TryGetValue(name, out var closure)) + return (true, closure); + + currentScope = currentScope.Parent; } - public bool IsSymbolWriteable(string identifier, out (bool IsClosure, Symbol Symbol)? sym) - { - sym = Find(identifier); + return null; + } - if (sym == null) - { - // Globals are always writeable. - return true; - } + public bool IsSymbolWriteable(string identifier, out (bool IsClosure, Symbol Symbol)? sym) + { + sym = Find(identifier); - return sym.Value.Symbol.ReadWrite; + if (sym == null) + { + // Globals are always writeable. + return true; } - public void Clear() - => Symbols.Clear(); + return sym.Value.Symbol.ReadWrite; + } + + public void Clear() + => Symbols.Clear(); - public Scope Descend() - => new(Chunk, this); + public Scope Descend() + => new(Chunk, this); - public static Scope CreateRoot(Chunk chunk) - => new(chunk); - } + public static Scope CreateRoot(Chunk chunk) + => new(chunk); } \ No newline at end of file diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Scoping/Symbol.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Scoping/Symbol.cs index a1bb2439..d775b5f8 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Scoping/Symbol.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Scoping/Symbol.cs @@ -1,23 +1,22 @@ +namespace EVIL.Ceres.TranslationEngine.Scoping; + using EVIL.Ceres.ExecutionEngine.Diagnostics; -namespace EVIL.Ceres.TranslationEngine.Scoping +internal record Symbol( + string Name, + int Id, + Symbol.SymbolType Type, + bool ReadWrite, + int DefinedOnLine, + int DefinedOnColumn, + ClosureInfo? ClosureInfo) { - internal record Symbol( - string Name, - int Id, - Symbol.SymbolType Type, - bool ReadWrite, - int DefinedOnLine, - int DefinedOnColumn, - ClosureInfo? ClosureInfo) - { - public string TypeName => Type.ToString().ToLower(); + public string TypeName => Type.ToString().ToLower(); - public enum SymbolType - { - Local, - Parameter, - Closure - } + public enum SymbolType + { + Local, + Parameter, + Closure } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/AssertModule.cs b/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/AssertModule.cs index 58c05f18..da5a805a 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/AssertModule.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/AssertModule.cs @@ -1,163 +1,163 @@ +namespace EVIL.Ceres.LanguageTests; + +using static EVIL.Ceres.ExecutionEngine.TypeSystem.DynamicValue; + using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.Concurrency; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.Ceres.Runtime; using EVIL.Ceres.Runtime.Extensions; using EVIL.Ceres.TranslationEngine; -using static EVIL.Ceres.ExecutionEngine.TypeSystem.DynamicValue; -namespace EVIL.Ceres.LanguageTests +public class AssertModule : RuntimeModule { - public class AssertModule : RuntimeModule + public override string FullyQualifiedName => "assert"; + + public AssertModule() { - public override string FullyQualifiedName => "assert"; + var compiler = new Compiler(); + var rootChunk = compiler.Compile("fn __invk(t, expr) -> t.is_true(expr);"); - public AssertModule() - { - var compiler = new Compiler(); - var rootChunk = compiler.Compile("fn __invk(t, expr) -> t.is_true(expr);"); - - this["throws"] = compiler.Compile( - "fn throws(func) {\n" + - " if (func !is Function) throw error('This function can only test Functions.');\n" + - "\n" + - " rw val threw = nil;" + - "\n" + - " try {\n" + - " func();\n" + - " threw = false;\n" + - " } catch { threw = true; }\n" + - "\n" + - " throw error { " + - " __should_have_thrown: true," + - " __threw: threw" + - " };\n" + - "}" - )["throws"]!; + this["throws"] = compiler.Compile( + "fn throws(func) {\n" + + " if (func !is Function) throw error('This function can only test Functions.');\n" + + "\n" + + " rw val threw = nil;" + + "\n" + + " try {\n" + + " func();\n" + + " threw = false;\n" + + " } catch { threw = true; }\n" + + "\n" + + " throw error { " + + " __should_have_thrown: true," + + " __threw: threw" + + " };\n" + + "}" + )["throws"]!; - MetaTable ??= new Table - { - { InvokeMetaKey, rootChunk.SubChunks[0] } - }; - } - - [RuntimeModuleFunction("is_true")] - private static DynamicValue IsTrue(Fiber _, params DynamicValue[] args) + MetaTable ??= new Table { - args.ExpectBooleanAt(0, out var boolean) - .OptionalStringAt(1, $"expected expression to be true, but it was false", out var msg); + { InvokeMetaKey, rootChunk.SubChunks[0] } + }; + } - if (!boolean) - { - throw new TestAssertionException(msg); - } - - return Nil; - } - - [RuntimeModuleFunction("is_false")] - private static DynamicValue IsFalse(Fiber _, params DynamicValue[] args) - { - args.ExpectBooleanAt(0, out var boolean) - .OptionalStringAt(1, $"expected expression to be false, but it was true", out var msg); + [RuntimeModuleFunction("is_true")] + private static DynamicValue IsTrue(Fiber _, params DynamicValue[] args) + { + args.ExpectBooleanAt(0, out var boolean) + .OptionalStringAt(1, $"expected expression to be true, but it was false", out var msg); - if (boolean) - { - throw new TestAssertionException(msg); - } - - return Nil; + if (!boolean) + { + throw new TestAssertionException(msg); } + + return Nil; + } + + [RuntimeModuleFunction("is_false")] + private static DynamicValue IsFalse(Fiber _, params DynamicValue[] args) + { + args.ExpectBooleanAt(0, out var boolean) + .OptionalStringAt(1, $"expected expression to be false, but it was true", out var msg); - [RuntimeModuleFunction("is_of_type")] - private static DynamicValue IsOfType(Fiber _, params DynamicValue[] args) + if (boolean) { - args.ExpectAnyAt(0, out var value) - .ExpectTypeCodeAt(1, out var typeCode) - .OptionalStringAt(2, $"expected the type of `{value}' to be `{typeCode}', but was `{value.Type}'", out var msg); + throw new TestAssertionException(msg); + } + + return Nil; + } - if (value.Type != typeCode) - { - throw new TestAssertionException(msg); - } + [RuntimeModuleFunction("is_of_type")] + private static DynamicValue IsOfType(Fiber _, params DynamicValue[] args) + { + args.ExpectAnyAt(0, out var value) + .ExpectTypeCodeAt(1, out var typeCode) + .OptionalStringAt(2, $"expected the type of `{value}' to be `{typeCode}', but was `{value.Type}'", out var msg); - return Nil; + if (value.Type != typeCode) + { + throw new TestAssertionException(msg); } + + return Nil; + } - [RuntimeModuleFunction("equal")] - private static DynamicValue Equal(Fiber _, params DynamicValue[] args) + [RuntimeModuleFunction("equal")] + private static DynamicValue Equal(Fiber _, params DynamicValue[] args) + { + args.ExpectAnyAt(0, out var actual) + .ExpectAnyAt(1, out var expected) + .OptionalStringAt(2, $"expected expression to be equal to `{expected}', but was `{actual}' instead", out var msg); + + if (expected != actual) { - args.ExpectAnyAt(0, out var actual) - .ExpectAnyAt(1, out var expected) - .OptionalStringAt(2, $"expected expression to be equal to `{expected}', but was `{actual}' instead", out var msg); - - if (expected != actual) - { - throw new TestAssertionException(msg); - } - - return Nil; + throw new TestAssertionException(msg); } + + return Nil; + } - [RuntimeModuleFunction("greater_than_or_equal")] - private static DynamicValue GreaterThanOrEqual(Fiber _, params DynamicValue[] args) + [RuntimeModuleFunction("greater_than_or_equal")] + private static DynamicValue GreaterThanOrEqual(Fiber _, params DynamicValue[] args) + { + args.ExpectAnyAt(0, out var actual) + .ExpectAnyAt(1, out var expected) + .OptionalStringAt(2, $"expected expression to be greater than or equal to `{expected}', but was `{actual}' instead", out var msg); + + if (actual.IsLessThan(expected).Boolean) { - args.ExpectAnyAt(0, out var actual) - .ExpectAnyAt(1, out var expected) - .OptionalStringAt(2, $"expected expression to be greater than or equal to `{expected}', but was `{actual}' instead", out var msg); - - if (actual.IsLessThan(expected).Boolean) - { - throw new TestAssertionException(msg); - } - - return Nil; + throw new TestAssertionException(msg); } + + return Nil; + } - [RuntimeModuleFunction("less_than_or_equal")] - private static DynamicValue LessThanOrEqual(Fiber _, params DynamicValue[] args) + [RuntimeModuleFunction("less_than_or_equal")] + private static DynamicValue LessThanOrEqual(Fiber _, params DynamicValue[] args) + { + args.ExpectAnyAt(0, out var actual) + .ExpectAnyAt(1, out var expected) + .OptionalStringAt(2, $"expected expression to be less than or equal to `{expected}', but was `{actual}' instead", out var msg); + + if (actual.IsGreaterThan(expected).Boolean) { - args.ExpectAnyAt(0, out var actual) - .ExpectAnyAt(1, out var expected) - .OptionalStringAt(2, $"expected expression to be less than or equal to `{expected}', but was `{actual}' instead", out var msg); - - if (actual.IsGreaterThan(expected).Boolean) - { - throw new TestAssertionException(msg); - } - - return Nil; + throw new TestAssertionException(msg); } + + return Nil; + } - [RuntimeModuleFunction("approx_equal")] - private static DynamicValue ApproximatelyEqual(Fiber _, params DynamicValue[] args) + [RuntimeModuleFunction("approx_equal")] + private static DynamicValue ApproximatelyEqual(Fiber _, params DynamicValue[] args) + { + args.ExpectNumberAt(0, out var actual) + .ExpectNumberAt(1, out var expected) + .OptionalIntegerAt(2, 1, out var precision) + .OptionalStringAt(3, $"expected expression to approximately (rounded to {precision} decimal places) equal `{expected}', but was `{actual}' instead", out var msg); + + if (double.Round(expected, (int)precision) != double.Round(actual, (int)precision)) { - args.ExpectNumberAt(0, out var actual) - .ExpectNumberAt(1, out var expected) - .OptionalIntegerAt(2, 1, out var precision) - .OptionalStringAt(3, $"expected expression to approximately (rounded to {precision} decimal places) equal `{expected}', but was `{actual}' instead", out var msg); - - if (double.Round(expected, (int)precision) != double.Round(actual, (int)precision)) - { - throw new TestAssertionException(msg); - } - - return Nil; + throw new TestAssertionException(msg); } + + return Nil; + } - [RuntimeModuleFunction("not_equal")] - private static DynamicValue NotEqual(Fiber _, params DynamicValue[] args) + [RuntimeModuleFunction("not_equal")] + private static DynamicValue NotEqual(Fiber _, params DynamicValue[] args) + { + args.ExpectAnyAt(0, out var actual) + .ExpectAnyAt(1, out var unexpected) + .OptionalStringAt(2, $"expected expression to NOT be equal to `{unexpected}', but was `{actual}' instead", out var msg); + + if (unexpected == actual) { - args.ExpectAnyAt(0, out var actual) - .ExpectAnyAt(1, out var unexpected) - .OptionalStringAt(2, $"expected expression to NOT be equal to `{unexpected}', but was `{actual}' instead", out var msg); - - if (unexpected == actual) - { - throw new TestAssertionException(msg); - } - - return Nil; + throw new TestAssertionException(msg); } + + return Nil; } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/AttributeProcessors.cs b/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/AttributeProcessors.cs index b663812b..a8ab0532 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/AttributeProcessors.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/AttributeProcessors.cs @@ -1,66 +1,65 @@ -using System; +namespace EVIL.Ceres.LanguageTests; + +using System; using System.Linq; using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.LanguageTests +public static class AttributeProcessors { - public static class AttributeProcessors + public static void ApproximateAttribute(ChunkAttribute approximateAttribute, Chunk chunk) { - public static void ApproximateAttribute(ChunkAttribute approximateAttribute, Chunk chunk) + if (!chunk.TryGetAttribute("test", out var testAttribute)) { - if (!chunk.TryGetAttribute("test", out var testAttribute)) - { - throw new Exception("Only valid on functions marked as a test."); - } + throw new Exception("Only valid on functions marked as a test."); + } - if (!testAttribute.Values.Any()) - { - throw new Exception("Only valid on tests returning a value."); - } + if (!testAttribute.Values.Any()) + { + throw new Exception("Only valid on tests returning a value."); + } + + if (testAttribute.Values[0].Type != DynamicValueType.Number) + { + throw new Exception("Only valid on tests returning a number."); + } - if (testAttribute.Values[0].Type != DynamicValueType.Number) + if (approximateAttribute.Values.Any()) + { + if (approximateAttribute.Values.Count > 1) { - throw new Exception("Only valid on tests returning a number."); + throw new Exception("Accepts at most 1 parameter."); } - if (approximateAttribute.Values.Any()) + if (approximateAttribute.Values[0].Number % 1 != 0) { - if (approximateAttribute.Values.Count > 1) - { - throw new Exception("Accepts at most 1 parameter."); - } - - if (approximateAttribute.Values[0].Number % 1 != 0) - { - throw new Exception("Decimal places parameter needs to be an integer."); - } + throw new Exception("Decimal places parameter needs to be an integer."); } } + } - public static void DisasmAttribute(ChunkAttribute disasmAttribute, Chunk chunk) + public static void DisasmAttribute(ChunkAttribute disasmAttribute, Chunk chunk) + { + if (disasmAttribute.Values.Any()) { - if (disasmAttribute.Values.Any()) + if (disasmAttribute.Values[0].Type != DynamicValueType.String) { - if (disasmAttribute.Values[0].Type != DynamicValueType.String) - { - throw new Exception("Only accepts a string."); - } - - switch (disasmAttribute.Values[0].String) - { - case "always": - case "failure": - case "never": - break; - - default: throw new Exception("Accepts only 'always', 'failure' or 'never'."); - } + throw new Exception("Only accepts a string."); } - else + + switch (disasmAttribute.Values[0].String) { - disasmAttribute.Values.Add(new("always")); + case "always": + case "failure": + case "never": + break; + + default: throw new Exception("Accepts only 'always', 'failure' or 'never'."); } } + else + { + disasmAttribute.Values.Add(new("always")); + } } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/Test.cs b/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/Test.cs index de116ae9..9a6b383e 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/Test.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/Test.cs @@ -1,3 +1,5 @@ +namespace EVIL.Ceres.LanguageTests; + using System; using System.Collections.Generic; using System.Linq; @@ -8,118 +10,115 @@ using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.LanguageTests +public class Test { - public class Test - { - private readonly Chunk _chunk; - private bool _processingCrash; + private readonly Chunk _chunk; + private bool _processingCrash; + + public Fiber Fiber { get; } - public Fiber Fiber { get; } + public bool CallsAnyAsserts { get; private set; } - public bool CallsAnyAsserts { get; private set; } + public bool Successful { get; private set; } = true; + public string ErrorMessage { get; private set; } = string.Empty; + public List StackTrace { get; private set; } = new(); + + public Test(CeresVM vm, Chunk chunk) + { + _chunk = chunk; + Fiber = vm.Scheduler.CreateFiber( + true, + TestCrashHandler, + (Dictionary)vm.MainFiber.ClosureContexts + ); + + Fiber.SetOnNativeFunctionInvoke(OnNativeFunctionInvoke); + } - public bool Successful { get; private set; } = true; - public string ErrorMessage { get; private set; } = string.Empty; - public List StackTrace { get; private set; } = new(); + public async Task Run() + { + Fiber.Schedule(_chunk); - public Test(CeresVM vm, Chunk chunk) + while (Fiber.State != FiberState.Crashed + && Fiber.State != FiberState.Finished) { - _chunk = chunk; - Fiber = vm.Scheduler.CreateFiber( - true, - TestCrashHandler, - (Dictionary)vm.MainFiber.ClosureContexts - ); - - Fiber.SetOnNativeFunctionInvoke(OnNativeFunctionInvoke); + await Task.Delay(TimeSpan.FromMicroseconds(1)); } - public async Task Run() + if (Fiber.State == FiberState.Crashed) { - Fiber.Schedule(_chunk); - - while (Fiber.State != FiberState.Crashed - && Fiber.State != FiberState.Finished) - { - await Task.Delay(TimeSpan.FromMicroseconds(1)); - } - - if (Fiber.State == FiberState.Crashed) - { - _processingCrash = true; - } + _processingCrash = true; } + } - public async Task WaitForCleanup() + public async Task WaitForCleanup() + { + while (_processingCrash) { - while (_processingCrash) - { - await Task.Delay(TimeSpan.FromMicroseconds(1)); - } - - Fiber.DeImmunize(); + await Task.Delay(TimeSpan.FromMicroseconds(1)); } - private void TestCrashHandler(Fiber fiber, Exception exception) - { - Successful = false; + Fiber.DeImmunize(); + } - if (exception is UserUnhandledExceptionException uuee) + private void TestCrashHandler(Fiber fiber, Exception exception) + { + Successful = false; + + if (exception is UserUnhandledExceptionException uuee) + { + if (uuee.EvilExceptionObject.Type == DynamicValueType.Error) { - if (uuee.EvilExceptionObject.Type == DynamicValueType.Error) + var e = uuee.EvilExceptionObject.Error!; + if (e["__should_have_thrown"] == true) { - var e = uuee.EvilExceptionObject.Error!; - if (e["__should_have_thrown"] == true) + CallsAnyAsserts = true; + + if (e["__threw"] == true) { - CallsAnyAsserts = true; - - if (e["__threw"] == true) - { - Successful = true; - } - else - { - ErrorMessage = "Expected function to throw, but it was successful."; - } + Successful = true; } - else if (e["__should_not_have_thrown"] != DynamicValue.Nil) + else { - CallsAnyAsserts = true; - - if (e["__threw"] == false) - { - Successful = true; - } - else - { - ErrorMessage = "Expected function to be successful, but it threw."; - } + ErrorMessage = "Expected function to throw, but it was successful."; } } - } - else - { - ErrorMessage = exception.Message; - } + else if (e["__should_not_have_thrown"] != DynamicValue.Nil) + { + CallsAnyAsserts = true; - if (!Successful) - { - StackTrace.AddRange(fiber.StackTrace(false).Split('\n').Where(x => !string.IsNullOrEmpty(x))); + if (e["__threw"] == false) + { + Successful = true; + } + else + { + ErrorMessage = "Expected function to be successful, but it threw."; + } + } } - - _processingCrash = false; + } + else + { + ErrorMessage = exception.Message; } - private void OnNativeFunctionInvoke(Fiber fiber, NativeFunction nativeFunction) + if (!Successful) { - var nativeFunctionType = nativeFunction.Method.DeclaringType; - if (nativeFunctionType == null) return; + StackTrace.AddRange(fiber.StackTrace(false).Split('\n').Where(x => !string.IsNullOrEmpty(x))); + } - if (nativeFunctionType.IsAssignableTo(typeof(AssertModule))) - { - CallsAnyAsserts = true; - } + _processingCrash = false; + } + + private void OnNativeFunctionInvoke(Fiber fiber, NativeFunction nativeFunction) + { + var nativeFunctionType = nativeFunction.Method.DeclaringType; + if (nativeFunctionType == null) return; + + if (nativeFunctionType.IsAssignableTo(typeof(AssertModule))) + { + CallsAnyAsserts = true; } } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestAssertionException.cs b/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestAssertionException.cs index 24a41e84..c4438594 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestAssertionException.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestAssertionException.cs @@ -1,12 +1,11 @@ +namespace EVIL.Ceres.LanguageTests; + using System; -namespace EVIL.Ceres.LanguageTests +public class TestAssertionException : Exception { - public class TestAssertionException : Exception + public TestAssertionException(string message) + : base(message) { - public TestAssertionException(string message) - : base(message) - { - } } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestBuildPhaseException.cs b/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestBuildPhaseException.cs index 442a3dbd..95aa835c 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestBuildPhaseException.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestBuildPhaseException.cs @@ -1,25 +1,24 @@ -using System; +namespace EVIL.Ceres.LanguageTests; + +using System; using EVIL.Ceres.TranslationEngine; using EVIL.Grammar; using EVIL.Lexical; -namespace EVIL.Ceres.LanguageTests +public class TestBuildPhaseException : Exception { - public class TestBuildPhaseException : Exception + public TestBuildPhaseException(string message, LexerException lexerException) + : base(message, lexerException) { - public TestBuildPhaseException(string message, LexerException lexerException) - : base(message, lexerException) - { - } + } - public TestBuildPhaseException(string message, ParserException parserException) - : base(message, parserException) - { - } + public TestBuildPhaseException(string message, ParserException parserException) + : base(message, parserException) + { + } - public TestBuildPhaseException(string message, CompilerException compilerException) - : base(message, compilerException) - { - } + public TestBuildPhaseException(string message, CompilerException compilerException) + : base(message, compilerException) + { } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestRunner.cs b/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestRunner.cs index 4d024cf6..127238ca 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestRunner.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestRunner.cs @@ -1,4 +1,6 @@ -using System; +namespace EVIL.Ceres.LanguageTests; + +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -13,345 +15,342 @@ using EVIL.Ceres.TranslationEngine; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.LanguageTests +public class TestRunner { - public class TestRunner - { - private Dictionary> _includeCache = new(); + private Dictionary> _includeCache = new(); - private Stopwatch Stopwatch { get; } = new(); - private string[] TestDirectories { get; } - private CeresVM VM { get; } - private TextWriter TextOut { get; } - private EvilRuntime Runtime { get; } + private Stopwatch Stopwatch { get; } = new(); + private string[] TestDirectories { get; } + private CeresVM VM { get; } + private TextWriter TextOut { get; } + private EvilRuntime Runtime { get; } - private Dictionary> FailureLog { get; } = new(); + private Dictionary> FailureLog { get; } = new(); - private TestRunnerOptions Options { get; } + private TestRunnerOptions Options { get; } - public TestRunner(CeresVM vm, TestRunnerOptions options) - { - VM = vm; - Options = options; + public TestRunner(CeresVM vm, TestRunnerOptions options) + { + VM = vm; + Options = options; - TestDirectories = Options.TestDirectories.Select( - x => Path.GetFullPath(x) - ).ToArray(); + TestDirectories = Options.TestDirectories.Select( + x => Path.GetFullPath(x) + ).ToArray(); - TextOut = Options.TestOutput ?? Console.Out; + TextOut = Options.TestOutput ?? Console.Out; - Runtime = new EvilRuntime(vm); - } + Runtime = new EvilRuntime(vm); + } - public async Task RunTests() - { - var result = 0; + public async Task RunTests() + { + var result = 0; - if ((result = Compile(out var testSets)) > 0) - return result; - - foreach (var testSet in testSets) - { - if ((result = await Execute(testSet)) > 0) - return result; - } - + if ((result = Compile(out var testSets)) > 0) return result; - } - private int Compile(out List testSets) + foreach (var testSet in testSets) { - var compiler = new Compiler(); - compiler.RegisterAttributeProcessor("approximate", AttributeProcessors.ApproximateAttribute); - compiler.RegisterAttributeProcessor("disasm", AttributeProcessors.DisasmAttribute); + if ((result = await Execute(testSet)) > 0) + return result; + } + + return result; + } - testSets = new List(); + private int Compile(out List testSets) + { + var compiler = new Compiler(); + compiler.RegisterAttributeProcessor("approximate", AttributeProcessors.ApproximateAttribute); + compiler.RegisterAttributeProcessor("disasm", AttributeProcessors.DisasmAttribute); + + testSets = new List(); - foreach (var testDirectory in TestDirectories) - { - TextOut.WriteLine($"<[ TEST SET '{testDirectory}' ]>"); - var testSet = new TestSet(testDirectory); + foreach (var testDirectory in TestDirectories) + { + TextOut.WriteLine($"<[ TEST SET '{testDirectory}' ]>"); + var testSet = new TestSet(testDirectory); - var paths = Directory - .GetFiles(testDirectory, "*.vil") - .OrderBy(x => x) - .ToList(); + var paths = Directory + .GetFiles(testDirectory, "*.vil") + .OrderBy(x => x) + .ToList(); - foreach (var path in paths) + foreach (var path in paths) + { + var source = File.ReadAllText(path); + try { - var source = File.ReadAllText(path); - try - { - TextOut.Write($" Compiling test '{path}'..."); - var rootChunk = compiler.Compile(source, Path.GetFullPath(path)); - testSet.AddTestRootChunk(path, rootChunk); - TextOut.WriteLine(" [ PASS ]"); - - if (compiler.Log.HasAnyMessages) - { - TextOut.Write(compiler.Log.ToString((s) => $" | {s}")); - compiler.Log.Clear(); - } - } - catch (CompilerException) - { - TextOut.WriteLine(" [ FAIL ]"); - TextOut.WriteLine(compiler.Log.ToString((s) => $" | {s}")); - - if (Options.FailOnCompilerErrors) - { - TextOut.WriteLine("Test run aborted early due to a compilation error."); - return 1; - } + TextOut.Write($" Compiling test '{path}'..."); + var rootChunk = compiler.Compile(source, Path.GetFullPath(path)); + testSet.AddTestRootChunk(path, rootChunk); + TextOut.WriteLine(" [ PASS ]"); + if (compiler.Log.HasAnyMessages) + { + TextOut.Write(compiler.Log.ToString((s) => $" | {s}")); compiler.Log.Clear(); } } + catch (CompilerException) + { + TextOut.WriteLine(" [ FAIL ]"); + TextOut.WriteLine(compiler.Log.ToString((s) => $" | {s}")); + + if (Options.FailOnCompilerErrors) + { + TextOut.WriteLine("Test run aborted early due to a compilation error."); + return 1; + } - testSets.Add(testSet); + compiler.Log.Clear(); + } } + + testSets.Add(testSet); + } - TextOut.WriteLine(); - return 0; - } + TextOut.WriteLine(); + return 0; + } - private async Task Execute(TestSet testSet) - { - var failuresOccurred = false; + private async Task Execute(TestSet testSet) + { + var failuresOccurred = false; - foreach (var testRoot in testSet.TestRootChunks) - { - var passed = 0; - var failed = 0; - var ignored = 0; + foreach (var testRoot in testSet.TestRootChunks) + { + var passed = 0; + var failed = 0; + var ignored = 0; - var path = testRoot.Key; - TextOut.WriteLine($"--- [TEST '{path}'] ---"); + var path = testRoot.Key; + TextOut.WriteLine($"--- [TEST '{path}'] ---"); - VM.Global.Clear(); - VM.Global.Set("__native_func", new((_, args) => { return args[3]; })); + VM.Global.Clear(); + VM.Global.Set("__native_func", new((_, args) => { return args[3]; })); - VM.Global.Set("__native_object", DynamicValue.FromObject(new object())); - VM.Global.Set("__tricky", new TrickyTable()); + VM.Global.Set("__native_object", DynamicValue.FromObject(new object())); + VM.Global.Set("__tricky", new TrickyTable()); - VM.Global.Set("__throw_test", new((fiber, args) => - { - return fiber.ThrowFromNative(args[0]); - })); + VM.Global.Set("__throw_test", new((fiber, args) => + { + return fiber.ThrowFromNative(args[0]); + })); - Runtime.RegisterBuiltInModules(); - Runtime.RegisterBuiltInFunctions(); - Runtime.RegisterModule(out _); + Runtime.RegisterBuiltInModules(); + Runtime.RegisterBuiltInFunctions(); + Runtime.RegisterModule(out _); - VM.MainFiber.SetCrashHandler((fiber, exception) => - { - TextOut.WriteLine($"Test crashed in root chunk: {exception.Message}"); - TextOut.WriteLine(fiber.StackTrace(false)); - TextOut.WriteLine(exception); - TextOut.WriteLine(); - }); + VM.MainFiber.SetCrashHandler((fiber, exception) => + { + TextOut.WriteLine($"Test crashed in root chunk: {exception.Message}"); + TextOut.WriteLine(fiber.StackTrace(false)); + TextOut.WriteLine(exception); + TextOut.WriteLine(); + }); - var testRootChunk = testRoot.Value; - VM.MainFiber.Schedule(testRootChunk); - VM.MainFiber.BlockUntilFinished(); + var testRootChunk = testRoot.Value; + VM.MainFiber.Schedule(testRootChunk); + VM.MainFiber.BlockUntilFinished(); - var testChunks = new List(); - foreach (var (name, _) in testRootChunk.NamedSubChunkLookup) + var testChunks = new List(); + foreach (var (name, _) in testRootChunk.NamedSubChunkLookup) + { + var v = VM.Global[name]; + if (v.Type == DynamicValueType.Chunk) { - var v = VM.Global[name]; - if (v.Type == DynamicValueType.Chunk) + if (v.Chunk!.HasAttribute("test")) { - if (v.Chunk!.HasAttribute("test")) - { - testChunks.Add(v.Chunk); - } + testChunks.Add(v.Chunk); } } + } - if (testChunks.Count == 0) - { - TextOut.WriteLine($"Test file '{path}' has no tests. Ignoring..."); - continue; - } + if (testChunks.Count == 0) + { + TextOut.WriteLine($"Test file '{path}' has no tests. Ignoring..."); + continue; + } - if (VM.MainFiber.State == FiberState.Crashed) - { - VM.MainFiber.Reset(); - continue; - } + if (VM.MainFiber.State == FiberState.Crashed) + { + VM.MainFiber.Reset(); + continue; + } - for (var i = 0; i < testChunks.Count; i++) - { - var whenToDisassemble = "failure"; - - var chunk = testChunks[i]; - if (chunk.TryGetAttribute("disasm", out var attr)) - { - whenToDisassemble = attr.Values[0].String; - } + for (var i = 0; i < testChunks.Count; i++) + { + var whenToDisassemble = "failure"; - TextOut.Write($"[{i + 1}/{testChunks.Count}] "); + var chunk = testChunks[i]; + if (chunk.TryGetAttribute("disasm", out var attr)) + { + whenToDisassemble = attr.Values[0].String; + } - var result = await RunTestChunk(chunk, path); + TextOut.Write($"[{i + 1}/{testChunks.Count}] "); - if (whenToDisassemble != "never" - && (whenToDisassemble == "always" - || (whenToDisassemble == "failure" && result == false) - )) - { - Disassembler.Disassemble(chunk, TextOut); - TextOut.WriteLine(); - } + var result = await RunTestChunk(chunk, path); - if (result == false) - { - failed++; - } - else if (result == true) - { - passed++; - } - else - { - ignored++; - } + if (whenToDisassemble != "never" + && (whenToDisassemble == "always" + || (whenToDisassemble == "failure" && result == false) + )) + { + Disassembler.Disassemble(chunk, TextOut); + TextOut.WriteLine(); } - var verb = (ignored > 1 || ignored == 0) - ? "were" - : "was"; - - failuresOccurred |= failed > 0; - - TextOut.WriteLine($"{passed} tests passed, {failed} failed, {ignored} {verb} ignored."); - using (var process = Process.GetCurrentProcess()) + if (result == false) { - TextOut.WriteLine($"Total process memory so far: {process.WorkingSet64} bytes."); + failed++; } - TextOut.WriteLine(); - - if (failuresOccurred && Options.FailOnTestErrors) + else if (result == true) + { + passed++; + } + else { - break; + ignored++; } } - ReportAnyTestFailures(); + var verb = (ignored > 1 || ignored == 0) + ? "were" + : "was"; - if (failuresOccurred) + failuresOccurred |= failed > 0; + + TextOut.WriteLine($"{passed} tests passed, {failed} failed, {ignored} {verb} ignored."); + using (var process = Process.GetCurrentProcess()) { - if (Options.FailOnTestErrors) - { - TextOut.WriteLine("Test run aborted early due to one or more test failures."); - } - - return 2; + TextOut.WriteLine($"Total process memory so far: {process.WorkingSet64} bytes."); } + TextOut.WriteLine(); - return 0; + if (failuresOccurred && Options.FailOnTestErrors) + { + break; + } } - private async Task RunTestChunk(Chunk chunk, string path) - { - var (ignore, why) = CheckIgnoreStatus(chunk); + ReportAnyTestFailures(); - if (ignore) + if (failuresOccurred) + { + if (Options.FailOnTestErrors) { - TextOut.Write($"[IGNORED] '{chunk.Name}'"); + TextOut.WriteLine("Test run aborted early due to one or more test failures."); + } + + return 2; + } - if (why != null) - { - TextOut.Write($": {why}"); - } + return 0; + } - TextOut.WriteLine(); - return null; - } + private async Task RunTestChunk(Chunk chunk, string path) + { + var (ignore, why) = CheckIgnoreStatus(chunk); - var test = new Test(VM, chunk); + if (ignore) + { + TextOut.Write($"[IGNORED] '{chunk.Name}'"); - Stopwatch.Reset(); - Stopwatch.Start(); + if (why != null) { - await test.Run(); + TextOut.Write($": {why}"); } - Stopwatch.Stop(); - await test.WaitForCleanup(); + + TextOut.WriteLine(); + return null; + } + + var test = new Test(VM, chunk); + + Stopwatch.Reset(); + Stopwatch.Start(); + { + await test.Run(); + } + Stopwatch.Stop(); + await test.WaitForCleanup(); - var stamp = $"{Stopwatch.Elapsed.TotalMicroseconds}μs"; + var stamp = $"{Stopwatch.Elapsed.TotalMicroseconds}μs"; - if (test.Successful) + if (test.Successful) + { + if (test.CallsAnyAsserts) { - if (test.CallsAnyAsserts) - { - TextOut.WriteLine($"[PASSED] '{chunk.Name}' [{stamp}]"); - } - else - { - var msg = $"No assertions were made. [{stamp}]"; - - AddTestFailure(path, chunk, msg); - TextOut.WriteLine($"[INCONCLUSIVE] '{chunk.Name}': {msg}"); - } + TextOut.WriteLine($"[PASSED] '{chunk.Name}' [{stamp}]"); } else { - var msg = new StringBuilder(); - msg.AppendLine($"{test.ErrorMessage} [{stamp}]"); - foreach (var line in test.StackTrace) - { - msg.AppendLine($" {line}"); - } - - AddTestFailure(path, chunk, msg.ToString()); - TextOut.WriteLine($"[FAILED] '{chunk.Name}': {msg}"); + var msg = $"No assertions were made. [{stamp}]"; + + AddTestFailure(path, chunk, msg); + TextOut.WriteLine($"[INCONCLUSIVE] '{chunk.Name}': {msg}"); } - - return test.Successful; } - - private (bool Ignore, string? Reason) CheckIgnoreStatus(Chunk chunk) + else { - if (!chunk.TryGetAttribute("ignore", out var ignoreAttr)) + var msg = new StringBuilder(); + msg.AppendLine($"{test.ErrorMessage} [{stamp}]"); + foreach (var line in test.StackTrace) { - return (false, null); + msg.AppendLine($" {line}"); } - string? reason = null; - if (ignoreAttr.Values.Count > 0) - { - reason = ignoreAttr.Values[0].ConvertToString().String; - } + AddTestFailure(path, chunk, msg.ToString()); + TextOut.WriteLine($"[FAILED] '{chunk.Name}': {msg}"); + } + + return test.Successful; + } - return (true, reason); + private (bool Ignore, string? Reason) CheckIgnoreStatus(Chunk chunk) + { + if (!chunk.TryGetAttribute("ignore", out var ignoreAttr)) + { + return (false, null); } - private void AddTestFailure(string path, Chunk testChunk, string failureReason) + string? reason = null; + if (ignoreAttr.Values.Count > 0) { - if (!FailureLog.TryGetValue(path, out var list)) - { - list = new List<(Chunk TestChunk, string FailureReason)>(); - FailureLog.Add(path, list); - } + reason = ignoreAttr.Values[0].ConvertToString().String; + } - list.Add((testChunk, failureReason)); + return (true, reason); + } + + private void AddTestFailure(string path, Chunk testChunk, string failureReason) + { + if (!FailureLog.TryGetValue(path, out var list)) + { + list = new List<(Chunk TestChunk, string FailureReason)>(); + FailureLog.Add(path, list); } - private void ReportAnyTestFailures() + list.Add((testChunk, failureReason)); + } + + private void ReportAnyTestFailures() + { + if (FailureLog.Any()) { - if (FailureLog.Any()) - { - TextOut.WriteLine("There were one or more of test failures/inconclusive results:"); - } + TextOut.WriteLine("There were one or more of test failures/inconclusive results:"); + } - foreach (var kvp in FailureLog) + foreach (var kvp in FailureLog) + { + TextOut.WriteLine($"{kvp.Key}: "); + foreach (var result in kvp.Value) { - TextOut.WriteLine($"{kvp.Key}: "); - foreach (var result in kvp.Value) - { - TextOut.WriteLine($"{result.TestChunk.Name} (def. at line {result.TestChunk.DebugDatabase.DefinedOnLine}): {result.FailureReason}"); - } + TextOut.WriteLine($"{result.TestChunk.Name} (def. at line {result.TestChunk.DebugDatabase.DefinedOnLine}): {result.FailureReason}"); } } } diff --git a/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestRunnerOptions.cs b/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestRunnerOptions.cs index 38475956..f0c3805b 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestRunnerOptions.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestRunnerOptions.cs @@ -1,11 +1,10 @@ +namespace EVIL.Ceres.LanguageTests; + using System.IO; -namespace EVIL.Ceres.LanguageTests -{ - public record TestRunnerOptions( - bool FailOnCompilerErrors, - bool FailOnTestErrors, - string[] TestDirectories, - TextWriter? TestOutput = null - ); -} \ No newline at end of file +public record TestRunnerOptions( + bool FailOnCompilerErrors, + bool FailOnTestErrors, + string[] TestDirectories, + TextWriter? TestOutput = null +); \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestSet.cs b/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestSet.cs index cae12362..24bce36f 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestSet.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TestSet.cs @@ -1,21 +1,20 @@ +namespace EVIL.Ceres.LanguageTests; + using System.Collections.Generic; using EVIL.Ceres.ExecutionEngine.Diagnostics; -namespace EVIL.Ceres.LanguageTests +public class TestSet { - public class TestSet - { - private readonly Dictionary _testRootChunks = new(); + private readonly Dictionary _testRootChunks = new(); - public string DirectoryPath { get; } - public IReadOnlyDictionary TestRootChunks => _testRootChunks; - - public TestSet(string directoryPath) - { - DirectoryPath = directoryPath; - } + public string DirectoryPath { get; } + public IReadOnlyDictionary TestRootChunks => _testRootChunks; - public bool AddTestRootChunk(string filePath, Chunk chunk) - => _testRootChunks.TryAdd(filePath, chunk); + public TestSet(string directoryPath) + { + DirectoryPath = directoryPath; } + + public bool AddTestRootChunk(string filePath, Chunk chunk) + => _testRootChunks.TryAdd(filePath, chunk); } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TrickyTable.cs b/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TrickyTable.cs index acc10c7a..b9205904 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TrickyTable.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/TrickyTable.cs @@ -1,45 +1,44 @@ -using System; +namespace EVIL.Ceres.LanguageTests; + +using System; using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.TypeSystem; using EVIL.CommonTypes.TypeSystem; -namespace EVIL.Ceres.LanguageTests +public class TrickyTable : Table { - public class TrickyTable : Table - { - private int _indexCount; + private int _indexCount; - protected override DynamicValue OnIndex(DynamicValue key) + protected override DynamicValue OnIndex(DynamicValue key) + { + if (_indexCount++ < 3) { - if (_indexCount++ < 3) - { - return DynamicValue.Nil; - } + return DynamicValue.Nil; + } - if (key.Type == DynamicValueType.String && key.String == "d20") - { - return new(Random.Shared.Next(0, 21)); - } - - return base.OnIndex(key); + if (key.Type == DynamicValueType.String && key.String == "d20") + { + return new(Random.Shared.Next(0, 21)); } - protected override (DynamicValue Key, DynamicValue Value) OnBeforeSet(DynamicValue key, DynamicValue value) - { - if (key.Type == DynamicValueType.String && key.String == "d20") - return (DynamicValue.Nil, DynamicValue.Nil); + return base.OnIndex(key); + } - return base.OnBeforeSet(key, value); - } + protected override (DynamicValue Key, DynamicValue Value) OnBeforeSet(DynamicValue key, DynamicValue value) + { + if (key.Type == DynamicValueType.String && key.String == "d20") + return (DynamicValue.Nil, DynamicValue.Nil); - protected override bool OnContains(DynamicValue key) - { - if (key.Type == DynamicValueType.String && key.String == "d20") - { - return false; - } + return base.OnBeforeSet(key, value); + } - return base.OnContains(key); + protected override bool OnContains(DynamicValue key) + { + if (key.Type == DynamicValueType.String && key.String == "d20") + { + return false; } + + return base.OnContains(key); } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeEnvironment.cs b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeEnvironment.cs index 0c401bda..7afdb28f 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeEnvironment.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeEnvironment.cs @@ -1,86 +1,85 @@ +namespace EVIL.Ceres.RuntimeTests; + using EVIL.Ceres.ExecutionEngine; using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.Runtime; using NUnit.Framework; -namespace EVIL.Ceres.RuntimeTests +public class RuntimeEnvironment { - public class RuntimeEnvironment - { - private CeresVM _vm; - private EvilRuntime _evilRuntime; + private CeresVM _vm; + private EvilRuntime _evilRuntime; - [SetUp] - public void Setup() - { - _vm = new CeresVM(); - _evilRuntime = new EvilRuntime(_vm); - _vm.Start(); - } + [SetUp] + public void Setup() + { + _vm = new CeresVM(); + _evilRuntime = new EvilRuntime(_vm); + _vm.Start(); + } - [TearDown] - public void Teardown() - { - _vm.Dispose(); - _evilRuntime = null!; - } + [TearDown] + public void Teardown() + { + _vm.Dispose(); + _evilRuntime = null!; + } - [Test] - public void GlobalNumberRegistered() - { - var value = _evilRuntime.Register("testvalue", 21.37); + [Test] + public void GlobalNumberRegistered() + { + var value = _evilRuntime.Register("testvalue", 21.37); - Assert.That( - _vm.Global["testvalue"], - Is.EqualTo(value) - ); - } + Assert.That( + _vm.Global["testvalue"], + Is.EqualTo(value) + ); + } - [Test] - public void GlobalStringRegistered() - { - var value = _evilRuntime.Register("testvalue", "blah"); + [Test] + public void GlobalStringRegistered() + { + var value = _evilRuntime.Register("testvalue", "blah"); - Assert.That( - _vm.Global["testvalue"], - Is.EqualTo(value) - ); - } + Assert.That( + _vm.Global["testvalue"], + Is.EqualTo(value) + ); + } - [Test] - public void GlobalBooleanRegistered() - { - var value = _evilRuntime.Register("testvalue", true); + [Test] + public void GlobalBooleanRegistered() + { + var value = _evilRuntime.Register("testvalue", true); - Assert.That( - _vm.Global["testvalue"], - Is.EqualTo(value) - ); - } + Assert.That( + _vm.Global["testvalue"], + Is.EqualTo(value) + ); + } - [Test] - public void GlobalTableRegistered() - { - var t = new Table(); + [Test] + public void GlobalTableRegistered() + { + var t = new Table(); - var value = _evilRuntime.Register("testvalue", t); + var value = _evilRuntime.Register("testvalue", t); - Assert.That( - _vm.Global["testvalue"], - Is.EqualTo(value) - ); - } + Assert.That( + _vm.Global["testvalue"], + Is.EqualTo(value) + ); + } - [Test] - public void FullyQualifiedNumberRegistered() - { - var value = _evilRuntime.Register("__rt.values.TEST_VALUE", 21.37); + [Test] + public void FullyQualifiedNumberRegistered() + { + var value = _evilRuntime.Register("__rt.values.TEST_VALUE", 21.37); - Assert.That( - _vm.Global["__rt"].Table!["values"].Table!["TEST_VALUE"], - Is.EqualTo(value) - ); - } + Assert.That( + _vm.Global["__rt"].Table!["values"].Table!["TEST_VALUE"], + Is.EqualTo(value) + ); } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/ArrayModuleTest.cs b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/ArrayModuleTest.cs index 9e8ecb6a..f282b9d2 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/ArrayModuleTest.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/ArrayModuleTest.cs @@ -1,262 +1,262 @@ +namespace EVIL.Ceres.RuntimeTests.RuntimeModules; + +using static EVIL.Ceres.ExecutionEngine.TypeSystem.DynamicValue; + using EVIL.Ceres.Runtime.Modules; using EVIL.CommonTypes.TypeSystem; using NUnit.Framework; using Shouldly; -using static EVIL.Ceres.ExecutionEngine.TypeSystem.DynamicValue; -namespace EVIL.Ceres.RuntimeTests.RuntimeModules +public class ArrayModuleTest : ModuleTest { - public class ArrayModuleTest : ModuleTest + [Test] + public void IndexOf() { - [Test] - public void IndexOf() - { - var result = EvilTestResult( - "fn test() {" + - " val values = array() { 1, 2, 3, 'a string', false };" + - " ret array() {" + - " arr.index_of(values, 'a string')," + - " arr.index_of(values, 3)," + - " arr.index_of(values, false)" + - " };" + - "}" - ); + var result = EvilTestResult( + "fn test() {" + + " val values = array() { 1, 2, 3, 'a string', false };" + + " ret array() {" + + " arr.index_of(values, 'a string')," + + " arr.index_of(values, 3)," + + " arr.index_of(values, false)" + + " };" + + "}" + ); - result.Type.ShouldBe(DynamicValueType.Array); + result.Type.ShouldBe(DynamicValueType.Array); - var arr = result.Array!; - arr[0].ShouldBe(3); - arr[1].ShouldBe(2); - arr[2].ShouldBe(4); - } + var arr = result.Array!; + arr[0].ShouldBe(3); + arr[1].ShouldBe(2); + arr[2].ShouldBe(4); + } - [Test] - public void Fill() - { - var result = EvilTestResult( - "fn test() {" + - " val values = array(5);" + - " arr.fill(values, 'a string');" + - " ret values;" + - "}" - ); + [Test] + public void Fill() + { + var result = EvilTestResult( + "fn test() {" + + " val values = array(5);" + + " arr.fill(values, 'a string');" + + " ret values;" + + "}" + ); - result.Type.ShouldBe(DynamicValueType.Array); + result.Type.ShouldBe(DynamicValueType.Array); - var arr = result.Array!; - arr[0].ShouldBe("a string"); - arr[1].ShouldBe("a string"); - arr[2].ShouldBe("a string"); - arr[3].ShouldBe("a string"); - arr[4].ShouldBe("a string"); - } + var arr = result.Array!; + arr[0].ShouldBe("a string"); + arr[1].ShouldBe("a string"); + arr[2].ShouldBe("a string"); + arr[3].ShouldBe("a string"); + arr[4].ShouldBe("a string"); + } - [Test] - public void Resize() - { - var result = EvilTestResult( - "fn test() {" + - " val values = array() { 21.37 };" + - " ret {" + - " arr: values, /* remember tables and arrays are passed by ref */" + - " pre_resize_sz: #values," + - " resize_ret: arr.resize(values, 5)," + - " post_resize_sz: #values" + - " };" + - "}" - ); + [Test] + public void Resize() + { + var result = EvilTestResult( + "fn test() {" + + " val values = array() { 21.37 };" + + " ret {" + + " arr: values, /* remember tables and arrays are passed by ref */" + + " pre_resize_sz: #values," + + " resize_ret: arr.resize(values, 5)," + + " post_resize_sz: #values" + + " };" + + "}" + ); - result.Type.ShouldBe(DynamicValueType.Table); - var table = result.Table!; + result.Type.ShouldBe(DynamicValueType.Table); + var table = result.Table!; - table["pre_resize_sz"].ShouldBe(1); - table["resize_ret"].ShouldBe(5); - table["post_resize_sz"].ShouldBe(5); + table["pre_resize_sz"].ShouldBe(1); + table["resize_ret"].ShouldBe(5); + table["post_resize_sz"].ShouldBe(5); - table["arr"].Type.ShouldBe(DynamicValueType.Array); - var array = table["arr"].Array!; + table["arr"].Type.ShouldBe(DynamicValueType.Array); + var array = table["arr"].Array!; - array[0].ShouldBe(21.37); - array[1].ShouldBe(Nil); - array[2].ShouldBe(Nil); - array[3].ShouldBe(Nil); - array[4].ShouldBe(Nil); - } + array[0].ShouldBe(21.37); + array[1].ShouldBe(Nil); + array[2].ShouldBe(Nil); + array[3].ShouldBe(Nil); + array[4].ShouldBe(Nil); + } - [Test] - public void Push() - { - var result = EvilTestResult( - "fn test() {" + - " val values = array() { 2, 1, 3, 7 };" + - " arr.push(values, 0, 0, 0, 0);" + - "" + - " ret values;" + - "}" - ); + [Test] + public void Push() + { + var result = EvilTestResult( + "fn test() {" + + " val values = array() { 2, 1, 3, 7 };" + + " arr.push(values, 0, 0, 0, 0);" + + "" + + " ret values;" + + "}" + ); - result.Type.ShouldBe(DynamicValueType.Array); - var arr = result.Array!; + result.Type.ShouldBe(DynamicValueType.Array); + var arr = result.Array!; - arr.Length.ShouldBe(8); + arr.Length.ShouldBe(8); - arr[0].ShouldBe(2); - arr[1].ShouldBe(1); - arr[2].ShouldBe(3); - arr[3].ShouldBe(7); - arr[4].ShouldBe(0); - arr[5].ShouldBe(0); - arr[6].ShouldBe(0); - arr[7].ShouldBe(0); - } + arr[0].ShouldBe(2); + arr[1].ShouldBe(1); + arr[2].ShouldBe(3); + arr[3].ShouldBe(7); + arr[4].ShouldBe(0); + arr[5].ShouldBe(0); + arr[6].ShouldBe(0); + arr[7].ShouldBe(0); + } - [Test] - public void InsertFront() - { - var result = EvilTestResult( - "fn test() {" + - " val values = array() { 2, 1, 3, 7 };" + - " arr.insert(values, 0, 0, 0, 0, 0);" + - "" + - " ret values;" + - "}" - ); + [Test] + public void InsertFront() + { + var result = EvilTestResult( + "fn test() {" + + " val values = array() { 2, 1, 3, 7 };" + + " arr.insert(values, 0, 0, 0, 0, 0);" + + "" + + " ret values;" + + "}" + ); - result.Type.ShouldBe(DynamicValueType.Array); - var arr = result.Array!; + result.Type.ShouldBe(DynamicValueType.Array); + var arr = result.Array!; - arr.Length.ShouldBe(8); + arr.Length.ShouldBe(8); - arr[0].ShouldBe(0); - arr[1].ShouldBe(0); - arr[2].ShouldBe(0); - arr[3].ShouldBe(0); - arr[4].ShouldBe(2); - arr[5].ShouldBe(1); - arr[6].ShouldBe(3); - arr[7].ShouldBe(7); - } + arr[0].ShouldBe(0); + arr[1].ShouldBe(0); + arr[2].ShouldBe(0); + arr[3].ShouldBe(0); + arr[4].ShouldBe(2); + arr[5].ShouldBe(1); + arr[6].ShouldBe(3); + arr[7].ShouldBe(7); + } - [Test] - public void InsertMiddle() - { - var result = EvilTestResult( - "fn test() {" + - " val values = array() { 2, 1, 3, 7 };" + - " arr.insert(values, 2, 0, 0, 0, 0);" + - "" + - " ret values;" + - "}" - ); + [Test] + public void InsertMiddle() + { + var result = EvilTestResult( + "fn test() {" + + " val values = array() { 2, 1, 3, 7 };" + + " arr.insert(values, 2, 0, 0, 0, 0);" + + "" + + " ret values;" + + "}" + ); - result.Type.ShouldBe(DynamicValueType.Array); - var arr = result.Array!; + result.Type.ShouldBe(DynamicValueType.Array); + var arr = result.Array!; - arr.Length.ShouldBe(8); + arr.Length.ShouldBe(8); - arr[0].ShouldBe(2); - arr[1].ShouldBe(1); - arr[2].ShouldBe(0); - arr[3].ShouldBe(0); - arr[4].ShouldBe(0); - arr[5].ShouldBe(0); - arr[6].ShouldBe(3); - arr[7].ShouldBe(7); - } + arr[0].ShouldBe(2); + arr[1].ShouldBe(1); + arr[2].ShouldBe(0); + arr[3].ShouldBe(0); + arr[4].ShouldBe(0); + arr[5].ShouldBe(0); + arr[6].ShouldBe(3); + arr[7].ShouldBe(7); + } - [Test] - public void InsertBack() - { - var result = EvilTestResult( - "fn test() {" + - " val values = array() { 2, 1, 3, 7 };" + - " arr.insert(values, #values, 0, 0, 0, 0);" + - "" + - " ret values;" + - "}" - ); + [Test] + public void InsertBack() + { + var result = EvilTestResult( + "fn test() {" + + " val values = array() { 2, 1, 3, 7 };" + + " arr.insert(values, #values, 0, 0, 0, 0);" + + "" + + " ret values;" + + "}" + ); - result.Type.ShouldBe(DynamicValueType.Array); - var arr = result.Array!; + result.Type.ShouldBe(DynamicValueType.Array); + var arr = result.Array!; - arr.Length.ShouldBe(8); + arr.Length.ShouldBe(8); - arr[0].ShouldBe(2); - arr[1].ShouldBe(1); - arr[2].ShouldBe(3); - arr[3].ShouldBe(7); - arr[4].ShouldBe(0); - arr[5].ShouldBe(0); - arr[6].ShouldBe(0); - arr[7].ShouldBe(0); - } + arr[0].ShouldBe(2); + arr[1].ShouldBe(1); + arr[2].ShouldBe(3); + arr[3].ShouldBe(7); + arr[4].ShouldBe(0); + arr[5].ShouldBe(0); + arr[6].ShouldBe(0); + arr[7].ShouldBe(0); + } - [Test] - public void RightShift() - { - var result = EvilTestResult( - "fn test() {" + - " val values = array() { 2, 1, 3, 7 };" + - "" + - " ret {" + - " shifted: array() {" + - " arr.rsh(values)," + - " arr.rsh(values)" + - " }," + - " values: values" + - " };" + - "}" - ); + [Test] + public void RightShift() + { + var result = EvilTestResult( + "fn test() {" + + " val values = array() { 2, 1, 3, 7 };" + + "" + + " ret {" + + " shifted: array() {" + + " arr.rsh(values)," + + " arr.rsh(values)" + + " }," + + " values: values" + + " };" + + "}" + ); - result.Type.ShouldBe(DynamicValueType.Table); + result.Type.ShouldBe(DynamicValueType.Table); - var tbl = result.Table!; - tbl["shifted"].Type.ShouldBe(DynamicValueType.Array); + var tbl = result.Table!; + tbl["shifted"].Type.ShouldBe(DynamicValueType.Array); - var shiftedValues = tbl["shifted"].Array!; - shiftedValues.Length.ShouldBe(2); - shiftedValues[0].ShouldBe(7); - shiftedValues[1].ShouldBe(3); + var shiftedValues = tbl["shifted"].Array!; + shiftedValues.Length.ShouldBe(2); + shiftedValues[0].ShouldBe(7); + shiftedValues[1].ShouldBe(3); - tbl["values"].Type.ShouldBe(DynamicValueType.Array); - var remainingValues = tbl["values"].Array!; - remainingValues.Length.ShouldBe(2); - remainingValues[0].ShouldBe(2); - remainingValues[1].ShouldBe(1); - } + tbl["values"].Type.ShouldBe(DynamicValueType.Array); + var remainingValues = tbl["values"].Array!; + remainingValues.Length.ShouldBe(2); + remainingValues[0].ShouldBe(2); + remainingValues[1].ShouldBe(1); + } - [Test] - public void LeftShift() - { - var result = EvilTestResult( - "fn test() {" + - " val values = array() { 2, 1, 3, 7 };" + - "" + - " ret {" + - " shifted: array() {" + - " arr.lsh(values)," + - " arr.lsh(values)" + - " }," + - " values: values" + - " };" + - "}" - ); + [Test] + public void LeftShift() + { + var result = EvilTestResult( + "fn test() {" + + " val values = array() { 2, 1, 3, 7 };" + + "" + + " ret {" + + " shifted: array() {" + + " arr.lsh(values)," + + " arr.lsh(values)" + + " }," + + " values: values" + + " };" + + "}" + ); - result.Type.ShouldBe(DynamicValueType.Table); + result.Type.ShouldBe(DynamicValueType.Table); - var tbl = result.Table!; - tbl["shifted"].Type.ShouldBe(DynamicValueType.Array); + var tbl = result.Table!; + tbl["shifted"].Type.ShouldBe(DynamicValueType.Array); - var shiftedValues = tbl["shifted"].Array!; - shiftedValues.Length.ShouldBe(2); - shiftedValues[0].ShouldBe(2); - shiftedValues[1].ShouldBe(1); + var shiftedValues = tbl["shifted"].Array!; + shiftedValues.Length.ShouldBe(2); + shiftedValues[0].ShouldBe(2); + shiftedValues[1].ShouldBe(1); - tbl["values"].Type.ShouldBe(DynamicValueType.Array); - var remainingValues = tbl["values"].Array!; - remainingValues.Length.ShouldBe(2); - remainingValues[0].ShouldBe(3); - remainingValues[1].ShouldBe(7); - } + tbl["values"].Type.ShouldBe(DynamicValueType.Array); + var remainingValues = tbl["values"].Array!; + remainingValues.Length.ShouldBe(2); + remainingValues[0].ShouldBe(3); + remainingValues[1].ShouldBe(7); } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/CoreModuleTest.cs b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/CoreModuleTest.cs index a7c74a50..a24e8e30 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/CoreModuleTest.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/CoreModuleTest.cs @@ -1,19 +1,18 @@ -using System; +namespace EVIL.Ceres.RuntimeTests.RuntimeModules; + +using System; using EVIL.Ceres.Runtime; using EVIL.Ceres.Runtime.Modules; using NUnit.Framework; using Shouldly; -namespace EVIL.Ceres.RuntimeTests.RuntimeModules +public class CoreModuleTest : ModuleTest { - public class CoreModuleTest : ModuleTest + [Test] + public void CoreFailTerminatesExecution() { - [Test] - public void CoreFailTerminatesExecution() - { - var e = Should.Throw(() => EvilTestResult("(fn -> core.fail(':( your computer ran'))();")); - e.InnerException.ShouldBeOfType(); - ((UserFailException)e.InnerException).Message.ShouldBe(":( your computer ran"); - } + var e = Should.Throw(() => EvilTestResult("(fn -> core.fail(':( your computer ran'))();")); + e.InnerException.ShouldBeOfType(); + ((UserFailException)e.InnerException).Message.ShouldBe(":( your computer ran"); } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/DebugModuleTest.cs b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/DebugModuleTest.cs index f2781b33..e374e4e9 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/DebugModuleTest.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/DebugModuleTest.cs @@ -1,78 +1,77 @@ -using EVIL.Ceres.ExecutionEngine.Collections; +namespace EVIL.Ceres.RuntimeTests.RuntimeModules; + +using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.Runtime.Modules; using NUnit.Framework; using Shouldly; -namespace EVIL.Ceres.RuntimeTests.RuntimeModules +public class DebugModuleTest : ModuleTest { - public class DebugModuleTest : ModuleTest + [Test] + public void StackTrace() { - [Test] - public void StackTrace() - { - var t = EvilTestResult( - "fn test(a = 1, b = 2, c = 3) -> debug.strace(true);" - ).Array!; - var frame = (Table)t[0]; + var t = EvilTestResult( + "fn test(a = 1, b = 2, c = 3) -> debug.strace(true);" + ).Array!; + var frame = (Table)t[0]; - frame["is_script"].ShouldBe(true); - frame["fn_name"].ShouldBe("test"); - frame["def_on_line"].ShouldBe(1); + frame["is_script"].ShouldBe(true); + frame["fn_name"].ShouldBe("test"); + frame["def_on_line"].ShouldBe(1); - var args = (Table)frame["args"]; - args[0].ShouldBe(1); - args[1].ShouldBe(2); - args[2].ShouldBe(3); - } + var args = (Table)frame["args"]; + args[0].ShouldBe(1); + args[1].ShouldBe(2); + args[2].ShouldBe(3); + } - [Test] - public void StackTraceString() - { - var s = (string)EvilTestResult( - "fn nested_2() {\n" + - " ret debug.strace_s();\n" + - "}\n" + - "" + - "fn nested_1() {\n" + - " ret nested_2();\n" + - "}\n" + - "" + - "fn nested_0() {\n" + - " ret nested_1();\n" + - "}\n" + - "" + - "fn test() {\n" + - " val test = 20;\n" + - " val test2 = 21;\n" + - "\n" + - " ret nested_0();\n" + - "}\n" - ); + [Test] + public void StackTraceString() + { + var s = (string)EvilTestResult( + "fn nested_2() {\n" + + " ret debug.strace_s();\n" + + "}\n" + + "" + + "fn nested_1() {\n" + + " ret nested_2();\n" + + "}\n" + + "" + + "fn nested_0() {\n" + + " ret nested_1();\n" + + "}\n" + + "" + + "fn test() {\n" + + " val test = 20;\n" + + " val test2 = 21;\n" + + "\n" + + " ret nested_0();\n" + + "}\n" + ); - s.ShouldContain( - "at clr!EVIL.EVIL.Ceres.Runtime.Modules.DebugModule::StackTraceString", - Case.Sensitive - ); + s.ShouldContain( + "at clr!EVIL.EVIL.Ceres.Runtime.Modules.DebugModule::StackTraceString", + Case.Sensitive + ); - s.ShouldContain( - "at nested_2 in !module_test_file!: line 2", - Case.Sensitive - ); + s.ShouldContain( + "at nested_2 in !module_test_file!: line 2", + Case.Sensitive + ); - s.ShouldContain( - "at nested_1 in !module_test_file!: line 5", - Case.Sensitive - ); + s.ShouldContain( + "at nested_1 in !module_test_file!: line 5", + Case.Sensitive + ); - s.ShouldContain( - "at nested_0 in !module_test_file!: line 8", - Case.Sensitive - ); + s.ShouldContain( + "at nested_0 in !module_test_file!: line 8", + Case.Sensitive + ); - s.ShouldContain( - "at test in !module_test_file!: line 14", - Case.Sensitive - ); - } + s.ShouldContain( + "at test in !module_test_file!: line 14", + Case.Sensitive + ); } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/EvilModuleTest.cs b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/EvilModuleTest.cs index 8af2e9df..09126dae 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/EvilModuleTest.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/EvilModuleTest.cs @@ -1,87 +1,87 @@ -using EVIL.Ceres.ExecutionEngine.Collections; +namespace EVIL.Ceres.RuntimeTests.RuntimeModules; + +using static EVIL.Ceres.ExecutionEngine.TypeSystem.DynamicValue; + +using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.Runtime.Modules; using EVIL.CommonTypes.TypeSystem; using NUnit.Framework; using Shouldly; -using static EVIL.Ceres.ExecutionEngine.TypeSystem.DynamicValue; -namespace EVIL.Ceres.RuntimeTests.RuntimeModules +public class EvilModuleTest : ModuleTest { - public class EvilModuleTest : ModuleTest + [Test] + public void Compile() { - [Test] - public void Compile() - { - var t = EvilTestResult( - "fn test() {" + - " val result = evil.compile('fn test() {" + - " ret \"i was compiled from within evil :dobry_jezu:\";" + - " }');" + - "" + - " ret {" + - " script_table: result," + - " test_result: result.chunk['test']()" + - " };" + - "}" - ).Table!; + var t = EvilTestResult( + "fn test() {" + + " val result = evil.compile('fn test() {" + + " ret \"i was compiled from within evil :dobry_jezu:\";" + + " }');" + + "" + + " ret {" + + " script_table: result," + + " test_result: result.chunk['test']()" + + " };" + + "}" + ).Table!; - var scriptTable = (Table)t["script_table"]; - var testResult = (string)t["test_result"]; + var scriptTable = (Table)t["script_table"]; + var testResult = (string)t["test_result"]; - scriptTable["success"].ShouldBe(true); - testResult.ShouldBe("i was compiled from within evil :dobry_jezu:"); - } + scriptTable["success"].ShouldBe(true); + testResult.ShouldBe("i was compiled from within evil :dobry_jezu:"); + } - [Test] - public void Reflect() - { - var t = EvilTestResult( - "#[attrib] fn reflected(a, b = 'hi', rw c = 21) {" + - " val local_1 = 12;" + - " rw val local_2 = 10;" + - "}" + - "" + - "fn test() -> evil.reflect(reflected);" - ).Table!; + [Test] + public void Reflect() + { + var t = EvilTestResult( + "#[attrib] fn reflected(a, b = 'hi', rw c = 21) {" + + " val local_1 = 12;" + + " rw val local_2 = 10;" + + "}" + + "" + + "fn test() -> evil.reflect(reflected);" + ).Table!; - t["name"].ShouldBe("reflected"); - t["attributes"].Type.ShouldBe(DynamicValueType.Array); + t["name"].ShouldBe("reflected"); + t["attributes"].Type.ShouldBe(DynamicValueType.Array); - var attributes = t["attributes"].Array!; - attributes[0].Type.ShouldBe(DynamicValueType.Table); - attributes[0].Table!["name"].ShouldBe("attrib"); + var attributes = t["attributes"].Array!; + attributes[0].Type.ShouldBe(DynamicValueType.Table); + attributes[0].Table!["name"].ShouldBe("attrib"); - t["local_info"].Type.ShouldBe(DynamicValueType.Array); - var locals = t["local_info"].Array!; - locals[0].Type.ShouldBe(DynamicValueType.Table); - locals[0].Table!["id"].ShouldBe(0); - locals[0].Table!["name"].ShouldBe("local_1"); - locals[0].Table!["is_rw"].ShouldBe(false); + t["local_info"].Type.ShouldBe(DynamicValueType.Array); + var locals = t["local_info"].Array!; + locals[0].Type.ShouldBe(DynamicValueType.Table); + locals[0].Table!["id"].ShouldBe(0); + locals[0].Table!["name"].ShouldBe("local_1"); + locals[0].Table!["is_rw"].ShouldBe(false); - locals[1].Type.ShouldBe(DynamicValueType.Table); - locals[1].Table!["id"].ShouldBe(1); - locals[1].Table!["name"].ShouldBe("local_2"); - locals[1].Table!["is_rw"].ShouldBe(true); + locals[1].Type.ShouldBe(DynamicValueType.Table); + locals[1].Table!["id"].ShouldBe(1); + locals[1].Table!["name"].ShouldBe("local_2"); + locals[1].Table!["is_rw"].ShouldBe(true); - t["param_info"].Type.ShouldBe(DynamicValueType.Array); - var parameters = t["param_info"].Array!; - parameters[0].Type.ShouldBe(DynamicValueType.Table); - parameters[0].Table!["id"].ShouldBe(0); - parameters[0].Table!["name"].ShouldBe("a"); - parameters[0].Table!["default_value"].ShouldBe(Nil); - parameters[0].Table!["is_rw"].ShouldBe(false); + t["param_info"].Type.ShouldBe(DynamicValueType.Array); + var parameters = t["param_info"].Array!; + parameters[0].Type.ShouldBe(DynamicValueType.Table); + parameters[0].Table!["id"].ShouldBe(0); + parameters[0].Table!["name"].ShouldBe("a"); + parameters[0].Table!["default_value"].ShouldBe(Nil); + parameters[0].Table!["is_rw"].ShouldBe(false); - parameters[1].Type.ShouldBe(DynamicValueType.Table); - parameters[1].Table!["id"].ShouldBe(1); - parameters[1].Table!["name"].ShouldBe("b"); - parameters[1].Table!["default_value"].ShouldBe("hi"); - parameters[1].Table!["is_rw"].ShouldBe(false); + parameters[1].Type.ShouldBe(DynamicValueType.Table); + parameters[1].Table!["id"].ShouldBe(1); + parameters[1].Table!["name"].ShouldBe("b"); + parameters[1].Table!["default_value"].ShouldBe("hi"); + parameters[1].Table!["is_rw"].ShouldBe(false); - parameters[2].Type.ShouldBe(DynamicValueType.Table); - parameters[2].Table!["id"].ShouldBe(2); - parameters[2].Table!["name"].ShouldBe("c"); - parameters[2].Table!["default_value"].ShouldBe(21); - parameters[2].Table!["is_rw"].ShouldBe(true); - } + parameters[2].Type.ShouldBe(DynamicValueType.Table); + parameters[2].Table!["id"].ShouldBe(2); + parameters[2].Table!["name"].ShouldBe("c"); + parameters[2].Table!["default_value"].ShouldBe(21); + parameters[2].Table!["is_rw"].ShouldBe(true); } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/FsModuleTest.Directory.cs b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/FsModuleTest.Directory.cs index 39ac37b7..216fc84f 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/FsModuleTest.Directory.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/FsModuleTest.Directory.cs @@ -1,290 +1,289 @@ +namespace EVIL.Ceres.RuntimeTests.RuntimeModules; + using System.Collections.Generic; using System.IO; using EVIL.CommonTypes.TypeSystem; using NUnit.Framework; using Shouldly; -namespace EVIL.Ceres.RuntimeTests.RuntimeModules +public partial class FsModuleTest { - public partial class FsModuleTest + [Test] + public void DirectoryExists() { - [Test] - public void DirectoryExists() - { - var info = Directory.CreateDirectory( - Path.Combine(Path.GetTempPath(), "evil_test_temp_dir") - ); + var info = Directory.CreateDirectory( + Path.Combine(Path.GetTempPath(), "evil_test_temp_dir") + ); - var result = EvilTestResult( - $"fn test() -> fs.dir.exists('{info.FullName.Replace('\\', '/')}');" - ); + var result = EvilTestResult( + $"fn test() -> fs.dir.exists('{info.FullName.Replace('\\', '/')}');" + ); + + Directory.Delete(info.FullName); + result.ShouldBe(true); + } - Directory.Delete(info.FullName); - result.ShouldBe(true); + [Test] + public void DirectoryCreate() + { + var path = Path.Combine( + Path.GetTempPath(), + "evil_test_temp_dir" + ).Replace('\\', '/'); + + var result = EvilTestResult( + $"fn test() -> fs.dir.create('{path}');" + ); + + result.Type.ShouldBe(DynamicValueType.Table); + var tbl = result.Table!; + + Directory.Exists(tbl["path"].String!).ShouldBe(true); + Directory.Delete(path); + } + + [Test] + public void DirectoryDelete() + { + var path = Path.Combine( + Path.GetTempPath(), + "evil_test_temp_dir" + ).Replace('\\', '/'); + + Directory.CreateDirectory(path); + + var result = EvilTestResult( + $"fn test() -> fs.dir.delete('{path}');" + ); + + result.ShouldBe(true); + Directory.Exists(path).ShouldBe(false); + } + + [Test] + public void DirectoryGetFiles() + { + var dirPath = Path.Combine( + Path.GetTempPath(), + "evil_test_temp_dir" + ).Replace('\\', '/'); + + try + { + Directory.Delete(dirPath, true); + } + catch + { + /* Ignore */ } - [Test] - public void DirectoryCreate() + Directory.CreateDirectory(dirPath); + + var fileNames = new List(); + for (var i = 0; i < 10; i++) { - var path = Path.Combine( - Path.GetTempPath(), - "evil_test_temp_dir" - ).Replace('\\', '/'); + var name = Path.GetRandomFileName(); + var filePath = Path.Combine(dirPath, name).Replace('\\', '/'); - var result = EvilTestResult( - $"fn test() -> fs.dir.create('{path}');" - ); + fileNames.Add(filePath); + File.Create(filePath).Dispose(); + } - result.Type.ShouldBe(DynamicValueType.Table); - var tbl = result.Table!; + var value = EvilTestResult( + $"fn test() -> fs.dir.get_files('{dirPath}');" + ); - Directory.Exists(tbl["path"].String!).ShouldBe(true); - Directory.Delete(path); + value.Type.ShouldBe(DynamicValueType.Array); + var array = value.Array!; + array.Length.ShouldBe(10); + + for (var i = 0; i < array.Length; i++) + { + array[i].Type.ShouldBe(DynamicValueType.String); + fileNames.ShouldContain(array[i].String); } - [Test] - public void DirectoryDelete() + Directory.Delete(dirPath, true); + } + + [Test] + public void DirectoryGetDirectories() + { + var dirPath = Path.Combine( + Path.GetTempPath(), + "evil_test_temp_dir" + ).Replace('\\', '/'); + + try { - var path = Path.Combine( - Path.GetTempPath(), - "evil_test_temp_dir" - ).Replace('\\', '/'); + Directory.Delete(dirPath, true); + } + catch + { + /* Ignore */ + } - Directory.CreateDirectory(path); + Directory.CreateDirectory(dirPath); - var result = EvilTestResult( - $"fn test() -> fs.dir.delete('{path}');" - ); + var dirNames = new List(); + for (var i = 0; i < 10; i++) + { + var name = Path.GetRandomFileName(); + var subDirPath = Path.Combine(dirPath, name).Replace('\\', '/'); - result.ShouldBe(true); - Directory.Exists(path).ShouldBe(false); + dirNames.Add(subDirPath); + Directory.CreateDirectory(subDirPath); } - [Test] - public void DirectoryGetFiles() + var value = EvilTestResult( + $"fn test() -> fs.dir.get_dirs('{dirPath}');" + ); + + value.Type.ShouldBe(DynamicValueType.Array); + var array = value.Array!; + array.Length.ShouldBe(10); + + for (var i = 0; i < array.Length; i++) { - var dirPath = Path.Combine( - Path.GetTempPath(), - "evil_test_temp_dir" - ).Replace('\\', '/'); - - try - { - Directory.Delete(dirPath, true); - } - catch - { - /* Ignore */ - } - - Directory.CreateDirectory(dirPath); - - var fileNames = new List(); - for (var i = 0; i < 10; i++) - { - var name = Path.GetRandomFileName(); - var filePath = Path.Combine(dirPath, name).Replace('\\', '/'); - - fileNames.Add(filePath); - File.Create(filePath).Dispose(); - } - - var value = EvilTestResult( - $"fn test() -> fs.dir.get_files('{dirPath}');" - ); + array[i].Type.ShouldBe(DynamicValueType.String); + dirNames.ShouldContain(array[i].String); + } + + Directory.Delete(dirPath, true); + } - value.Type.ShouldBe(DynamicValueType.Array); - var array = value.Array!; - array.Length.ShouldBe(10); + [Test] + public void DirectoryCopy() + { + var dirPath = Path.Combine( + Path.GetTempPath(), + "evil_test_temp_dir" + ).Replace('\\', '/'); - for (var i = 0; i < array.Length; i++) - { - array[i].Type.ShouldBe(DynamicValueType.String); - fileNames.ShouldContain(array[i].String); - } + var dirPath2 = Path.Combine( + Path.GetTempPath(), + "evil_test_temp_dir2" + ).Replace('\\', '/'); + try + { Directory.Delete(dirPath, true); } - - [Test] - public void DirectoryGetDirectories() + catch { - var dirPath = Path.Combine( - Path.GetTempPath(), - "evil_test_temp_dir" - ).Replace('\\', '/'); - - try - { - Directory.Delete(dirPath, true); - } - catch - { - /* Ignore */ - } - - Directory.CreateDirectory(dirPath); - - var dirNames = new List(); - for (var i = 0; i < 10; i++) - { - var name = Path.GetRandomFileName(); - var subDirPath = Path.Combine(dirPath, name).Replace('\\', '/'); - - dirNames.Add(subDirPath); - Directory.CreateDirectory(subDirPath); - } - - var value = EvilTestResult( - $"fn test() -> fs.dir.get_dirs('{dirPath}');" - ); + /* Ignore */ + } + + try + { + Directory.Delete(dirPath2, true); + } + catch + { + /* Ignore */ + } - value.Type.ShouldBe(DynamicValueType.Array); - var array = value.Array!; - array.Length.ShouldBe(10); + Directory.CreateDirectory(dirPath); - for (var i = 0; i < array.Length; i++) - { - array[i].Type.ShouldBe(DynamicValueType.String); - dirNames.ShouldContain(array[i].String); - } + var fileNames = new List(); + for (var i = 0; i < 10; i++) + { + var name = Path.GetRandomFileName(); + var filePath = Path.Combine(dirPath, name).Replace('\\', '/'); - Directory.Delete(dirPath, true); + fileNames.Add(filePath); + File.Create(filePath).Dispose(); } - [Test] - public void DirectoryCopy() + var value = EvilTestResult( + $"fn test() -> fs.dir.copy(" + + $" '{dirPath}'," + + $" '{dirPath2}'" + + $");" + ); + + value.Type.ShouldBe(DynamicValueType.Boolean); + value.ShouldBe(true); + + var containsAllFiles = true; + for (var i = 0; i < fileNames.Count; i++) { - var dirPath = Path.Combine( - Path.GetTempPath(), - "evil_test_temp_dir" - ).Replace('\\', '/'); - - var dirPath2 = Path.Combine( - Path.GetTempPath(), - "evil_test_temp_dir2" - ).Replace('\\', '/'); - - try - { - Directory.Delete(dirPath, true); - } - catch - { - /* Ignore */ - } - - try - { - Directory.Delete(dirPath2, true); - } - catch - { - /* Ignore */ - } - - Directory.CreateDirectory(dirPath); - - var fileNames = new List(); - for (var i = 0; i < 10; i++) - { - var name = Path.GetRandomFileName(); - var filePath = Path.Combine(dirPath, name).Replace('\\', '/'); - - fileNames.Add(filePath); - File.Create(filePath).Dispose(); - } - - var value = EvilTestResult( - $"fn test() -> fs.dir.copy(" + - $" '{dirPath}'," + - $" '{dirPath2}'" + - $");" + containsAllFiles &= File.Exists( + Path.Combine(dirPath2, fileNames[i] + ) ); + } - value.Type.ShouldBe(DynamicValueType.Boolean); - value.ShouldBe(true); + containsAllFiles.ShouldBe(true); - var containsAllFiles = true; - for (var i = 0; i < fileNames.Count; i++) - { - containsAllFiles &= File.Exists( - Path.Combine(dirPath2, fileNames[i] - ) - ); - } + Directory.Delete(dirPath, true); + Directory.Delete(dirPath2, true); + } + + [Test] + public void DirectoryMove() + { + var dirPath = Path.Combine( + Path.GetTempPath(), + "evil_test_temp_dir" + ).Replace('\\', '/'); - containsAllFiles.ShouldBe(true); + var dirPath2 = Path.Combine( + Path.GetTempPath(), + "evil_test_temp_dir2" + ).Replace('\\', '/'); + try + { Directory.Delete(dirPath, true); + } + catch + { + /* Ignore */ + } + + try + { Directory.Delete(dirPath2, true); } - - [Test] - public void DirectoryMove() + catch { - var dirPath = Path.Combine( - Path.GetTempPath(), - "evil_test_temp_dir" - ).Replace('\\', '/'); - - var dirPath2 = Path.Combine( - Path.GetTempPath(), - "evil_test_temp_dir2" - ).Replace('\\', '/'); - - try - { - Directory.Delete(dirPath, true); - } - catch - { - /* Ignore */ - } - - try - { - Directory.Delete(dirPath2, true); - } - catch - { - /* Ignore */ - } - - Directory.CreateDirectory(dirPath); - - var fileNames = new List(); - for (var i = 0; i < 10; i++) - { - var name = Path.GetRandomFileName(); - var filePath = Path.Combine(dirPath, name).Replace('\\', '/'); - - fileNames.Add(filePath); - File.Create(filePath).Dispose(); - } - - var value = EvilTestResult( - $"fn test() -> fs.dir.move(" + - $" '{dirPath}'," + - $" '{dirPath2}'" + - $");" - ); + /* Ignore */ + } - value.Type.ShouldBe(DynamicValueType.Boolean); - value.ShouldBe(true); + Directory.CreateDirectory(dirPath); - Directory.Exists(dirPath).ShouldBe(false); + var fileNames = new List(); + for (var i = 0; i < 10; i++) + { + var name = Path.GetRandomFileName(); + var filePath = Path.Combine(dirPath, name).Replace('\\', '/'); - var containsAllFiles = true; - for (var i = 0; i < fileNames.Count; i++) - { - containsAllFiles &= File.Exists( - Path.Combine(dirPath2, Path.GetFileName(fileNames[i])!) - ); - } + fileNames.Add(filePath); + File.Create(filePath).Dispose(); + } - containsAllFiles.ShouldBe(true); - Directory.Delete(dirPath2, true); + var value = EvilTestResult( + $"fn test() -> fs.dir.move(" + + $" '{dirPath}'," + + $" '{dirPath2}'" + + $");" + ); + + value.Type.ShouldBe(DynamicValueType.Boolean); + value.ShouldBe(true); + + Directory.Exists(dirPath).ShouldBe(false); + + var containsAllFiles = true; + for (var i = 0; i < fileNames.Count; i++) + { + containsAllFiles &= File.Exists( + Path.Combine(dirPath2, Path.GetFileName(fileNames[i])!) + ); } + + containsAllFiles.ShouldBe(true); + Directory.Delete(dirPath2, true); } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/FsModuleTest.File.cs b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/FsModuleTest.File.cs index a0623356..db2a94e8 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/FsModuleTest.File.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/FsModuleTest.File.cs @@ -1,3 +1,5 @@ +namespace EVIL.Ceres.RuntimeTests.RuntimeModules; + using System; using System.IO; using System.Text; @@ -5,399 +7,396 @@ using NUnit.Framework; using Shouldly; -namespace EVIL.Ceres.RuntimeTests.RuntimeModules +public partial class FsModuleTest { - public partial class FsModuleTest + [Test] + public void FileExists() { - [Test] - public void FileExists() - { - var tmpPath = Path.Combine( - Path.GetTempPath(), - Path.GetRandomFileName() - ).Replace('\\', '/'); + var tmpPath = Path.Combine( + Path.GetTempPath(), + Path.GetRandomFileName() + ).Replace('\\', '/'); - File.Create(tmpPath).Dispose(); + File.Create(tmpPath).Dispose(); - var result = EvilTestResult( - $"fn test() -> fs.file.exists('{tmpPath}');" - ); + var result = EvilTestResult( + $"fn test() -> fs.file.exists('{tmpPath}');" + ); - File.Delete(tmpPath); + File.Delete(tmpPath); - result.Type.ShouldBe(DynamicValueType.Boolean); - result.ShouldBe(true); - } + result.Type.ShouldBe(DynamicValueType.Boolean); + result.ShouldBe(true); + } - [Test] - public void FileDelete() - { - var tmpPath = Path.Combine( - Path.GetTempPath(), - Path.GetRandomFileName() - ).Replace('\\', '/'); + [Test] + public void FileDelete() + { + var tmpPath = Path.Combine( + Path.GetTempPath(), + Path.GetRandomFileName() + ).Replace('\\', '/'); - File.Create(tmpPath).Dispose(); + File.Create(tmpPath).Dispose(); - var result = EvilTestResult( - $"fn test() -> fs.file.delete('{tmpPath}');" - ); + var result = EvilTestResult( + $"fn test() -> fs.file.delete('{tmpPath}');" + ); - result.Type.ShouldBe(DynamicValueType.Boolean); - result.ShouldBe(true); - File.Exists(tmpPath).ShouldBe(false); - } + result.Type.ShouldBe(DynamicValueType.Boolean); + result.ShouldBe(true); + File.Exists(tmpPath).ShouldBe(false); + } - [Test] - public void FileCopy() - { - var tmpPath = Path.Combine( - Path.GetTempPath(), - Path.GetRandomFileName() - ).Replace('\\', '/'); + [Test] + public void FileCopy() + { + var tmpPath = Path.Combine( + Path.GetTempPath(), + Path.GetRandomFileName() + ).Replace('\\', '/'); - var tmpPath2 = tmpPath + "2"; + var tmpPath2 = tmpPath + "2"; - File.Create(tmpPath).Dispose(); - - var result = EvilTestResult( - $"fn test() -> fs.file.copy(" + - $" '{tmpPath}'," + - $" '{tmpPath2}'" + - $");" - ); + File.Create(tmpPath).Dispose(); + + var result = EvilTestResult( + $"fn test() -> fs.file.copy(" + + $" '{tmpPath}'," + + $" '{tmpPath2}'" + + $");" + ); - result.Type.ShouldBe(DynamicValueType.Boolean); - result.ShouldBe(true); + result.Type.ShouldBe(DynamicValueType.Boolean); + result.ShouldBe(true); - File.Exists(tmpPath).ShouldBe(true); - File.Exists(tmpPath2).ShouldBe(true); + File.Exists(tmpPath).ShouldBe(true); + File.Exists(tmpPath2).ShouldBe(true); - File.Delete(tmpPath); - File.Delete(tmpPath2); - } + File.Delete(tmpPath); + File.Delete(tmpPath2); + } - [Test] - public void FileMove() - { - var tmpPath = Path.Combine( - Path.GetTempPath(), - Path.GetRandomFileName() - ).Replace('\\', '/'); + [Test] + public void FileMove() + { + var tmpPath = Path.Combine( + Path.GetTempPath(), + Path.GetRandomFileName() + ).Replace('\\', '/'); - var tmpPath2 = tmpPath + "2"; + var tmpPath2 = tmpPath + "2"; - File.Create(tmpPath).Dispose(); - - var result = EvilTestResult( - $"fn test() -> fs.file.move(" + - $" '{tmpPath}'," + - $" '{tmpPath2}'" + - $");" - ); + File.Create(tmpPath).Dispose(); + + var result = EvilTestResult( + $"fn test() -> fs.file.move(" + + $" '{tmpPath}'," + + $" '{tmpPath2}'" + + $");" + ); - result.Type.ShouldBe(DynamicValueType.Boolean); - result.ShouldBe(true); + result.Type.ShouldBe(DynamicValueType.Boolean); + result.ShouldBe(true); - File.Exists(tmpPath).ShouldBe(false); - File.Exists(tmpPath2).ShouldBe(true); + File.Exists(tmpPath).ShouldBe(false); + File.Exists(tmpPath2).ShouldBe(true); - File.Delete(tmpPath2); - } + File.Delete(tmpPath2); + } + + [Test] + public void FileLines() + { + var tmpPath = Path.Combine( + Path.GetTempPath(), + Path.GetRandomFileName() + ).Replace('\\', '/'); - [Test] - public void FileLines() + using (var sw = new StreamWriter(tmpPath)) { - var tmpPath = Path.Combine( - Path.GetTempPath(), - Path.GetRandomFileName() - ).Replace('\\', '/'); - - using (var sw = new StreamWriter(tmpPath)) - { - sw.WriteLine("line 1"); - sw.WriteLine("line 2"); - sw.WriteLine("line 3"); - } - - var result = EvilTestResult( - $"fn test() -> fs.file.get_lines('{tmpPath}');" - ); - - result.Type.ShouldBe(DynamicValueType.Array); - - var array = result.Array!; - array.Length.ShouldBe(3); + sw.WriteLine("line 1"); + sw.WriteLine("line 2"); + sw.WriteLine("line 3"); + } + + var result = EvilTestResult( + $"fn test() -> fs.file.get_lines('{tmpPath}');" + ); + + result.Type.ShouldBe(DynamicValueType.Array); - for (var i = 0; i < array.Length; i++) - { - array[i].ShouldBe($"line {i+1}"); - } + var array = result.Array!; + array.Length.ShouldBe(3); - File.Delete(tmpPath); + for (var i = 0; i < array.Length; i++) + { + array[i].ShouldBe($"line {i+1}"); } + + File.Delete(tmpPath); + } - [Test] - public void FileOpen() - { - var tmpPath = Path.Combine( - Path.GetTempPath(), - Path.GetRandomFileName() - ).Replace('\\', '/'); + [Test] + public void FileOpen() + { + var tmpPath = Path.Combine( + Path.GetTempPath(), + Path.GetRandomFileName() + ).Replace('\\', '/'); - File.Create(tmpPath).Dispose(); + File.Create(tmpPath).Dispose(); - var result = EvilTestResult( - $"fn test() -> fs.file.open('{tmpPath}');" - ); + var result = EvilTestResult( + $"fn test() -> fs.file.open('{tmpPath}');" + ); - result.Type.ShouldBe(DynamicValueType.NativeObject); - result.NativeObject.ShouldBeAssignableTo(); + result.Type.ShouldBe(DynamicValueType.NativeObject); + result.NativeObject.ShouldBeAssignableTo(); - ((Stream)result.NativeObject!).Dispose(); + ((Stream)result.NativeObject!).Dispose(); - File.Delete(tmpPath); - } + File.Delete(tmpPath); + } - [Test] - public void FileClose() - { - var tmpPath = Path.Combine( - Path.GetTempPath(), - Path.GetRandomFileName() - ).Replace('\\', '/'); + [Test] + public void FileClose() + { + var tmpPath = Path.Combine( + Path.GetTempPath(), + Path.GetRandomFileName() + ).Replace('\\', '/'); - File.Create(tmpPath).Dispose(); + File.Create(tmpPath).Dispose(); - var result = EvilTestResult( - $"fn test() {{" + - $" val stream = fs.file.open('{tmpPath}');" + - $" fs.file.close(stream);" + - $" ret stream;" + - $"}}" - ); - - result.Type.ShouldBe(DynamicValueType.NativeObject); - result.NativeObject.ShouldBeAssignableTo(); - - Should.Throw(() => - { - _ = ((Stream)result.NativeObject!).Read(new byte[4]); - }); - - File.Delete(tmpPath); - } - - [Test] - public void FileSeek() + var result = EvilTestResult( + $"fn test() {{" + + $" val stream = fs.file.open('{tmpPath}');" + + $" fs.file.close(stream);" + + $" ret stream;" + + $"}}" + ); + + result.Type.ShouldBe(DynamicValueType.NativeObject); + result.NativeObject.ShouldBeAssignableTo(); + + Should.Throw(() => { - var tmpPath = Path.Combine( - Path.GetTempPath(), - Path.GetRandomFileName() - ).Replace('\\', '/'); - - var stream = File.Create(tmpPath); - stream.Write(Encoding.UTF8.GetBytes("hello world uwu")); - stream.Dispose(); + _ = ((Stream)result.NativeObject!).Read(new byte[4]); + }); + + File.Delete(tmpPath); + } + + [Test] + public void FileSeek() + { + var tmpPath = Path.Combine( + Path.GetTempPath(), + Path.GetRandomFileName() + ).Replace('\\', '/'); + + var stream = File.Create(tmpPath); + stream.Write(Encoding.UTF8.GetBytes("hello world uwu")); + stream.Dispose(); - var result = EvilTestResult( - $"fn test() {{" + - $" val stream = fs.file.open('{tmpPath}');" + - $" val retval = fs.file.seek(stream, 8, fs.origin.BEGIN);" + - $" ret array() {{ stream, retval }};" + - $"}}" - ); - - result.Type.ShouldBe(DynamicValueType.Array); - var array = result.Array!; - array.Length.ShouldBe(2); - array[0].Type.ShouldBe(DynamicValueType.NativeObject); - array[0].NativeObject.ShouldBeAssignableTo(); - var innerStream = (Stream)array[0].NativeObject!; - array[1].Type.ShouldBe(DynamicValueType.Number); - var position = array[1].Number; - - innerStream.Position.ShouldBe(8); - position.ShouldBe(8); - - innerStream.Dispose(); + var result = EvilTestResult( + $"fn test() {{" + + $" val stream = fs.file.open('{tmpPath}');" + + $" val retval = fs.file.seek(stream, 8, fs.origin.BEGIN);" + + $" ret array() {{ stream, retval }};" + + $"}}" + ); + + result.Type.ShouldBe(DynamicValueType.Array); + var array = result.Array!; + array.Length.ShouldBe(2); + array[0].Type.ShouldBe(DynamicValueType.NativeObject); + array[0].NativeObject.ShouldBeAssignableTo(); + var innerStream = (Stream)array[0].NativeObject!; + array[1].Type.ShouldBe(DynamicValueType.Number); + var position = array[1].Number; + + innerStream.Position.ShouldBe(8); + position.ShouldBe(8); + + innerStream.Dispose(); - File.Delete(tmpPath); - } + File.Delete(tmpPath); + } - [Test] - public void FileTell() - { - var tmpPath = Path.Combine( - Path.GetTempPath(), - Path.GetRandomFileName() - ).Replace('\\', '/'); - - var stream = File.Create(tmpPath); - stream.Write(Encoding.UTF8.GetBytes("hello world uwu")); - stream.Dispose(); + [Test] + public void FileTell() + { + var tmpPath = Path.Combine( + Path.GetTempPath(), + Path.GetRandomFileName() + ).Replace('\\', '/'); + + var stream = File.Create(tmpPath); + stream.Write(Encoding.UTF8.GetBytes("hello world uwu")); + stream.Dispose(); - var result = EvilTestResult( - $"fn test() {{" + - $" val stream = fs.file.open('{tmpPath}');" + - $" fs.file.seek(stream, 8, fs.origin.BEGIN);" + - $" val retval = fs.file.tell(stream);" + - $" fs.file.close(stream);" + - $" ret retval;" + - $"}}" - ); - - result.Type.ShouldBe(DynamicValueType.Number); - result.ShouldBe(8); + var result = EvilTestResult( + $"fn test() {{" + + $" val stream = fs.file.open('{tmpPath}');" + + $" fs.file.seek(stream, 8, fs.origin.BEGIN);" + + $" val retval = fs.file.tell(stream);" + + $" fs.file.close(stream);" + + $" ret retval;" + + $"}}" + ); + + result.Type.ShouldBe(DynamicValueType.Number); + result.ShouldBe(8); - File.Delete(tmpPath); - } + File.Delete(tmpPath); + } - [Test] - public void FileWrite() - { - var tmpPath = Path.Combine( - Path.GetTempPath(), - Path.GetRandomFileName() - ).Replace('\\', '/'); - - var result = EvilTestResult( - $"fn test() {{" + - $" val stream = fs.file.open('{tmpPath}', 'w+');" + - $" val result = fs.file.write(" + - $" stream, " + - $" array() {{ 0x21, 0x37, 0x42, 0x69 }}" + - $" );" + - $"" + - $" ret array() {{ result, stream }};" + - $"}}" - ); - - result.Type.ShouldBe(DynamicValueType.Array); - var array = result.Array!; - array.Length.ShouldBe(2); - - array[0].Type.ShouldBe(DynamicValueType.Boolean); - array[0].ShouldBe(true); - - array[1].Type.ShouldBe(DynamicValueType.NativeObject); - array[1].NativeObject.ShouldBeAssignableTo(); + [Test] + public void FileWrite() + { + var tmpPath = Path.Combine( + Path.GetTempPath(), + Path.GetRandomFileName() + ).Replace('\\', '/'); + + var result = EvilTestResult( + $"fn test() {{" + + $" val stream = fs.file.open('{tmpPath}', 'w+');" + + $" val result = fs.file.write(" + + $" stream, " + + $" array() {{ 0x21, 0x37, 0x42, 0x69 }}" + + $" );" + + $"" + + $" ret array() {{ result, stream }};" + + $"}}" + ); + + result.Type.ShouldBe(DynamicValueType.Array); + var array = result.Array!; + array.Length.ShouldBe(2); + + array[0].Type.ShouldBe(DynamicValueType.Boolean); + array[0].ShouldBe(true); + + array[1].Type.ShouldBe(DynamicValueType.NativeObject); + array[1].NativeObject.ShouldBeAssignableTo(); - ((Stream)array[1].NativeObject!).Dispose(); + ((Stream)array[1].NativeObject!).Dispose(); - var bytes = File.ReadAllBytes(tmpPath); - bytes[0].ShouldBe((byte)0x21); - bytes[1].ShouldBe((byte)0x37); - bytes[2].ShouldBe((byte)0x42); - bytes[3].ShouldBe((byte)0x69); + var bytes = File.ReadAllBytes(tmpPath); + bytes[0].ShouldBe((byte)0x21); + bytes[1].ShouldBe((byte)0x37); + bytes[2].ShouldBe((byte)0x42); + bytes[3].ShouldBe((byte)0x69); - File.Delete(tmpPath); - } + File.Delete(tmpPath); + } - [Test] - public void FileWriteString() - { - var tmpPath = Path.Combine( - Path.GetTempPath(), - Path.GetRandomFileName() - ).Replace('\\', '/'); - - var result = EvilTestResult( - $"fn test() {{" + - $" val stream = fs.file.open('{tmpPath}', 'w+');" + - $" val result = fs.file.write_s(stream, 'hello world uwu');" + - $" fs.file.close(stream);" + - $" ret result;" + - $"}}" - ); - - result.Type.ShouldBe(DynamicValueType.Boolean); - result.ShouldBe(true); - - var text = File.ReadAllText(tmpPath); - text.ShouldBe("hello world uwu"); - - File.Delete(tmpPath); - } + [Test] + public void FileWriteString() + { + var tmpPath = Path.Combine( + Path.GetTempPath(), + Path.GetRandomFileName() + ).Replace('\\', '/'); + + var result = EvilTestResult( + $"fn test() {{" + + $" val stream = fs.file.open('{tmpPath}', 'w+');" + + $" val result = fs.file.write_s(stream, 'hello world uwu');" + + $" fs.file.close(stream);" + + $" ret result;" + + $"}}" + ); + + result.Type.ShouldBe(DynamicValueType.Boolean); + result.ShouldBe(true); + + var text = File.ReadAllText(tmpPath); + text.ShouldBe("hello world uwu"); + + File.Delete(tmpPath); + } - [Test] - public void FileRead() - { - var tmpPath = Path.Combine( - Path.GetTempPath(), - Path.GetRandomFileName() - ).Replace('\\', '/'); - - var stream = File.OpenWrite(tmpPath); - stream.Write(Encoding.UTF8.GetBytes("hello world")); - stream.Dispose(); + [Test] + public void FileRead() + { + var tmpPath = Path.Combine( + Path.GetTempPath(), + Path.GetRandomFileName() + ).Replace('\\', '/'); + + var stream = File.OpenWrite(tmpPath); + stream.Write(Encoding.UTF8.GetBytes("hello world")); + stream.Dispose(); - var result = EvilTestResult( - $"fn test() {{" + - $" val stream = fs.file.open('{tmpPath}', 'r');" + - $" val arr = array(16); " + - $" val read_cnt = fs.file.read(stream, arr);" + - $" fs.file.close(stream);" + - $" ret array() {{ read_cnt, arr }};" + - $"}}" - ); + var result = EvilTestResult( + $"fn test() {{" + + $" val stream = fs.file.open('{tmpPath}', 'r');" + + $" val arr = array(16); " + + $" val read_cnt = fs.file.read(stream, arr);" + + $" fs.file.close(stream);" + + $" ret array() {{ read_cnt, arr }};" + + $"}}" + ); - result.Type.ShouldBe(DynamicValueType.Array); - var array = result.Array!; - array.Length.ShouldBe(2); + result.Type.ShouldBe(DynamicValueType.Array); + var array = result.Array!; + array.Length.ShouldBe(2); - array[0].Type.ShouldBe(DynamicValueType.Number); - array[0].ShouldBe(11); + array[0].Type.ShouldBe(DynamicValueType.Number); + array[0].ShouldBe(11); - array[1].Type.ShouldBe(DynamicValueType.Array); - var innerArray = array[1].Array!; - innerArray.Length.ShouldBe(16); + array[1].Type.ShouldBe(DynamicValueType.Array); + var innerArray = array[1].Array!; + innerArray.Length.ShouldBe(16); - var bytes = new byte[(int)array[0].Number]; - for (var i = 0; i < bytes.Length; i++) - { - bytes[i] = (byte)innerArray[i].Number; - } + var bytes = new byte[(int)array[0].Number]; + for (var i = 0; i < bytes.Length; i++) + { + bytes[i] = (byte)innerArray[i].Number; + } - var str = Encoding.UTF8.GetString(bytes); - str.ShouldBe("hello world"); + var str = Encoding.UTF8.GetString(bytes); + str.ShouldBe("hello world"); - File.Delete(tmpPath); - } + File.Delete(tmpPath); + } - [Test] - public void FileReadByte() - { - var tmpPath = Path.Combine( - Path.GetTempPath(), - Path.GetRandomFileName() - ).Replace('\\', '/'); - - var stream = File.OpenWrite(tmpPath); - stream.Write(new byte[] { 2, 1, 3, 7 }); - stream.Dispose(); - - var result = EvilTestResult( - $"fn test() {{" + - $" val stream = fs.file.open('{tmpPath}', 'r');" + - $" val result = array(4);" + - $" for (rw val i = 0; i < #result; i++) {{" + - $" result[i] = fs.file.read_b(stream);" + - $" }}" + - $" fs.file.close(stream);" + - $" ret result;" + - $"}}" - ); - - File.Delete(tmpPath); - - result.Type.ShouldBe(DynamicValueType.Array); - var array = result.Array!; - - array[0].ShouldBe(2); - array[1].ShouldBe(1); - array[2].ShouldBe(3); - array[3].ShouldBe(7); - } + [Test] + public void FileReadByte() + { + var tmpPath = Path.Combine( + Path.GetTempPath(), + Path.GetRandomFileName() + ).Replace('\\', '/'); + + var stream = File.OpenWrite(tmpPath); + stream.Write(new byte[] { 2, 1, 3, 7 }); + stream.Dispose(); + + var result = EvilTestResult( + $"fn test() {{" + + $" val stream = fs.file.open('{tmpPath}', 'r');" + + $" val result = array(4);" + + $" for (rw val i = 0; i < #result; i++) {{" + + $" result[i] = fs.file.read_b(stream);" + + $" }}" + + $" fs.file.close(stream);" + + $" ret result;" + + $"}}" + ); + + File.Delete(tmpPath); + + result.Type.ShouldBe(DynamicValueType.Array); + var array = result.Array!; + + array[0].ShouldBe(2); + array[1].ShouldBe(1); + array[2].ShouldBe(3); + array[3].ShouldBe(7); } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/FsModuleTest.Path.cs b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/FsModuleTest.Path.cs index ac9197b1..7b06dcfd 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/FsModuleTest.Path.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/FsModuleTest.Path.cs @@ -1,224 +1,223 @@ +namespace EVIL.Ceres.RuntimeTests.RuntimeModules; + using System.IO; using EVIL.CommonTypes.TypeSystem; using NUnit.Framework; using Shouldly; -namespace EVIL.Ceres.RuntimeTests.RuntimeModules +public partial class FsModuleTest { - public partial class FsModuleTest + [Test] + public void PathGetPathSeparator() { - [Test] - public void PathGetPathSeparator() - { - var result = EvilTestResult( - "fn test() -> fs.path.sep;" - ); + var result = EvilTestResult( + "fn test() -> fs.path.sep;" + ); - result.Type.ShouldBe(DynamicValueType.String); - result.ShouldBe(Path.PathSeparator.ToString()); - } + result.Type.ShouldBe(DynamicValueType.String); + result.ShouldBe(Path.PathSeparator.ToString()); + } - [Test] - public void PathGetAltPathSeparator() - { - var result = EvilTestResult( - "fn test() -> fs.path.alt_sep;" - ); + [Test] + public void PathGetAltPathSeparator() + { + var result = EvilTestResult( + "fn test() -> fs.path.alt_sep;" + ); - result.Type.ShouldBe(DynamicValueType.String); - result.ShouldBe(Path.AltDirectorySeparatorChar.ToString()); - } + result.Type.ShouldBe(DynamicValueType.String); + result.ShouldBe(Path.AltDirectorySeparatorChar.ToString()); + } - [Test] - public void PathGetBadPathChars() - { - var result = EvilTestResult( - "fn test() -> fs.path.bad_path_chars;" - ); + [Test] + public void PathGetBadPathChars() + { + var result = EvilTestResult( + "fn test() -> fs.path.bad_path_chars;" + ); - result.Type.ShouldBe(DynamicValueType.Array); + result.Type.ShouldBe(DynamicValueType.Array); - var chars = Path.GetInvalidPathChars(); - var array = result.Array!; - for (var i = 0; i < array.Length; i++) - { - array[i].Type.ShouldBe(DynamicValueType.String); - array[i].String.ShouldBe(chars[i].ToString()); - } + var chars = Path.GetInvalidPathChars(); + var array = result.Array!; + for (var i = 0; i < array.Length; i++) + { + array[i].Type.ShouldBe(DynamicValueType.String); + array[i].String.ShouldBe(chars[i].ToString()); } + } - [Test] - public void PathGetBadNameChars() - { - var result = EvilTestResult( - "fn test() -> fs.path.bad_fname_chars;" - ); + [Test] + public void PathGetBadNameChars() + { + var result = EvilTestResult( + "fn test() -> fs.path.bad_fname_chars;" + ); - result.Type.ShouldBe(DynamicValueType.Array); + result.Type.ShouldBe(DynamicValueType.Array); - var chars = Path.GetInvalidFileNameChars(); - var array = result.Array!; - for (var i = 0; i < array.Length; i++) - { - array[i].Type.ShouldBe(DynamicValueType.String); - array[i].String.ShouldBe(chars[i].ToString()); - } + var chars = Path.GetInvalidFileNameChars(); + var array = result.Array!; + for (var i = 0; i < array.Length; i++) + { + array[i].Type.ShouldBe(DynamicValueType.String); + array[i].String.ShouldBe(chars[i].ToString()); } + } - [Test] - public void PathGetTempDirPath() - { - var tempDir = Path.GetTempPath(); - var result = EvilTestResult( - "fn test() -> fs.path.temp_dir;" - ); + [Test] + public void PathGetTempDirPath() + { + var tempDir = Path.GetTempPath(); + var result = EvilTestResult( + "fn test() -> fs.path.temp_dir;" + ); - result.Type.ShouldBe(DynamicValueType.String); - result.ShouldBe(tempDir); - } + result.Type.ShouldBe(DynamicValueType.String); + result.ShouldBe(tempDir); + } - [Test] - public void PathGetRandomFileName() - { - var result = EvilTestResult( - $"fn test() -> fs.path.rand_fname;" - ); + [Test] + public void PathGetRandomFileName() + { + var result = EvilTestResult( + $"fn test() -> fs.path.rand_fname;" + ); - result.Type.ShouldBe(DynamicValueType.String); - string.IsNullOrEmpty(result.String!).ShouldBe(false); - } + result.Type.ShouldBe(DynamicValueType.String); + string.IsNullOrEmpty(result.String!).ShouldBe(false); + } - [Test] - public void PathCombine() - { - var result = EvilTestResult( - "fn test() -> fs.path.cmb('c:', 'weird stuff', 'test');" - ); + [Test] + public void PathCombine() + { + var result = EvilTestResult( + "fn test() -> fs.path.cmb('c:', 'weird stuff', 'test');" + ); - result.Type.ShouldBe(DynamicValueType.String); - result.ShouldBe("c:/weird stuff/test"); - } + result.Type.ShouldBe(DynamicValueType.String); + result.ShouldBe("c:/weird stuff/test"); + } - [Test] - public void PathGetFileNameWithExtension() - { - var result = EvilTestResult( - $"fn test() -> fs.path.get_fname('/var/lib/something.so.1');" - ); + [Test] + public void PathGetFileNameWithExtension() + { + var result = EvilTestResult( + $"fn test() -> fs.path.get_fname('/var/lib/something.so.1');" + ); - result.Type.ShouldBe(DynamicValueType.String); - result.ShouldBe("something.so.1"); - } + result.Type.ShouldBe(DynamicValueType.String); + result.ShouldBe("something.so.1"); + } - [Test] - public void PathGetFileNameWithoutExtension() - { - var result = EvilTestResult( - $"fn test() -> fs.path.get_fname(" + - $" '/var/lib/something.so.1'," + - $" true" + - $");" - ); + [Test] + public void PathGetFileNameWithoutExtension() + { + var result = EvilTestResult( + $"fn test() -> fs.path.get_fname(" + + $" '/var/lib/something.so.1'," + + $" true" + + $");" + ); - result.Type.ShouldBe(DynamicValueType.String); - result.ShouldBe("something.so"); - } + result.Type.ShouldBe(DynamicValueType.String); + result.ShouldBe("something.so"); + } - [Test] - public void PathGetDirectoryName() - { - var result = EvilTestResult( - $"fn test() -> fs.path.get_dname(" + - $" 'c:/program files (x86)/btw/buy/deadlink.exe'" + - $");" - ); + [Test] + public void PathGetDirectoryName() + { + var result = EvilTestResult( + $"fn test() -> fs.path.get_dname(" + + $" 'c:/program files (x86)/btw/buy/deadlink.exe'" + + $");" + ); - result.Type.ShouldBe(DynamicValueType.String); - result.ShouldBe("c:/program files (x86)/btw/buy"); - } + result.Type.ShouldBe(DynamicValueType.String); + result.ShouldBe("c:/program files (x86)/btw/buy"); + } - [Test] - public void PathExists() - { - var path = Path.Combine( - Path.GetTempPath(), - Path.GetTempFileName() - ).Replace('\\', '/'); + [Test] + public void PathExists() + { + var path = Path.Combine( + Path.GetTempPath(), + Path.GetTempFileName() + ).Replace('\\', '/'); - File.Create(path).Dispose(); - - var resultFile = EvilTestResult( - $"fn test() -> fs.path.exists('{path}');" - ); - resultFile.Type.ShouldBe(DynamicValueType.Boolean); - resultFile.ShouldBe(true); - File.Delete(path); - - Directory.CreateDirectory(path); - - var resultDirectory = EvilTestResult( - $"fn test() -> fs.path.exists('{path}');" - ); - resultDirectory.Type.ShouldBe(DynamicValueType.Boolean); - resultDirectory.ShouldBe(true); - Directory.Delete(path, true); - } + File.Create(path).Dispose(); + + var resultFile = EvilTestResult( + $"fn test() -> fs.path.exists('{path}');" + ); + resultFile.Type.ShouldBe(DynamicValueType.Boolean); + resultFile.ShouldBe(true); + File.Delete(path); + + Directory.CreateDirectory(path); + + var resultDirectory = EvilTestResult( + $"fn test() -> fs.path.exists('{path}');" + ); + resultDirectory.Type.ShouldBe(DynamicValueType.Boolean); + resultDirectory.ShouldBe(true); + Directory.Delete(path, true); + } - [Test] - public void PathGetExtension() - { - var result = EvilTestResult( - $"fn test() -> fs.path.get_ext('dobry_jezu.exe');" - ); + [Test] + public void PathGetExtension() + { + var result = EvilTestResult( + $"fn test() -> fs.path.get_ext('dobry_jezu.exe');" + ); - result.Type.ShouldBe(DynamicValueType.String); - result.ShouldBe(".exe"); - } + result.Type.ShouldBe(DynamicValueType.String); + result.ShouldBe(".exe"); + } - [Test] - public void PathHasExtension() - { - var result = EvilTestResult( - $"fn test() -> fs.path.has_ext('dobry_jezu.exe');" - ); + [Test] + public void PathHasExtension() + { + var result = EvilTestResult( + $"fn test() -> fs.path.has_ext('dobry_jezu.exe');" + ); - result.Type.ShouldBe(DynamicValueType.Boolean); - result.ShouldBe(true); + result.Type.ShouldBe(DynamicValueType.Boolean); + result.ShouldBe(true); - result = EvilTestResult( - $"fn test() -> fs.path.has_ext('dobry_jezu');" - ); + result = EvilTestResult( + $"fn test() -> fs.path.has_ext('dobry_jezu');" + ); - result.Type.ShouldBe(DynamicValueType.Boolean); - result.ShouldBe(false); - } + result.Type.ShouldBe(DynamicValueType.Boolean); + result.ShouldBe(false); + } - [Test] - public void PathChangeExtension() - { - var result = EvilTestResult( - $"fn test() -> fs.path.chg_ext(" + - $" '/root/dobry_jezu.exe'," + - $" '.png'" + - $");" - ); - - result.Type.ShouldBe(DynamicValueType.String); - result.ShouldBe("/root/dobry_jezu.png"); - } + [Test] + public void PathChangeExtension() + { + var result = EvilTestResult( + $"fn test() -> fs.path.chg_ext(" + + $" '/root/dobry_jezu.exe'," + + $" '.png'" + + $");" + ); + + result.Type.ShouldBe(DynamicValueType.String); + result.ShouldBe("/root/dobry_jezu.png"); + } - [Test] - public void PathRemoveExtension() - { - var result = EvilTestResult( - $"fn test() -> fs.path.chg_ext(" + - $" '/root/dobry_jezu.exe'," + - $" nil" + - $");" - ); - - result.Type.ShouldBe(DynamicValueType.String); - result.ShouldBe("/root/dobry_jezu"); - } + [Test] + public void PathRemoveExtension() + { + var result = EvilTestResult( + $"fn test() -> fs.path.chg_ext(" + + $" '/root/dobry_jezu.exe'," + + $" nil" + + $");" + ); + + result.Type.ShouldBe(DynamicValueType.String); + result.ShouldBe("/root/dobry_jezu"); } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/FsModuleTest.cs b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/FsModuleTest.cs index 5b0f8099..1b293af7 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/FsModuleTest.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/FsModuleTest.cs @@ -1,34 +1,33 @@ +namespace EVIL.Ceres.RuntimeTests.RuntimeModules; + using System.IO; using EVIL.Ceres.Runtime.Modules; using EVIL.CommonTypes.TypeSystem; using NUnit.Framework; using Shouldly; -namespace EVIL.Ceres.RuntimeTests.RuntimeModules +public partial class FsModuleTest : ModuleTest { - public partial class FsModuleTest : ModuleTest + [Test] + public void OriginValuesMatch() { - [Test] - public void OriginValuesMatch() - { - var result = EvilTestResult( - $"fn test() -> array() {{ " + - $" fs.origin.BEGIN, " + - $" fs.origin.CURRENT, " + - $" fs.origin.END " + - $"}};" - ); + var result = EvilTestResult( + $"fn test() -> array() {{ " + + $" fs.origin.BEGIN, " + + $" fs.origin.CURRENT, " + + $" fs.origin.END " + + $"}};" + ); - result.Type.ShouldBe(DynamicValueType.Array); - var array = result.Array!; + result.Type.ShouldBe(DynamicValueType.Array); + var array = result.Array!; - array[0].Type.ShouldBe(DynamicValueType.Number); - array[1].Type.ShouldBe(DynamicValueType.Number); - array[2].Type.ShouldBe(DynamicValueType.Number); + array[0].Type.ShouldBe(DynamicValueType.Number); + array[1].Type.ShouldBe(DynamicValueType.Number); + array[2].Type.ShouldBe(DynamicValueType.Number); - array[0].ShouldBe((long)SeekOrigin.Begin); - array[1].ShouldBe((long)SeekOrigin.Current); - array[2].ShouldBe((long)SeekOrigin.End); - } + array[0].ShouldBe((long)SeekOrigin.Begin); + array[1].ShouldBe((long)SeekOrigin.Current); + array[2].ShouldBe((long)SeekOrigin.End); } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/IoModuleTest.cs b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/IoModuleTest.cs index a103c75c..7f19911c 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/IoModuleTest.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/IoModuleTest.cs @@ -1,63 +1,62 @@ -using System; +namespace EVIL.Ceres.RuntimeTests.RuntimeModules; + +using System; using System.IO; using EVIL.Ceres.Runtime.Modules; using NUnit.Framework; using Shouldly; -namespace EVIL.Ceres.RuntimeTests.RuntimeModules +public class IoModuleTest : ModuleTest { - public class IoModuleTest : ModuleTest + [Test] + public void Print() { - [Test] - public void Print() - { - var src = "fn test() -> io.print(\"hello, world\");"; - var originalOut = Console.Out; + var src = "fn test() -> io.print(\"hello, world\");"; + var originalOut = Console.Out; - using (var ms = new MemoryStream()) + using (var ms = new MemoryStream()) + { + using (var sw = new StreamWriter(ms)) { - using (var sw = new StreamWriter(ms)) - { - sw.AutoFlush = true; - Console.SetOut(sw); + sw.AutoFlush = true; + Console.SetOut(sw); - EvilTestResult(src).ShouldBe(12); - ms.Seek(0, SeekOrigin.Begin); + EvilTestResult(src).ShouldBe(12); + ms.Seek(0, SeekOrigin.Begin); - using (var sr = new StreamReader(ms, leaveOpen: true)) - { - sr.ReadToEnd().ShouldBe("hello, world"); - } + using (var sr = new StreamReader(ms, leaveOpen: true)) + { + sr.ReadToEnd().ShouldBe("hello, world"); } } - - Console.SetOut(originalOut); } - [Test] - public void PrintLine() - { - var src = "fn test() -> io.println(\"hello, world\");"; - var originalOut = Console.Out; + Console.SetOut(originalOut); + } + + [Test] + public void PrintLine() + { + var src = "fn test() -> io.println(\"hello, world\");"; + var originalOut = Console.Out; - using (var ms = new MemoryStream()) + using (var ms = new MemoryStream()) + { + using (var sw = new StreamWriter(ms)) { - using (var sw = new StreamWriter(ms)) - { - sw.AutoFlush = true; - Console.SetOut(sw); + sw.AutoFlush = true; + Console.SetOut(sw); - EvilTestResult(src).ShouldBe("hello, world".Length + Environment.NewLine.Length); - ms.Seek(0, SeekOrigin.Begin); + EvilTestResult(src).ShouldBe("hello, world".Length + Environment.NewLine.Length); + ms.Seek(0, SeekOrigin.Begin); - using (var sr = new StreamReader(ms, leaveOpen: true)) - { - sr.ReadToEnd().ShouldBe($"hello, world{Environment.NewLine}"); - } + using (var sr = new StreamReader(ms, leaveOpen: true)) + { + sr.ReadToEnd().ShouldBe($"hello, world{Environment.NewLine}"); } } - - Console.SetOut(originalOut); } + + Console.SetOut(originalOut); } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/MathModuleTest.cs b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/MathModuleTest.cs index ff090aef..fe5f5ebb 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/MathModuleTest.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/MathModuleTest.cs @@ -1,338 +1,337 @@ -using System; +namespace EVIL.Ceres.RuntimeTests.RuntimeModules; + +using System; using EVIL.Ceres.Runtime.Modules; using NUnit.Framework; using Shouldly; -namespace EVIL.Ceres.RuntimeTests.RuntimeModules +public class MathModuleTest : ModuleTest { - public class MathModuleTest : ModuleTest + [Test] + public void Abs() + { + EvilTestResult( + "fn test() -> math.abs(-2137);" + ).ShouldBe(2137); + } + + [Test] + public void Acos() + { + Math.Round( + EvilTestResult( + "fn test() -> math.acos(0.13);" + ).Number, 1 + ).ShouldBe(1.4); + } + + [Test] + public void Acosh() + { + Math.Round( + EvilTestResult( + "fn test() -> math.acosh(100);" + ).Number, 1 + ).ShouldBe(5.3); + } + + [Test] + public void Asin() + { + Math.Round( + EvilTestResult( + "fn test() -> math.asin(0.13);" + ).Number, 1 + ).ShouldBe(0.1); + } + + [Test] + public void Asinh() + { + Math.Round( + EvilTestResult( + "fn test() -> math.asinh(0.20);" + ).Number, 1 + ).ShouldBe(0.2); + } + + [Test] + public void Atan() { - [Test] - public void Abs() - { + Math.Round( EvilTestResult( - "fn test() -> math.abs(-2137);" - ).ShouldBe(2137); - } - - [Test] - public void Acos() - { - Math.Round( - EvilTestResult( - "fn test() -> math.acos(0.13);" - ).Number, 1 - ).ShouldBe(1.4); - } - - [Test] - public void Acosh() - { - Math.Round( - EvilTestResult( - "fn test() -> math.acosh(100);" - ).Number, 1 - ).ShouldBe(5.3); - } - - [Test] - public void Asin() - { - Math.Round( - EvilTestResult( - "fn test() -> math.asin(0.13);" - ).Number, 1 - ).ShouldBe(0.1); - } - - [Test] - public void Asinh() - { - Math.Round( - EvilTestResult( - "fn test() -> math.asinh(0.20);" - ).Number, 1 - ).ShouldBe(0.2); - } - - [Test] - public void Atan() - { - Math.Round( - EvilTestResult( - "fn test() -> math.atan(2137);" - ).Number, 1 - ).ShouldBe(1.6); - } - - [Test] - public void Atanh() - { - Math.Round( - EvilTestResult( - "fn test() -> math.atanh(0.2137);" - ).Number, 1 - ).ShouldBe(0.2); - } - - [Test] - public void Atan2() - { - Math.Round( - EvilTestResult( - "fn test() -> math.atan2(37, 21);" - ).Number, 1 - ).ShouldBe(0.5); - } - - [Test] - public void Cbrt() - { - Math.Round( - EvilTestResult( - "fn test() -> math.cbrt(27);" - ).Number, 1 - ).ShouldBe(3); - } - - [Test] - public void Ceil() - { - Math.Round( - EvilTestResult( - "fn test() -> math.ceil(13.34);" - ).Number, 1 - ).ShouldBe(14); - } - - [Test] - public void Clamp() - { - Math.Round( - EvilTestResult( - "fn test() -> math.clamp(10, 11, 13);" - ).Number, 1 - ).ShouldBe(11); - } - - [Test] - public void Cos() - { - Math.Round( - EvilTestResult( - "fn test() -> math.cos(math.pi/6);" - ).Number, 1 - ).ShouldBe(0.9); - } - - [Test] - public void Cosh() - { - Math.Round( - EvilTestResult( - "fn test() -> math.cosh(math.pi/6);" - ).Number, 1 - ).ShouldBe(1.1); - } - - [Test] - public void Exp() - { - Math.Round( - EvilTestResult( - "fn test() -> math.exp(3);" - ).Number, 1 - ).ShouldBe(20.1); - } - - [Test] - public void Floor() - { - Math.Round( - EvilTestResult( - "fn test() -> math.floor(21.37);" - ).Number, 1 - ).ShouldBe(21); - } - - [Test] - public void Lerp() - { - var t = EvilTestResult( - "fn test() -> {" + - " math.round(math.lerp(0, 100, 0.0), 0)," + - " math.round(math.lerp(0, 100, 0.2), 0)," + - " math.round(math.lerp(0, 100, 0.4), 0)," + - " math.round(math.lerp(0, 100, 0.6), 0)," + - " math.round(math.lerp(0, 100, 0.8), 0)," + - " math.round(math.lerp(0, 100, 1.0), 0) " + - "};" - ).Table!; - - t[0].ShouldBe(0); - t[1].ShouldBe(20); - t[2].ShouldBe(40); - t[3].ShouldBe(60); - t[4].ShouldBe(80); - t[5].ShouldBe(100); - } - - [Test] - public void Log() - { - Math.Round( - EvilTestResult( - "fn test() -> math.log(27, 3);" - ).Number, 1 - ).ShouldBe(3); - } - - [Test] - public void Log2() - { - Math.Round( - EvilTestResult( - "fn test() -> math.log2(64);" - ).Number, 1 - ).ShouldBe(6); - } - - [Test] - public void Log10() - { - Math.Round( - EvilTestResult( - "fn test() -> math.log10(100);" - ).Number, 1 - ).ShouldBe(2); - } - - [Test] - public void Max() - { - Math.Round( - EvilTestResult( - "fn test() -> math.max(100, 1000);" - ).Number, 1 - ).ShouldBe(1000); - } - - [Test] - public void Min() - { - Math.Round( - EvilTestResult( - "fn test() -> math.min(100, 1000);" - ).Number, 1 - ).ShouldBe(100); - } - - [Test] - public void Pow() - { - Math.Round( - EvilTestResult( - "fn test() -> math.pow(4, 4);" - ).Number, 1 - ).ShouldBe(256); - } - - [Test] - public void Round() - { - var t = EvilTestResult( - "fn test() -> { " + - " math.round(3.6662137, 0)," + - " math.round(3.6662137, 1)" + - "};" - ).Table!; - - t[0].ShouldBe(4); - t[1].ShouldBe(3.7); - } - - [Test] - public void Sin() - { - Math.Round( - EvilTestResult( - "fn test() -> math.sin(math.pi/6);" - ).Number, 1 - ).ShouldBe(0.5); - } - - [Test] - public void SinCos() - { - var t = EvilTestResult("fn test() -> math.sincos(math.pi/6);").Table!; - Math.Round(t["sin"].Number, 1).ShouldBe(0.5); - Math.Round(t["cos"].Number, 1).ShouldBe(0.9); - } - - [Test] - public void Sinh() - { - Math.Round( - EvilTestResult( - "fn test() -> math.sinh(math.pi/8);" - ).Number, 1 - ).ShouldBe(0.4); - } - - [Test] - public void Sqrt() - { + "fn test() -> math.atan(2137);" + ).Number, 1 + ).ShouldBe(1.6); + } + + [Test] + public void Atanh() + { + Math.Round( EvilTestResult( - "fn test() -> math.sqrt(400);" - ).ShouldBe(20); - } - - [Test] - public void Tan() - { - Math.Round( - EvilTestResult( - "fn test() -> math.tan(math.pi/6);" - ).Number, 1 - ).ShouldBe(0.6); - } - - [Test] - public void Tanh() - { - Math.Round( - EvilTestResult( - "fn test() -> math.tanh(math.pi/9.5);" - ).Number, 1 - ).ShouldBe(0.3); - } - - [Test] - public void Trunc() - { + "fn test() -> math.atanh(0.2137);" + ).Number, 1 + ).ShouldBe(0.2); + } + + [Test] + public void Atan2() + { + Math.Round( + EvilTestResult( + "fn test() -> math.atan2(37, 21);" + ).Number, 1 + ).ShouldBe(0.5); + } + + [Test] + public void Cbrt() + { + Math.Round( + EvilTestResult( + "fn test() -> math.cbrt(27);" + ).Number, 1 + ).ShouldBe(3); + } + + [Test] + public void Ceil() + { + Math.Round( + EvilTestResult( + "fn test() -> math.ceil(13.34);" + ).Number, 1 + ).ShouldBe(14); + } + + [Test] + public void Clamp() + { + Math.Round( + EvilTestResult( + "fn test() -> math.clamp(10, 11, 13);" + ).Number, 1 + ).ShouldBe(11); + } + + [Test] + public void Cos() + { + Math.Round( + EvilTestResult( + "fn test() -> math.cos(math.pi/6);" + ).Number, 1 + ).ShouldBe(0.9); + } + + [Test] + public void Cosh() + { + Math.Round( + EvilTestResult( + "fn test() -> math.cosh(math.pi/6);" + ).Number, 1 + ).ShouldBe(1.1); + } + + [Test] + public void Exp() + { + Math.Round( + EvilTestResult( + "fn test() -> math.exp(3);" + ).Number, 1 + ).ShouldBe(20.1); + } + + [Test] + public void Floor() + { + Math.Round( + EvilTestResult( + "fn test() -> math.floor(21.37);" + ).Number, 1 + ).ShouldBe(21); + } + + [Test] + public void Lerp() + { + var t = EvilTestResult( + "fn test() -> {" + + " math.round(math.lerp(0, 100, 0.0), 0)," + + " math.round(math.lerp(0, 100, 0.2), 0)," + + " math.round(math.lerp(0, 100, 0.4), 0)," + + " math.round(math.lerp(0, 100, 0.6), 0)," + + " math.round(math.lerp(0, 100, 0.8), 0)," + + " math.round(math.lerp(0, 100, 1.0), 0) " + + "};" + ).Table!; + + t[0].ShouldBe(0); + t[1].ShouldBe(20); + t[2].ShouldBe(40); + t[3].ShouldBe(60); + t[4].ShouldBe(80); + t[5].ShouldBe(100); + } + + [Test] + public void Log() + { + Math.Round( + EvilTestResult( + "fn test() -> math.log(27, 3);" + ).Number, 1 + ).ShouldBe(3); + } + + [Test] + public void Log2() + { + Math.Round( + EvilTestResult( + "fn test() -> math.log2(64);" + ).Number, 1 + ).ShouldBe(6); + } + + [Test] + public void Log10() + { + Math.Round( + EvilTestResult( + "fn test() -> math.log10(100);" + ).Number, 1 + ).ShouldBe(2); + } + + [Test] + public void Max() + { + Math.Round( + EvilTestResult( + "fn test() -> math.max(100, 1000);" + ).Number, 1 + ).ShouldBe(1000); + } + + [Test] + public void Min() + { + Math.Round( + EvilTestResult( + "fn test() -> math.min(100, 1000);" + ).Number, 1 + ).ShouldBe(100); + } + + [Test] + public void Pow() + { + Math.Round( + EvilTestResult( + "fn test() -> math.pow(4, 4);" + ).Number, 1 + ).ShouldBe(256); + } + + [Test] + public void Round() + { + var t = EvilTestResult( + "fn test() -> { " + + " math.round(3.6662137, 0)," + + " math.round(3.6662137, 1)" + + "};" + ).Table!; + + t[0].ShouldBe(4); + t[1].ShouldBe(3.7); + } + + [Test] + public void Sin() + { + Math.Round( + EvilTestResult( + "fn test() -> math.sin(math.pi/6);" + ).Number, 1 + ).ShouldBe(0.5); + } + + [Test] + public void SinCos() + { + var t = EvilTestResult("fn test() -> math.sincos(math.pi/6);").Table!; + Math.Round(t["sin"].Number, 1).ShouldBe(0.5); + Math.Round(t["cos"].Number, 1).ShouldBe(0.9); + } + + [Test] + public void Sinh() + { + Math.Round( + EvilTestResult( + "fn test() -> math.sinh(math.pi/8);" + ).Number, 1 + ).ShouldBe(0.4); + } + + [Test] + public void Sqrt() + { + EvilTestResult( + "fn test() -> math.sqrt(400);" + ).ShouldBe(20); + } + + [Test] + public void Tan() + { + Math.Round( + EvilTestResult( + "fn test() -> math.tan(math.pi/6);" + ).Number, 1 + ).ShouldBe(0.6); + } + + [Test] + public void Tanh() + { + Math.Round( + EvilTestResult( + "fn test() -> math.tanh(math.pi/9.5);" + ).Number, 1 + ).ShouldBe(0.3); + } + + [Test] + public void Trunc() + { + EvilTestResult( + "fn test() -> math.trunc(13333.411321443134213);" + ).ShouldBe(13333); + } + + [Test] + public void Rad2Deg() + { + Math.Round( + EvilTestResult( + "fn test() -> math.rad2deg(1.1);" + ).Number, 1 + ).ShouldBe(63); + } + + [Test] + public void Deg2Rad() + { + Math.Round( EvilTestResult( - "fn test() -> math.trunc(13333.411321443134213);" - ).ShouldBe(13333); - } - - [Test] - public void Rad2Deg() - { - Math.Round( - EvilTestResult( - "fn test() -> math.rad2deg(1.1);" - ).Number, 1 - ).ShouldBe(63); - } - - [Test] - public void Deg2Rad() - { - Math.Round( - EvilTestResult( - "fn test() -> math.deg2rad(21.37);" - ).Number, 1 - ).ShouldBe(0.4); - } + "fn test() -> math.deg2rad(21.37);" + ).Number, 1 + ).ShouldBe(0.4); } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/ModuleTest.cs b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/ModuleTest.cs index 3ebc9771..14bf9a8a 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/ModuleTest.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/ModuleTest.cs @@ -1,6 +1,7 @@ -using System; +namespace EVIL.Ceres.RuntimeTests.RuntimeModules; + +using System; using System.Threading; -using System.Threading.Tasks; using EVIL.Ceres.ExecutionEngine; using EVIL.Ceres.ExecutionEngine.Concurrency; using EVIL.Ceres.ExecutionEngine.TypeSystem; @@ -9,73 +10,70 @@ using EVIL.Grammar.Parsing; using NUnit.Framework; -namespace EVIL.Ceres.RuntimeTests.RuntimeModules +public abstract class ModuleTest where T : RuntimeModule, new() { - public abstract class ModuleTest where T : RuntimeModule, new() - { - private CeresVM _vm; - private EvilRuntime _evilRuntime; + private CeresVM _vm; + private EvilRuntime _evilRuntime; - private Parser _parser; - private Compiler _compiler; + private Parser _parser; + private Compiler _compiler; - [SetUp] - public virtual void Setup() - { - _parser = new Parser(); - _compiler = new Compiler(); + [SetUp] + public virtual void Setup() + { + _parser = new Parser(); + _compiler = new Compiler(); - _vm = new CeresVM(); + _vm = new CeresVM(); - _evilRuntime = new EvilRuntime(_vm); - _evilRuntime.RegisterModule(out _); + _evilRuntime = new EvilRuntime(_vm); + _evilRuntime.RegisterModule(out _); - _vm.Start(); - } + _vm.Start(); + } - [TearDown] - public virtual void Teardown() - { - _vm.Dispose(); - _evilRuntime = null!; - _parser = null!; - _compiler = null!; - } + [TearDown] + public virtual void Teardown() + { + _vm.Dispose(); + _evilRuntime = null!; + _parser = null!; + _compiler = null!; + } - protected DynamicValue EvilTestResult(string source, params DynamicValue[] args) - { - var chunk = _compiler.Compile(source, "!module_test_file!"); - var waitForCrashHandler = true; + protected DynamicValue EvilTestResult(string source, params DynamicValue[] args) + { + var chunk = _compiler.Compile(source, "!module_test_file!"); + var waitForCrashHandler = true; - _vm.MainFiber.Schedule(chunk); - _vm.MainFiber.Schedule(chunk["test"]!, false, args); - _vm.MainFiber.Resume(); + _vm.MainFiber.Schedule(chunk); + _vm.MainFiber.Schedule(chunk["test"]!, false, args); + _vm.MainFiber.Resume(); - Exception? fiberException = null; - _vm.MainFiber.SetCrashHandler((f, e) => - { - fiberException = e; - waitForCrashHandler = false; - }); + Exception? fiberException = null; + _vm.MainFiber.SetCrashHandler((f, e) => + { + fiberException = e; + waitForCrashHandler = false; + }); - _vm.MainFiber.BlockUntilFinished(); + _vm.MainFiber.BlockUntilFinished(); - while (waitForCrashHandler) - { - Thread.Sleep(1); - } + while (waitForCrashHandler) + { + Thread.Sleep(1); + } - if (_vm.MainFiber.State == FiberState.Finished) - { - return _vm.MainFiber.PopValue(); - } + if (_vm.MainFiber.State == FiberState.Finished) + { + return _vm.MainFiber.PopValue(); + } - if (_vm.MainFiber.State == FiberState.Crashed) - { - throw new Exception("Test has failed inside EVIL world.", fiberException); - } - - throw new Exception("There is something wrong with the awaiter logic or the fiber itself."); + if (_vm.MainFiber.State == FiberState.Crashed) + { + throw new Exception("Test has failed inside EVIL world.", fiberException); } + + throw new Exception("There is something wrong with the awaiter logic or the fiber itself."); } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/StringModuleTest.cs b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/StringModuleTest.cs index 0b2f8d54..88bbf83f 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/StringModuleTest.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/StringModuleTest.cs @@ -1,231 +1,230 @@ -using EVIL.Ceres.ExecutionEngine.Collections; +namespace EVIL.Ceres.RuntimeTests.RuntimeModules; + +using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.Runtime.Modules; using NUnit.Framework; using Shouldly; -namespace EVIL.Ceres.RuntimeTests.RuntimeModules +public class StringModuleTest : ModuleTest { - public class StringModuleTest : ModuleTest - { - [Test] - public void ToChar() - { - EvilTestResult( - "fn test() -> str.chr(0x65);" - ).ShouldBe("e"); - } + [Test] + public void ToChar() + { + EvilTestResult( + "fn test() -> str.chr(0x65);" + ).ShouldBe("e"); + } - [Test] - public void Explode() - { - var array = (Array)EvilTestResult( - "fn test() -> str.explode('abcdef');" - ); - - array[0].ShouldBe("a"); - array[1].ShouldBe("b"); - array[2].ShouldBe("c"); - array[3].ShouldBe("d"); - array[4].ShouldBe("e"); - array[5].ShouldBe("f"); - } + [Test] + public void Explode() + { + var array = (Array)EvilTestResult( + "fn test() -> str.explode('abcdef');" + ); + + array[0].ShouldBe("a"); + array[1].ShouldBe("b"); + array[2].ShouldBe("c"); + array[3].ShouldBe("d"); + array[4].ShouldBe("e"); + array[5].ShouldBe("f"); + } - [Test] - public void Split() - { - var array = (Array)EvilTestResult( - "fn test() -> str.spl('abc|def|ghi', '|');" - ); - - array[0].ShouldBe("abc"); - array[1].ShouldBe("def"); - array[2].ShouldBe("ghi"); - } - - [Test] - public void JoinEmpty() - { - EvilTestResult( - "fn test() -> str.join(str.empty);" - ).ShouldBe(string.Empty); - } - - [Test] - public void JoinVarious() - { - EvilTestResult( - "fn test() -> str.join('|', 1, 'test', true);" - ).ShouldBe("1|test|true"); - } - - [Test] - public void Repeat() - { - EvilTestResult( - "fn test() -> str.repeat('test', 4);" - ).ShouldBe("testtesttesttest"); - } - - [Test] - public void IndexOf() - { - EvilTestResult( - "fn test() -> str.index_of('hello, world!', 'w');" - ).ShouldBe(7); - } - - [Test] - public void LastIndexOf() - { - EvilTestResult( - "fn test() -> str.last_index_of('hello hello hello hello', 'hello');" - ).ShouldBe(18); - } - - [Test] - public void IsWhiteSpace() - { - EvilTestResult( - "fn test() -> str.is_whitespace('');" - ).ShouldBe(true); - } - - [Test] - public void LeftPad() - { - EvilTestResult( - "fn test() -> str.lpad('2137', '0', 8);" - ).ShouldBe("00002137"); - } - - [Test] - public void RightPad() - { - EvilTestResult( - "fn test() -> str.rpad('2137', '0', 8);" - ).ShouldBe("21370000"); - } - - [Test] - public void LeftTrim() - { - EvilTestResult( - "fn test() -> str.ltrim('21372', '2');" - ).ShouldBe("1372"); - } - - [Test] - public void RightTrim() - { - EvilTestResult( - "fn test() -> str.rtrim('21372', '2', '7');" - ).ShouldBe("213"); - } - - [Test] - public void Trim() - { - EvilTestResult( - "fn test() -> str.trim('21372', '2');" - ).ShouldBe("137"); - } - - [Test] - public void UpperCase() - { - EvilTestResult( - "fn test() -> str.ucase('i was lowercase. ą.');" - ).ShouldBe("I WAS LOWERCASE. Ą."); - } - - [Test] - public void LowerCase() - { - EvilTestResult( - "fn test() -> str.lcase('I WAS UPPERCASE ONCE. Ą.');" - ).ShouldBe("i was uppercase once. ą."); - } - - [Test] - public void SubstringFrom() - { - EvilTestResult( - "fn test() -> str.sub('hello, world', 7);" - ).ShouldBe("world"); - } - - [Test] - public void SubstringFromWithNil() - { - EvilTestResult( - "fn test() -> str.sub('hello, world', 7, nil, true);" - ).ShouldBe("world"); - } - - [Test] - public void SubstringFromTo() - { - EvilTestResult( - "fn test() -> str.sub('hello, world', 3, 7, true);" - ).ShouldBe("lo, w"); - } + [Test] + public void Split() + { + var array = (Array)EvilTestResult( + "fn test() -> str.spl('abc|def|ghi', '|');" + ); + + array[0].ShouldBe("abc"); + array[1].ShouldBe("def"); + array[2].ShouldBe("ghi"); + } + + [Test] + public void JoinEmpty() + { + EvilTestResult( + "fn test() -> str.join(str.empty);" + ).ShouldBe(string.Empty); + } + + [Test] + public void JoinVarious() + { + EvilTestResult( + "fn test() -> str.join('|', 1, 'test', true);" + ).ShouldBe("1|test|true"); + } + + [Test] + public void Repeat() + { + EvilTestResult( + "fn test() -> str.repeat('test', 4);" + ).ShouldBe("testtesttesttest"); + } + + [Test] + public void IndexOf() + { + EvilTestResult( + "fn test() -> str.index_of('hello, world!', 'w');" + ).ShouldBe(7); + } + + [Test] + public void LastIndexOf() + { + EvilTestResult( + "fn test() -> str.last_index_of('hello hello hello hello', 'hello');" + ).ShouldBe(18); + } + + [Test] + public void IsWhiteSpace() + { + EvilTestResult( + "fn test() -> str.is_whitespace('');" + ).ShouldBe(true); + } + + [Test] + public void LeftPad() + { + EvilTestResult( + "fn test() -> str.lpad('2137', '0', 8);" + ).ShouldBe("00002137"); + } + + [Test] + public void RightPad() + { + EvilTestResult( + "fn test() -> str.rpad('2137', '0', 8);" + ).ShouldBe("21370000"); + } + + [Test] + public void LeftTrim() + { + EvilTestResult( + "fn test() -> str.ltrim('21372', '2');" + ).ShouldBe("1372"); + } + + [Test] + public void RightTrim() + { + EvilTestResult( + "fn test() -> str.rtrim('21372', '2', '7');" + ).ShouldBe("213"); + } + + [Test] + public void Trim() + { + EvilTestResult( + "fn test() -> str.trim('21372', '2');" + ).ShouldBe("137"); + } + + [Test] + public void UpperCase() + { + EvilTestResult( + "fn test() -> str.ucase('i was lowercase. ą.');" + ).ShouldBe("I WAS LOWERCASE. Ą."); + } + + [Test] + public void LowerCase() + { + EvilTestResult( + "fn test() -> str.lcase('I WAS UPPERCASE ONCE. Ą.');" + ).ShouldBe("i was uppercase once. ą."); + } + + [Test] + public void SubstringFrom() + { + EvilTestResult( + "fn test() -> str.sub('hello, world', 7);" + ).ShouldBe("world"); + } + + [Test] + public void SubstringFromWithNil() + { + EvilTestResult( + "fn test() -> str.sub('hello, world', 7, nil, true);" + ).ShouldBe("world"); + } + + [Test] + public void SubstringFromTo() + { + EvilTestResult( + "fn test() -> str.sub('hello, world', 3, 7, true);" + ).ShouldBe("lo, w"); + } - [Test] - public void SubstringFromTo2() - { - EvilTestResult( - "fn test() -> str.sub('hello, world', 0, 0, true);" - ).ShouldBe("h"); - } + [Test] + public void SubstringFromTo2() + { + EvilTestResult( + "fn test() -> str.sub('hello, world', 0, 0, true);" + ).ShouldBe("h"); + } - [Test] - public void SubstringFromTo3() - { - EvilTestResult( - "fn test() -> str.sub('hello, world', 0, 1, true);" - ).ShouldBe("he"); - } + [Test] + public void SubstringFromTo3() + { + EvilTestResult( + "fn test() -> str.sub('hello, world', 0, 1, true);" + ).ShouldBe("he"); + } - [Test] - public void SubstringFromTo4() - { - EvilTestResult( - "fn test() -> str.sub('hello, world', 4, 15, true);" - ).ShouldBe("o, world"); - } - - [Test] - public void StartsWith() - { - EvilTestResult( - "fn test() -> str.starts_with('hello, world', 'hel');" - ).ShouldBe(true); - } - - [Test] - public void EndsWith() - { - EvilTestResult( - "fn test() -> str.ends_with('hello, world', 'orld');" - ).ShouldBe(true); - } - - [Test] - public void RegexMatch() - { - var array = (Array)EvilTestResult( - "fn test() -> str.rmatch(" + - " 'This 21 is 37 an example 00 of 12 a test string 99.'," + - @" '(\\w+) (\\d+)'" + - ");" - ); - - array.Length.ShouldBe(5); - array[0].Table!["value"].ShouldBe("This 21"); - array[1].Table!["value"].ShouldBe("is 37"); - array[2].Table!["value"].ShouldBe("example 00"); - array[3].Table!["value"].ShouldBe("of 12"); - array[4].Table!["value"].ShouldBe("string 99"); - } + [Test] + public void SubstringFromTo4() + { + EvilTestResult( + "fn test() -> str.sub('hello, world', 4, 15, true);" + ).ShouldBe("o, world"); + } + + [Test] + public void StartsWith() + { + EvilTestResult( + "fn test() -> str.starts_with('hello, world', 'hel');" + ).ShouldBe(true); + } + + [Test] + public void EndsWith() + { + EvilTestResult( + "fn test() -> str.ends_with('hello, world', 'orld');" + ).ShouldBe(true); + } + + [Test] + public void RegexMatch() + { + var array = (Array)EvilTestResult( + "fn test() -> str.rmatch(" + + " 'This 21 is 37 an example 00 of 12 a test string 99.'," + + @" '(\\w+) (\\d+)'" + + ");" + ); + + array.Length.ShouldBe(5); + array[0].Table!["value"].ShouldBe("This 21"); + array[1].Table!["value"].ShouldBe("is 37"); + array[2].Table!["value"].ShouldBe("example 00"); + array[3].Table!["value"].ShouldBe("of 12"); + array[4].Table!["value"].ShouldBe("string 99"); } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/TableModuleTest.cs b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/TableModuleTest.cs index 3a054dad..d38fc5ef 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/TableModuleTest.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/TableModuleTest.cs @@ -1,150 +1,149 @@ -using EVIL.Ceres.Runtime.Modules; +namespace EVIL.Ceres.RuntimeTests.RuntimeModules; + +using EVIL.Ceres.Runtime.Modules; using NUnit.Framework; using Shouldly; -namespace EVIL.Ceres.RuntimeTests.RuntimeModules +public class TableModuleTest : ModuleTest { - public class TableModuleTest : ModuleTest + [Test] + public void Clear() { - [Test] - public void Clear() - { - var t = EvilTestResult( - "fn test() {" + - " val t = { 1, 2, 3, 4 };" + - " tbl.clear(t);" + - " ret t;" + - "}" - ).Table!; + var t = EvilTestResult( + "fn test() {" + + " val t = { 1, 2, 3, 4 };" + + " tbl.clear(t);" + + " ret t;" + + "}" + ).Table!; - t.Length.ShouldBe(0); - } + t.Length.ShouldBe(0); + } - [Test] - public void Freeze() - { - var t = EvilTestResult( - "fn test() {" + - " val t = {};" + - " ret tbl.freeze(t);" + - "}" - ).Table!; + [Test] + public void Freeze() + { + var t = EvilTestResult( + "fn test() {" + + " val t = {};" + + " ret tbl.freeze(t);" + + "}" + ).Table!; - t.IsFrozen.ShouldBe(true); - } + t.IsFrozen.ShouldBe(true); + } - [Test] - public void Unfreeze() - { - var t = EvilTestResult( - "fn test() {" + - " val t = {};" + - " ret tbl.unfreeze(tbl.freeze(t));" + - "}" - ).Table!; + [Test] + public void Unfreeze() + { + var t = EvilTestResult( + "fn test() {" + + " val t = {};" + + " ret tbl.unfreeze(tbl.freeze(t));" + + "}" + ).Table!; - t.IsFrozen.ShouldBe(false); - } + t.IsFrozen.ShouldBe(false); + } - [Test] - public void IsFrozen() - { - var b = EvilTestResult( - "fn test() {" + - " val t = {};" + - " tbl.freeze(t);" + - " ret tbl.is_frozen(t);" + - "}" - ).Boolean!; + [Test] + public void IsFrozen() + { + var b = EvilTestResult( + "fn test() {" + + " val t = {};" + + " tbl.freeze(t);" + + " ret tbl.is_frozen(t);" + + "}" + ).Boolean!; - b.ShouldBe(true); - } + b.ShouldBe(true); + } - [Test] - public void Keys() - { - var array = EvilTestResult( - "fn test() {" + - " val t = {" + - " this: 'is'," + - " a: 'test'," + - " of: 'evil runtime'" + - " };" + - " ret tbl.keys(t);" + - "}" - ).Array!; + [Test] + public void Keys() + { + var array = EvilTestResult( + "fn test() {" + + " val t = {" + + " this: 'is'," + + " a: 'test'," + + " of: 'evil runtime'" + + " };" + + " ret tbl.keys(t);" + + "}" + ).Array!; - array.Length.ShouldBe(3); - foreach (var kvp in array) - { - kvp.Value.ShouldBeOneOf("this", "a", "of"); - } + array.Length.ShouldBe(3); + foreach (var kvp in array) + { + kvp.Value.ShouldBeOneOf("this", "a", "of"); } + } - [Test] - public void Values() - { - var array = EvilTestResult( - "fn test() {" + - " val t = {" + - " this: 'is'," + - " a: 'test'," + - " of: 'evil runtime'" + - " };" + - " ret tbl.values(t);" + - "}" - ).Array!; + [Test] + public void Values() + { + var array = EvilTestResult( + "fn test() {" + + " val t = {" + + " this: 'is'," + + " a: 'test'," + + " of: 'evil runtime'" + + " };" + + " ret tbl.values(t);" + + "}" + ).Array!; - array.Length.ShouldBe(3); - foreach (var kvp in array) - { - kvp.Value.ShouldBeOneOf("is", "test", "evil runtime"); - } + array.Length.ShouldBe(3); + foreach (var kvp in array) + { + kvp.Value.ShouldBeOneOf("is", "test", "evil runtime"); } + } - [Test] - public void ShallowCopy() - { - var t = EvilTestResult( - "fn test() {" + - " val t1 = { 1, 2, 3 };" + - " val t2 = { 'test', t1 };" + - " val t3 = tbl.cpy(t2);" + - "" + - " ret { t1: t1, t2: t2, t3: t3 };" + - "}" - ).Table!; + [Test] + public void ShallowCopy() + { + var t = EvilTestResult( + "fn test() {" + + " val t1 = { 1, 2, 3 };" + + " val t2 = { 'test', t1 };" + + " val t3 = tbl.cpy(t2);" + + "" + + " ret { t1: t1, t2: t2, t3: t3 };" + + "}" + ).Table!; - var t1 = t["t1"]; - var t2 = t["t2"].Table!; - var t3 = t["t3"].Table!; + var t1 = t["t1"]; + var t2 = t["t2"].Table!; + var t3 = t["t3"].Table!; - t1.ShouldBeEquivalentTo(t3[1]); - t1.ShouldBeEquivalentTo(t2[1]); - t3[1].ShouldBeEquivalentTo(t2[1]); - } + t1.ShouldBeEquivalentTo(t3[1]); + t1.ShouldBeEquivalentTo(t2[1]); + t3[1].ShouldBeEquivalentTo(t2[1]); + } - [Test] - public void DeepCopy() - { - var t = EvilTestResult( - "fn test() {" + - " val t1 = { 1, 2, 3 };" + - " val t2 = { 'test', t1 };" + - " val t3 = tbl.cpy(t2, true);" + - "" + - " ret { t1: t1, t2: t2, t3: t3 };" + - "}" - ).Table!; + [Test] + public void DeepCopy() + { + var t = EvilTestResult( + "fn test() {" + + " val t1 = { 1, 2, 3 };" + + " val t2 = { 'test', t1 };" + + " val t3 = tbl.cpy(t2, true);" + + "" + + " ret { t1: t1, t2: t2, t3: t3 };" + + "}" + ).Table!; - var t1 = t["t1"].Table!; - var t2 = t["t2"].Table!; - var t3 = t["t3"].Table!; + var t1 = t["t1"].Table!; + var t2 = t["t2"].Table!; + var t3 = t["t3"].Table!; - t1.IsDeeplyEqualTo(t3[1].Table!).ShouldBeTrue(); - t1.IsDeeplyEqualTo(t2[1].Table!).ShouldBeTrue(); - t3[1].Table!.IsDeeplyEqualTo(t2[1].Table!).ShouldBeTrue(); - t2[1].Table!.ShouldNotBeSameAs(t3[1].Table!); - } + t1.IsDeeplyEqualTo(t3[1].Table!).ShouldBeTrue(); + t1.IsDeeplyEqualTo(t2[1].Table!).ShouldBeTrue(); + t3[1].Table!.IsDeeplyEqualTo(t2[1].Table!).ShouldBeTrue(); + t2[1].Table!.ShouldNotBeSameAs(t3[1].Table!); } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/TimeModuleTest.cs b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/TimeModuleTest.cs index 545d0168..e51472b1 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/TimeModuleTest.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/RuntimeModules/TimeModuleTest.cs @@ -1,64 +1,63 @@ -using System; +namespace EVIL.Ceres.RuntimeTests.RuntimeModules; + +using System; using EVIL.Ceres.Runtime.Modules; using NUnit.Framework; using Shouldly; -namespace EVIL.Ceres.RuntimeTests.RuntimeModules +public class TimeModuleTest : ModuleTest { - public class TimeModuleTest : ModuleTest + [Test] + public void TimeNow() { - [Test] - public void TimeNow() - { - var now = DateTime.Now; - var stamp = new DateTimeOffset(now).ToUnixTimeMilliseconds(); + var now = DateTime.Now; + var stamp = new DateTimeOffset(now).ToUnixTimeMilliseconds(); - var t = EvilTestResult( - "fn test() {" + - " val t = time.now;" + - " ret { now: t, stamp: t.as_stamp_ms() }; " + - "}" - ).Table!; + var t = EvilTestResult( + "fn test() {" + + " val t = time.now;" + + " ret { now: t, stamp: t.as_stamp_ms() }; " + + "}" + ).Table!; - var evilNow = t["now"].Table!; - evilNow["day"].ShouldBe(now.Day); - evilNow["month"].ShouldBe(now.Month); - evilNow["year"].ShouldBe(now.Year); - evilNow["hour"].ShouldBe(now.Hour); - evilNow["minute"].ShouldBe(now.Minute); - ((double)evilNow["second"]).ShouldBeInRange(now.Second, now.Second + 2); - ((double)evilNow["millisecond"]).ShouldBeInRange(0, 999); - ((double)evilNow["microsecond"]).ShouldBeInRange(0, 999); - ((double)evilNow["nanosecond"]).ShouldBeInRange(0, 1000); - ((double)evilNow["ticks"]).ShouldBeInRange(now.Ticks, now.Ticks + 20000000); - evilNow["day_of_year"].ShouldBe(now.DayOfYear); - evilNow["day_of_week"].ShouldBe((int)now.DayOfWeek); - evilNow["day_of_week_name"].ShouldBe(now.DayOfWeek.ToString()); + var evilNow = t["now"].Table!; + evilNow["day"].ShouldBe(now.Day); + evilNow["month"].ShouldBe(now.Month); + evilNow["year"].ShouldBe(now.Year); + evilNow["hour"].ShouldBe(now.Hour); + evilNow["minute"].ShouldBe(now.Minute); + ((double)evilNow["second"]).ShouldBeInRange(now.Second, now.Second + 2); + ((double)evilNow["millisecond"]).ShouldBeInRange(0, 999); + ((double)evilNow["microsecond"]).ShouldBeInRange(0, 999); + ((double)evilNow["nanosecond"]).ShouldBeInRange(0, 1000); + ((double)evilNow["ticks"]).ShouldBeInRange(now.Ticks, now.Ticks + 20000000); + evilNow["day_of_year"].ShouldBe(now.DayOfYear); + evilNow["day_of_week"].ShouldBe((int)now.DayOfWeek); + evilNow["day_of_week_name"].ShouldBe(now.DayOfWeek.ToString()); - var evilStamp = t["stamp"].Number!; - evilStamp.ShouldBeInRange(stamp, stamp + 100); - } + var evilStamp = t["stamp"].Number!; + evilStamp.ShouldBeInRange(stamp, stamp + 100); + } - [Test] - public void StampMs() - { - var ms = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - var evilMs = EvilTestResult( - "fn test() -> time.stamp.ms;" - ).Number; + [Test] + public void StampMs() + { + var ms = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + var evilMs = EvilTestResult( + "fn test() -> time.stamp.ms;" + ).Number; - evilMs.ShouldBeInRange(ms, ms + 1000); - } + evilMs.ShouldBeInRange(ms, ms + 1000); + } - [Test] - public void StampSecs() - { - var secs = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); - var evilSecs = EvilTestResult( - "fn test() -> time.stamp.secs;" - ).Number; + [Test] + public void StampSecs() + { + var secs = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + var evilSecs = EvilTestResult( + "fn test() -> time.stamp.secs;" + ).Number; - evilSecs.ShouldBeInRange(secs, secs + 2); - } + evilSecs.ShouldBeInRange(secs, secs + 2); } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/Serialization.cs b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/Serialization.cs index eb63c524..6a66427b 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/Serialization.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.RuntimeTests/Serialization.cs @@ -1,59 +1,58 @@ -using System.IO; +namespace EVIL.Ceres.RuntimeTests; + +using System.IO; using EVIL.Ceres.ExecutionEngine.Diagnostics; using EVIL.Ceres.TranslationEngine; using EVIL.Grammar.Parsing; using NUnit.Framework; -namespace EVIL.Ceres.RuntimeTests +public class Serialization { - public class Serialization + private Parser _parser = new(); + private Compiler _compiler = new(); + + [SetUp] + public void Setup() { - private Parser _parser = new(); - private Compiler _compiler = new(); + } - [SetUp] - public void Setup() - { - } + [TearDown] + public void Teardown() + { + } - [TearDown] - public void Teardown() - { - } + [Test] + public void ChunkSerializeDeserialize() + { + var source = "#[jp2;gmd(2137)] fn main(a, b = 123, c = \"brokuł\") { " + + " rw val f = 33.3, " + + " s = \"teststring\";" + + "" + + " for (rw val i = 0; i < 10; i++)" + + " f += 2;" + + "" + + " val f1 = fn(a, b) -> a + b * f;" + + "" + + " if (false) -> 10; " + + " elif (false_too_just_nil) -> 20;" + + " elif (0) -> 30;" + + " else -> \"haha you will never get a 4\";" + + "" + + " ret 2+2;" + + "}"; + + var program = _parser.Parse(source); + var rootChunk = _compiler.Compile(program); + var originalChunk = rootChunk; - [Test] - public void ChunkSerializeDeserialize() + using (var ms = new MemoryStream()) { - var source = "#[jp2;gmd(2137)] fn main(a, b = 123, c = \"brokuł\") { " + - " rw val f = 33.3, " + - " s = \"teststring\";" + - "" + - " for (rw val i = 0; i < 10; i++)" + - " f += 2;" + - "" + - " val f1 = fn(a, b) -> a + b * f;" + - "" + - " if (false) -> 10; " + - " elif (false_too_just_nil) -> 20;" + - " elif (0) -> 30;" + - " else -> \"haha you will never get a 4\";" + - "" + - " ret 2+2;" + - "}"; - - var program = _parser.Parse(source); - var rootChunk = _compiler.Compile(program); - var originalChunk = rootChunk; - - using (var ms = new MemoryStream()) - { - originalChunk.Serialize(ms); - ms.Seek(0, SeekOrigin.Begin); - var chunk = Chunk.Deserialize(ms, out var version, out _); - - Assert.That(version, Is.EqualTo(Chunk.FormatVersion)); - Assert.That(chunk, Is.EqualTo(originalChunk)); - } + originalChunk.Serialize(ms); + ms.Seek(0, SeekOrigin.Begin); + var chunk = Chunk.Deserialize(ms, out var version, out _); + + Assert.That(version, Is.EqualTo(Chunk.FormatVersion)); + Assert.That(chunk, Is.EqualTo(originalChunk)); } } } \ No newline at end of file diff --git a/VirtualMachine/Tests/EVIL.Ceres.SerializationTests/DynamicValueSerializerTests.cs b/VirtualMachine/Tests/EVIL.Ceres.SerializationTests/DynamicValueSerializerTests.cs index 95762b18..df9940f0 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.SerializationTests/DynamicValueSerializerTests.cs +++ b/VirtualMachine/Tests/EVIL.Ceres.SerializationTests/DynamicValueSerializerTests.cs @@ -1,3 +1,7 @@ +namespace EVIL.Ceres.SerializationTests; + +using Array = EVIL.Ceres.ExecutionEngine.Collections.Array; + using System; using System.IO; using EVIL.Ceres.ExecutionEngine; @@ -9,223 +13,219 @@ using EVIL.CommonTypes.TypeSystem; using NUnit.Framework; using Shouldly; -using Array = EVIL.Ceres.ExecutionEngine.Collections.Array; -namespace EVIL.Ceres.SerializationTests +public class DynamicValueSerializerTests { - public class DynamicValueSerializerTests + [Test] + public void NilSerializeDeserialize() { - [Test] - public void NilSerializeDeserialize() - { - var nilValue = DynamicValue.Nil; + var nilValue = DynamicValue.Nil; - using (var ms = new MemoryStream()) - { - nilValue.Serialize(ms); - ms.Seek(0, SeekOrigin.Begin); + using (var ms = new MemoryStream()) + { + nilValue.Serialize(ms); + ms.Seek(0, SeekOrigin.Begin); - DynamicValue.Deserialize(ms) - .ShouldBeEquivalentTo(nilValue); - } + DynamicValue.Deserialize(ms) + .ShouldBeEquivalentTo(nilValue); } + } - [Test] - public void NumberSerializeDeserialize() - { - var numberValue = new DynamicValue(2137); + [Test] + public void NumberSerializeDeserialize() + { + var numberValue = new DynamicValue(2137); - using (var ms = new MemoryStream()) - { - numberValue.Serialize(ms); - ms.Seek(0, SeekOrigin.Begin); + using (var ms = new MemoryStream()) + { + numberValue.Serialize(ms); + ms.Seek(0, SeekOrigin.Begin); - DynamicValue.Deserialize(ms) - .ShouldBeEquivalentTo(numberValue); - } + DynamicValue.Deserialize(ms) + .ShouldBeEquivalentTo(numberValue); } + } - [Test] - public void StringSerializeDeserialize() - { - var stringValue = new DynamicValue("this is a test string 12342137"); + [Test] + public void StringSerializeDeserialize() + { + var stringValue = new DynamicValue("this is a test string 12342137"); - using (var ms = new MemoryStream()) - { - stringValue.Serialize(ms); - ms.Seek(0, SeekOrigin.Begin); + using (var ms = new MemoryStream()) + { + stringValue.Serialize(ms); + ms.Seek(0, SeekOrigin.Begin); - DynamicValue.Deserialize(ms) - .ShouldBeEquivalentTo(stringValue); - } + DynamicValue.Deserialize(ms) + .ShouldBeEquivalentTo(stringValue); } + } - [Test] - public void BooleanSerializeDeserialize() - { - var booleanValue = new DynamicValue(true); + [Test] + public void BooleanSerializeDeserialize() + { + var booleanValue = new DynamicValue(true); - using (var ms = new MemoryStream()) - { - booleanValue.Serialize(ms); - ms.Seek(0, SeekOrigin.Begin); + using (var ms = new MemoryStream()) + { + booleanValue.Serialize(ms); + ms.Seek(0, SeekOrigin.Begin); - DynamicValue.Deserialize(ms) - .ShouldBeEquivalentTo(booleanValue); - } + DynamicValue.Deserialize(ms) + .ShouldBeEquivalentTo(booleanValue); } + } - [Test] - public void TableSerializeDeserialize() + [Test] + public void TableSerializeDeserialize() + { + var tableValue = new DynamicValue(new Table() { - var tableValue = new DynamicValue(new Table() + ["key"] = "a string value", + [2137] = "2137 + meow = uwu", + [true] = false, + ["a table"] = new Table() { - ["key"] = "a string value", - [2137] = "2137 + meow = uwu", - [true] = false, - ["a table"] = new Table() - { - ["inside a table"] = "inside a table", - [2.137] = "666" - } - }); + ["inside a table"] = "inside a table", + [2.137] = "666" + } + }); - using (var ms = new MemoryStream()) - { - tableValue.Serialize(ms); - ms.Seek(0, SeekOrigin.Begin); + using (var ms = new MemoryStream()) + { + tableValue.Serialize(ms); + ms.Seek(0, SeekOrigin.Begin); - DynamicValue.Deserialize(ms) - .IsDeeplyEqualTo(tableValue) - .ShouldBe(true); - } + DynamicValue.Deserialize(ms) + .IsDeeplyEqualTo(tableValue) + .ShouldBe(true); } + } - [Test] - public void ArraySerializeDeserialize() - { - var arr = new Array(5); + [Test] + public void ArraySerializeDeserialize() + { + var arr = new Array(5); - arr[0] = 1; - arr[1] = new Table() { ["aaaa"] = 333, ["bbbb"] = "ąśćę" }; - arr[2] = "ąćżęłóń"; - arr[3] = -1234; - arr[4] = true; + arr[0] = 1; + arr[1] = new Table() { ["aaaa"] = 333, ["bbbb"] = "ąśćę" }; + arr[2] = "ąćżęłóń"; + arr[3] = -1234; + arr[4] = true; - var arrayValue = new DynamicValue(arr); + var arrayValue = new DynamicValue(arr); - using (var ms = new MemoryStream()) - { - arrayValue.Serialize(ms); - ms.Seek(0, SeekOrigin.Begin); + using (var ms = new MemoryStream()) + { + arrayValue.Serialize(ms); + ms.Seek(0, SeekOrigin.Begin); - DynamicValue.Deserialize(ms) - .IsDeeplyEqualTo(arrayValue) - .ShouldBe(true); - } + DynamicValue.Deserialize(ms) + .IsDeeplyEqualTo(arrayValue) + .ShouldBe(true); } + } - [Test] - public void ChunkSerializeDeserialize() + [Test] + public void ChunkSerializeDeserialize() + { + var compiler = new Compiler(); + var chunk = compiler.Compile("ret 1234;", "unit.test/TestFileName.vil"); + var chunkValue = new DynamicValue(chunk); + + using (var ms = new MemoryStream()) { - var compiler = new Compiler(); - var chunk = compiler.Compile("ret 1234;", "unit.test/TestFileName.vil"); - var chunkValue = new DynamicValue(chunk); + chunkValue.Serialize(ms); + ms.Seek(0, SeekOrigin.Begin); - using (var ms = new MemoryStream()) + var deserialized = DynamicValue.Deserialize(ms); + + using (var vm = new CeresVM()) { - chunkValue.Serialize(ms); - ms.Seek(0, SeekOrigin.Begin); - - var deserialized = DynamicValue.Deserialize(ms); - - using (var vm = new CeresVM()) - { - vm.Start(); - vm.MainFiber.Schedule(deserialized.Chunk!); - vm.MainFiber.BlockUntilFinished(); - var ret = vm.MainFiber.PopValue(); - vm.Stop(); - ret.ShouldBe(1234); - } + vm.Start(); + vm.MainFiber.Schedule(deserialized.Chunk!); + vm.MainFiber.BlockUntilFinished(); + var ret = vm.MainFiber.PopValue(); + vm.Stop(); + ret.ShouldBe(1234); } } + } - [Test] - public void TypeCodeSerializeDeserialize() - { - var typeCodeValue = new DynamicValue(DynamicValueType.Table); + [Test] + public void TypeCodeSerializeDeserialize() + { + var typeCodeValue = new DynamicValue(DynamicValueType.Table); - using (var ms = new MemoryStream()) - { - typeCodeValue.Serialize(ms); - ms.Seek(0, SeekOrigin.Begin); + using (var ms = new MemoryStream()) + { + typeCodeValue.Serialize(ms); + ms.Seek(0, SeekOrigin.Begin); - DynamicValue.Deserialize(ms) - .ShouldBeEquivalentTo(typeCodeValue); - } + DynamicValue.Deserialize(ms) + .ShouldBeEquivalentTo(typeCodeValue); } + } - [Test] - public void NativeFunctionSerializeDeserialize() - { - var nativeFunctionValue = new DynamicValue(TestNativeFunction); + [Test] + public void NativeFunctionSerializeDeserialize() + { + var nativeFunctionValue = new DynamicValue(TestNativeFunction); - using (var ms = new MemoryStream()) - { - nativeFunctionValue.Serialize(ms); - ms.Seek(0, SeekOrigin.Begin); + using (var ms = new MemoryStream()) + { + nativeFunctionValue.Serialize(ms); + ms.Seek(0, SeekOrigin.Begin); - var deserialized = DynamicValue.Deserialize(ms); - deserialized.ShouldBeEquivalentTo(new DynamicValue(TestNativeFunction)); + var deserialized = DynamicValue.Deserialize(ms); + deserialized.ShouldBeEquivalentTo(new DynamicValue(TestNativeFunction)); - using (var vm = new CeresVM()) - { - var compiler = new Compiler(); - var chunk = compiler.Compile("ret testfunc();", "unit.test/TestFileName.vil"); + using (var vm = new CeresVM()) + { + var compiler = new Compiler(); + var chunk = compiler.Compile("ret testfunc();", "unit.test/TestFileName.vil"); - vm.Start(); - vm.Global["testfunc"] = deserialized; - vm.MainFiber.Schedule(chunk); - vm.MainFiber.BlockUntilFinished(); - var ret = vm.MainFiber.PopValue(); - ret.ShouldBe(2137); - } + vm.Start(); + vm.Global["testfunc"] = deserialized; + vm.MainFiber.Schedule(chunk); + vm.MainFiber.BlockUntilFinished(); + var ret = vm.MainFiber.PopValue(); + ret.ShouldBe(2137); } } + } - [Test] - public void NativeFunctionSerializeShouldThrowOnInstanceMethod() - { - var nativeFunctionValue = new DynamicValue((_, _) => 2137); + [Test] + public void NativeFunctionSerializeShouldThrowOnInstanceMethod() + { + var nativeFunctionValue = new DynamicValue((_, _) => 2137); - Should.Throw(() => - { - using (var ms = new MemoryStream()) - { - nativeFunctionValue.Serialize(ms); - } - }); - } - - [Test] - public void NativeObjectSerializeDeserialize() + Should.Throw(() => { - var nativeObjectValue = new DynamicValue(new FormatException()); - using (var ms = new MemoryStream()) { - nativeObjectValue.Serialize(ms); - ms.Seek(0, SeekOrigin.Begin); - - DynamicValue.Deserialize(ms) - .ShouldBeEquivalentTo(nativeObjectValue); + nativeFunctionValue.Serialize(ms); } - } + }); + } - public static DynamicValue TestNativeFunction(Fiber fiber, params DynamicValue[] args) + [Test] + public void NativeObjectSerializeDeserialize() + { + var nativeObjectValue = new DynamicValue(new FormatException()); + + using (var ms = new MemoryStream()) { - return 2137; + nativeObjectValue.Serialize(ms); + ms.Seek(0, SeekOrigin.Begin); + + DynamicValue.Deserialize(ms) + .ShouldBeEquivalentTo(nativeObjectValue); } } + + public static DynamicValue TestNativeFunction(Fiber fiber, params DynamicValue[] args) + { + return 2137; + } } \ No newline at end of file