From 9b2d7d056a70b070857ce25a13f30f8acf1d4d1b Mon Sep 17 00:00:00 2001 From: vddCore Date: Fri, 24 May 2024 18:50:22 +0200 Subject: [PATCH] Small tweaks, bugfixes and missing features. --- .gitignore | 8 +-- Core/EVIL.Lexical/EVIL.Lexical.csproj | 2 +- Core/EVIL.Lexical/Lexer.cs | 69 +++++++++++++++++-- VirtualMachine/EVIL.Ceres/EVIL.Ceres.csproj | 2 +- .../Diagnostics/Chunk.Deserializer.cs | 5 ++ .../ExecutionEngine/Diagnostics/Chunk.cs | 7 ++ .../ExecutionEngine/Diagnostics/ChunkFlags.cs | 3 +- .../Diagnostics/Disassembler.cs | 6 ++ .../ExecutionEngine/Diagnostics/Error.cs | 24 +++++-- .../Compiler.Statement.Throw.cs | 2 + .../EVIL.Ceres/TranslationEngine/Compiler.cs | 4 +- .../tests/025_fn_indexed.vil | 15 +++- 12 files changed, 126 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index 920d1cde..50bf323a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,5 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore +# Obsidian metadata +.obsidian/ # User-specific files *.rsuser @@ -33,8 +31,6 @@ bld/ # Visual Studio 2015/2017 cache/options directory .vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ # Visual Studio 2017 auto generated files Generated\ Files/ diff --git a/Core/EVIL.Lexical/EVIL.Lexical.csproj b/Core/EVIL.Lexical/EVIL.Lexical.csproj index 3bc29708..dce24167 100644 --- a/Core/EVIL.Lexical/EVIL.Lexical.csproj +++ b/Core/EVIL.Lexical/EVIL.Lexical.csproj @@ -3,7 +3,7 @@ net7.0 enable - 4.0.0 + 4.1.0 false diff --git a/Core/EVIL.Lexical/Lexer.cs b/Core/EVIL.Lexical/Lexer.cs index 9cf5f546..57685047 100644 --- a/Core/EVIL.Lexical/Lexer.cs +++ b/Core/EVIL.Lexical/Lexer.cs @@ -361,10 +361,71 @@ private Token GetDecimalNumber() { var number = string.Empty; - while (char.IsDigit(State.Character) || State.Character == '.') + if (char.IsDigit(State.Character) || State.Character == '.') { - number += State.Character; - Advance(); + 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 == '+') + { + if (State.Character == '.') + { + if (foundDecimalSeparator) + { + 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 (foundExponent) + { + throw new LexerException( + $"Character `{State.Character}' was unexpected at this time.", + State.Line, + State.Column + ); + } + + foundExponent = true; + } + + if (State.Character == '+' || State.Character == '-') + { + if (!foundExponent || foundExponentSign) + { + throw new LexerException( + $"Character `{State.Character}' was unexpected at this time.", + State.Line, + State.Column + ); + } + + foundExponent = true; + } + + number += State.Character; + Advance(); + } + } + else + { + throw new LexerException( + $"Character `{State.Character}' was unexpected at this time.", + State.Line, + State.Column + ); } try @@ -373,7 +434,7 @@ private Token GetDecimalNumber() } catch (FormatException) { - throw new LexerException("Invalid number format.", State.Line, State.Column); + throw new LexerException($"Malformed numeric constant `{number}'.", State.Line, State.Column); } } diff --git a/VirtualMachine/EVIL.Ceres/EVIL.Ceres.csproj b/VirtualMachine/EVIL.Ceres/EVIL.Ceres.csproj index 07fbeddb..99c86750 100644 --- a/VirtualMachine/EVIL.Ceres/EVIL.Ceres.csproj +++ b/VirtualMachine/EVIL.Ceres/EVIL.Ceres.csproj @@ -8,7 +8,7 @@ true true - 7.4.1 + 7.5.0 false diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Chunk.Deserializer.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Chunk.Deserializer.cs index 43ce7887..0a8f29bb 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Chunk.Deserializer.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Chunk.Deserializer.cs @@ -111,6 +111,11 @@ public static Chunk Deserialize(Stream stream, out byte version, out long timest chunk.MarkSelfAware(); } + if (flags.HasFlag(ChunkFlags.MayThrow)) + { + chunk.MarkThrowing(); + } + chunk.IsSpecialName = flags.HasFlag(ChunkFlags.IsSpecialName); if (flags.HasFlag(ChunkFlags.HasParameters)) diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Chunk.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Chunk.cs index b83474cf..fa09a479 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Chunk.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Chunk.cs @@ -38,6 +38,7 @@ public sealed partial class Chunk : IDisposable, IEquatable 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; @@ -112,6 +113,9 @@ public ChunkFlags Flags if (ProtectedBlocks.Count > 0) ret |= ChunkFlags.HasProtectedBlocks; + + if (MayThrow) + ret |= ChunkFlags.MayThrow; return ret; } @@ -183,6 +187,9 @@ public BinaryReader SpawnCodeReader() ); } + public void MarkThrowing() + => MayThrow = true; + public void MarkSelfAware() => IsSelfAware = true; diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ChunkFlags.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ChunkFlags.cs index e1de7b8d..d5ee6919 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ChunkFlags.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/ChunkFlags.cs @@ -17,6 +17,7 @@ public enum ChunkFlags IsSubChunk = 1 << 8, IsSelfAware = 1 << 9, IsSpecialName = 1 << 10, - HasProtectedBlocks = 1 << 11 + HasProtectedBlocks = 1 << 11, + MayThrow = 1 << 12 } } \ 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 80967206..dbc2483c 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Disassembler.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Disassembler.cs @@ -43,6 +43,12 @@ public static void Disassemble(Chunk chunk, TextWriter output, DisassemblyOption } output.WriteLine("{"); + + if (chunk.MayThrow) + { + output.WriteLine($"{indent} .MAY_THROW"); + output.WriteLine(); + } output.WriteLine($"{indent} .LOCALS {chunk.LocalCount}"); output.WriteLine($"{indent} .CLOSRS {chunk.ClosureCount}"); diff --git a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Error.cs b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Error.cs index a7d17e8c..5e1a60c8 100644 --- a/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Error.cs +++ b/VirtualMachine/EVIL.Ceres/ExecutionEngine/Diagnostics/Error.cs @@ -1,14 +1,30 @@ using EVIL.Ceres.ExecutionEngine.Collections; using EVIL.Ceres.ExecutionEngine.TypeSystem; +using EVIL.CommonTypes.TypeSystem; namespace EVIL.Ceres.ExecutionEngine.Diagnostics { - public class Error + public sealed class Error { private Table UserData { get; } = new(); public int Length => UserData.Length; - + + public string? Message + { + get + { + if (UserData["msg"].Type == DynamicValueType.String) + { + return UserData["msg"].String!; + } + + return null; + } + + set => UserData["msg"] = value ?? DynamicValue.Nil; + } + public DynamicValue this[DynamicValue key] { get => UserData[key]; @@ -26,13 +42,13 @@ public Error(Table userData) public Error(string message) { - UserData["msg"] = message; + Message = message; } public Error(Table userData, string message) { UserData = userData; - UserData["msg"] = message; + Message = message; } public bool Contains(DynamicValue key) diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Throw.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Throw.cs index f686d0ff..c6ceb2cd 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Throw.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.Statement.Throw.cs @@ -7,6 +7,8 @@ public partial class Compiler { public override void Visit(ThrowStatement throwStatement) { + Chunk.MarkThrowing(); + Visit(throwStatement.ThrownExpression); Chunk.CodeGenerator.Emit(OpCode.THROW); } diff --git a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.cs b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.cs index 503e6d3f..bf4b8831 100644 --- a/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.cs +++ b/VirtualMachine/EVIL.Ceres/TranslationEngine/Compiler.cs @@ -84,8 +84,8 @@ public Chunk Compile(string source, string fileName = "") le.Message, CurrentFileName, EvilMessageCode.LexerError, - line: Line, - column: Column, + line: le.Line, + column: le.Column, innerException: le ); } diff --git a/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/tests/025_fn_indexed.vil b/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/tests/025_fn_indexed.vil index 28a51f16..ef8ae482 100644 --- a/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/tests/025_fn_indexed.vil +++ b/VirtualMachine/Tests/EVIL.Ceres.LanguageTests/tests/025_fn_indexed.vil @@ -1,5 +1,5 @@ #[test] -fn fn_indexed_simple() { +fn fn_indexed_simple { val t = { }; loc fn t.function(a, b) -> a + b; @@ -9,11 +9,22 @@ fn fn_indexed_simple() { } #[test] -fn fn_indexed_nested() { +fn fn_indexed_nested { val t = { q: { } }; loc fn t.q.function(a, b) -> a - b; assert.is_of_type(t.q.function, Function); assert.equal(t.q.function(5, 3), 2); +} + +#[test] +fn fn_indexed_byref { + val f = fn(table) { loc fn table.func(a, b) -> a * b; }; + + val t = { }; + f(t); + + assert.is_of_type(t.func, Function); + assert.equal(t.func(10, 2), 20); } \ No newline at end of file